Search Unity

Question Camera not rending to cubemap

Discussion in 'General Graphics' started by neoshaman, Apr 11, 2022.

  1. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    Hello!

    I have been working on a custom GI solution that rely on a custom Lightprobe atlas structure. I was basically refactoring old ugly code to separate things in their own class, but for some reason, part of the code do not work anymore encapsulated into a class. I have rounded out things to this section of the code

    Code (CSharp):
    1. private void setCameraData(){
    2.  
    3.         //set camera
    4.         pivot = new GameObject("CaptureScene");
    5.         pivot.AddComponent<Camera>();
    6.  
    7.         //Set camera parameters
    8.         lens = pivot.GetComponent<Camera>();
    9.         lens.backgroundColor = Color.blue;
    10.         lens.clearFlags = CameraClearFlags.SolidColor;
    11.         lens.allowMSAA = false;
    12.         lens.cullingMask = 1 << 8;//what mask?
    13.         //should probably have an alternative for regular scene rendering
    14.         lens.SetReplacementShader(capture, "RenderType");
    15.    
    16.         //set rendertexture
    17.         sceneCapture = new RenderTexture(cubemapSize, cubemapSize, 24);
    18.         sceneCapture.dimension = UnityEngine.Rendering.TextureDimension.Cube;
    19.         sceneCapture.antiAliasing = 1;
    20.         sceneCapture.filterMode = FilterMode.Point;
    21.         sceneCapture.graphicsFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.R8G8B8A8_UNorm;
    22.         sceneCapture.depth = 16;
    23.         sceneCapture.Create();
    24.    
    25.     }
    26.  
    27.  
    28.     public  void updateCell(int x, int y){
    29.         //this fonction capture a cubemap of the scene from the point of view of a given cell
    30.      
    31.         //place camera
    32.         int midcell = cellsize / 2;
    33.         //-------------------- hashed position
    34.         pivot.transform.position = new Vector3((x * cellsize) + midcell, 0, (y * cellsize) + midcell);
    35.         pivot.transform.rotation = Quaternion.identity;
    36.  
    37.         lens.RenderToCubemap(sceneCapture);
    38.  
    39.         updateTile(x, y);
    40.     }
    41.  
    42.  
    43.  
    There is two shader used to create the atlas:
    1 - the first capture the scene into a cubemap
    2 - the second transfer the cubemap to an atlas tile

    Setting the second shader to red, display red correctly.
    Setting the first to red, display a gray texture.
    ALSO if I comment destroy camera elsewhere, the camera replace the main camera and show a blue background on screen (as should the gray texture be at least).
    The shader itself is not at fault, since it would have shown something when put to red, and it has already been tested in the old code and was not modified.

    My hypothesis is that either the camera or the rendertexture are not correctly set up, but verification and reading the code don't return any relevant information, I have no error in the console at all. The camera is a prime suspect as it should not render to screen, as it behave correctly in the old code. I have seen no meaningful different with the old code. The camera therefore potentially may not render to the right target, for some reason.



    I don't know if I missed something very obvious, but this has me stumped for month.

    Full class:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class lightprobeData //: MonoBehaviour
    6. {
    7.     //lightprobeData class manage a custom cubemap format,
    8.     //it initialize the atlas by capturing the scene, at set points, using a cubemap camera
    9.  
    10.     int cellsize = 4; //hash dimension
    11.     int cubemapSize = 64; //size of the cubemap capturing the scene
    12.     int atlasSize = 16; //atlas Size, on the side, hold 16x16 tiles
    13.     int probeNumber = 256; //-> atlasSize² //max number of probes, addressing limit with 8bit for freeform
    14.     int tileSize = 128; //-> 2048/16  //size of tile in the atlas
    15.     int atlasTextureSize = 2048; //atlas size x tilesize //16*128=2048
    16.  
    17.  
    18.     public Shader capture;//get a view of the scene using this shader   //should be passed externally?
    19.  
    20.     public Shader transfer;//shader that unwrap cubemap to tile
    21.     Material atlasTransfer;//use to apply unwrap shader to atlas
    22.     public RenderTexture atlas;//{ get => atlas; protected set => atlas = value; } //should have layer for extra data like depth or LPGB
    23.  
    24.     //TODO:external?
    25.     Camera lens; //cubemap capture
    26.     GameObject pivot;//camera position
    27.     RenderTexture sceneCapture;//temp cubemap for transfer to atlas
    28.  
    29.     public void initAtlas(){
    30.         setCameraData();
    31.         SetAtlas();
    32.         updateAll();
    33.         destroyCamera();
    34.     }
    35.  
    36.  
    37.     private void setCameraData(){
    38.  
    39.         //set camera
    40.         pivot = new GameObject("CaptureScene");
    41.         pivot.AddComponent<Camera>();
    42.  
    43.         //Set camera parameters
    44.         lens = pivot.GetComponent<Camera>();
    45.         lens.backgroundColor = Color.blue;
    46.         lens.clearFlags = CameraClearFlags.SolidColor;
    47.         lens.allowMSAA = false;
    48.         lens.cullingMask = 1 << 8;//what mask?
    49.         //should probably have an alternative for regular scene rendering
    50.         lens.SetReplacementShader(capture, "RenderType");
    51.      
    52.         //set rendertexture
    53.         sceneCapture = new RenderTexture(cubemapSize, cubemapSize, 24);
    54.         sceneCapture.dimension = UnityEngine.Rendering.TextureDimension.Cube;
    55.         sceneCapture.antiAliasing = 1;
    56.         sceneCapture.filterMode = FilterMode.Point;
    57.         sceneCapture.graphicsFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.R8G8B8A8_UNorm;
    58.         sceneCapture.depth = 16;
    59.         sceneCapture.Create();
    60.      
    61.     }
    62.     private void SetAtlas(){
    63.  
    64.         //set atlas
    65.         atlas = new RenderTexture(atlasTextureSize, atlasTextureSize, 24);
    66.         atlas.antiAliasing = 1;
    67.         atlas.filterMode = FilterMode.Point;
    68.         atlas.graphicsFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.R8G8B8A8_UNorm;
    69.         atlas.Create();
    70.         //set material
    71.         atlasTransfer = new Material(transfer);
    72.     }
    73.     public  void updateAll(){
    74.         for (int i = 0; i < probeNumber; i++)
    75.         {
    76.             int x = i / atlasSize;
    77.             int y = i % atlasSize;
    78.             updateCell(x, y);//TODO:Add the origin offset!!!!!!!!!
    79.         }
    80.     }
    81.  
    82.     void destroyCamera(){
    83.         sceneCapture.Release();
    84.         //Destroy(pivot);//don't work in pure class
    85.         pivot.SetActive(false);
    86.      
    87.     }
    88.  
    89.  
    90. //-----------------------------------------------------
    91.     public  void updateCell(int x, int y){
    92.         //this fonction capture a cubemap of the scene from the point of view of a given cell
    93.      
    94.         //place camera
    95.         int midcell = cellsize / 2;
    96.         //-------------------- hashed position
    97.         pivot.transform.position = new Vector3((x * cellsize) + midcell, 0, (y * cellsize) + midcell);
    98.         pivot.transform.rotation = Quaternion.identity;
    99.  
    100.         lens.RenderToCubemap(sceneCapture);
    101.  
    102.         updateTile(x, y);
    103.     }
    104.     private void updateTile(int x, int y){
    105.         //create the atlas textures zones
    106.         int halftile = tileSize / 2;
    107.         int xt = (x * tileSize) + halftile;
    108.         int yt = (y * tileSize) + halftile;
    109.         float size = tileSize;
    110.         Vector2 position = new Vector2(xt, yt);
    111.         renderTile(size, position);
    112.     }
    113.     private void renderTile(float size, Vector2 offset){
    114.         //this function use low level immediate render mode to draw on a rendertexture
    115.      
    116.         offset        = new Vector2 (offset.x - (size/2),offset.y - (size/2));
    117.         Vector2 s    = new Vector2 (size + offset.x,size + offset.y);
    118.      
    119.         offset    /=atlas.width;
    120.         s        /=atlas.width;
    121.      
    122.         Graphics.SetRenderTarget(atlas);
    123.         // GL.Flush();
    124.         GL.PushMatrix();
    125.         GL.LoadOrtho();
    126.         atlasTransfer.SetPass(0);
    127.  
    128.         //draw with a quad
    129.         GL.Begin(GL.TRIANGLE_STRIP);
    130.      
    131.         //0,0
    132.         GL.TexCoord(new Vector3(0f,                0f,            0f));
    133.         GL.Vertex3(                offset.x,        offset.y,    1f);
    134.          
    135.         //0,1
    136.         GL.TexCoord(new Vector3(0f,                1f,            0f));
    137.         GL.Vertex3(                offset.x,        s.y,        1f);
    138.          
    139.         //1,0
    140.         GL.TexCoord(new Vector3(1f,                0f,            0f));
    141.         GL.Vertex3(                s.x,            offset.y,    1f);
    142.          
    143.         //1,1
    144.         GL.TexCoord(new Vector3(1f,                1f,            0f));
    145.         GL.Vertex3(                s.x,            s.y,        1f);
    146.          
    147.         GL.End();
    148.         GL.PopMatrix();
    149.         Graphics.SetRenderTarget(null);
    150.     }
    151. }
    I had to replace custom render texture (don't render before updates), and not rely on rendertexture assets, they made everything messier, but was great for prototyping when I didn't knew what I was doing!

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class MagicSetup : MonoBehaviour
    6. {
    7.     #region declaration
    8.     public Shader
    9.         UV,
    10.         Transfer,
    11.         Lighting,
    12.         UpdateGI;
    13.      
    14.     public Material
    15.         atlasTransfer,
    16.         boxProject,
    17.         DirectLightMat;
    18.  
    19.     int Cellsize = 4;
    20.     int AtlasTileSize = 128;    //size(2048)/16
    21.     int ProbeNumber = 256;        //16x16
    22.     GameObject[] ProbeArray;
    23.     GameObject Capture;
    24.     Camera UVCapture;
    25.     List<CustomRenderTextureUpdateZone> zones;
    26.     CustomRenderTextureUpdateZone[] updating;
    27.  
    28.     //setting are on teh texture object?
    29.     public CustomRenderTexture
    30.         IndirectionProbeAtlas,
    31.         DirectLight,
    32.         LightAccumulation;
    33.     public RenderTexture SceneCapture, atlastest;
    34.     public RenderTexture[] LMGB;
    35.     public Material[] LMGBmat;
    36.     public GameObject[] GIscene;
    37.  
    38.     // enum LMGBtexture{
    39.     //     albedo = 0,
    40.     //     worldNormal = 1,
    41.     //     worldPosition = 2,
    42.     //     shadowMasking = 3
    43.     // }
    44.     #endregion
    45.  
    46.     //--------------functions-----------------
    47.     void placeProbe(){
    48.      
    49.         //set slots parameters
    50.         ProbeArray = new GameObject[ProbeNumber];
    51.         int midcell = Cellsize/2;
    52.         //texture zones data
    53.         IndirectionProbeAtlas.ClearUpdateZones();
    54.         CustomRenderTextureUpdateZone[] ProbeTexture = new CustomRenderTextureUpdateZone[ProbeNumber];
    55.      
    56.         for(int i=0;i<ProbeNumber; i++ ){
    57.             int x = i/16;
    58.             int y = i%16;
    59.          
    60.             //create slots primitive
    61.             ProbeArray[i] = GameObject.CreatePrimitive(PrimitiveType.Sphere);//new GameObject();
    62.             ProbeArray[i].transform.position = new Vector3((x*Cellsize)+midcell,0,(y*Cellsize)+midcell);
    63.             ProbeArray[i].SetActive(false);
    64.          
    65.             //create atlas textures zones
    66.             int halftile = AtlasTileSize/2;
    67.             int xt = (x * AtlasTileSize) + halftile;
    68.             int yt = (y * AtlasTileSize) + halftile;
    69.             ProbeTexture[i].updateZoneSize        = new Vector3(AtlasTileSize,AtlasTileSize,0);
    70.             ProbeTexture[i].updateZoneCenter    = new Vector3(xt,yt,0);
    71.         }
    72.         //initialize the texture zones
    73.         IndirectionProbeAtlas.SetUpdateZones(ProbeTexture);
    74.     }
    75.  
    76.     void setProbeCapture(){
    77.         placeProbe();
    78.         //set camera
    79.         Capture = new GameObject("CaptureScene");
    80.         Capture.AddComponent<Camera>();
    81.         UVCapture = Capture.GetComponent<Camera>();
    82.         UVCapture.SetReplacementShader(UV, "RenderType");
    83.         //Set camera parameters
    84.         UVCapture.backgroundColor = Color.yellow;
    85.         UVCapture.clearFlags = CameraClearFlags.SolidColor;
    86.         UVCapture.allowMSAA = false;
    87.         UVCapture.cullingMask = 1 << 8;
    88.      
    89.         //UVCapture.targetTexture = SceneCapture;
    90.      
    91.         //atlas data
    92.         zones = new List<CustomRenderTextureUpdateZone>();
    93.         IndirectionProbeAtlas.GetUpdateZones(zones);
    94.         updating = new CustomRenderTextureUpdateZone[1];
    95.         IndirectionProbeAtlas.Initialize();
    96.  
    97.     }
    98.     void renderProbe(){
    99.  
    100.         setProbeCapture();
    101.  
    102.         GameObject probe;
    103.         UVCapture.enabled = true; // move that outside
    104.  
    105.         for (int i = 0; i<ProbeArray.Length;i++){
    106.             //render at position on grid
    107.             probe = ProbeArray[i];
    108.             Capture.transform.position = probe.transform.position;
    109.             Capture.transform.rotation = Quaternion.identity;
    110.             UVCapture.RenderToCubemap(SceneCapture);
    111.             //update zone
    112.             updating[0] = zones[i];
    113.             IndirectionProbeAtlas.SetUpdateZones(updating);
    114.          
    115.             float size = updating[0].updateZoneSize.x;
    116.             Vector2 position = updating[0].updateZoneCenter;
    117.          
    118.             updatingAtlas(size, position);
    119.         }
    120.  
    121.         //move both outside
    122.          initLMGB();
    123.         UVCapture.enabled = false;
    124.     }
    125.  
    126.     void initLMGB(){
    127.         // albedo = 0,
    128.         // worldNormal = 1,
    129.         // worldPosition = 2,
    130.         // shadowMasking = 3
    131.         UVCapture.backgroundColor = Color.black;
    132.  
    133.         for (int i = 0; i < LMGB.Length; i++) {
    134.             UVCapture.targetTexture = LMGB[i];
    135.             UVCapture.RenderWithShader(LMGBmat[i].shader,"");
    136.             //updateRT(LMGB[i],LMGBmat[i]);
    137.         }
    138.     }
    139.  
    140.     void updatingAtlas(float size, Vector2 offset){
    141.         //could probably do teh UV selection in shader
    142.         //at each point
    143.         //hash the offset using the size
    144.         //if offset ! of input uniform, add 0
    145.         //else add transfered color using remap UV
    146.      
    147.         offset        = new Vector2 (offset.x - (size/2),offset.y - (size/2));
    148.         Vector2 s    = new Vector2 (size + offset.x,size + offset.y);
    149.      
    150.         offset    /=IndirectionProbeAtlas.width;
    151.         s        /=IndirectionProbeAtlas.width;
    152.      
    153.         Graphics.SetRenderTarget(atlastest);
    154.         GL.PushMatrix();
    155.         GL.LoadOrtho();
    156.         atlasTransfer.SetPass(0);
    157.  
    158.         GL.Begin(GL.TRIANGLE_STRIP);
    159.      
    160.          //0,0
    161.         GL.TexCoord(new Vector3(0f,                0f,            0f));
    162.         GL.Vertex3(                offset.x,        offset.y,    1f);
    163.      
    164.          //0,1
    165.         GL.TexCoord(new Vector3(0f,                1f,            0f));
    166.         GL.Vertex3(                offset.x,        s.y,        1f);
    167.      
    168.          //1,0
    169.         GL.TexCoord(new Vector3(1f,                0f,            0f));
    170.         GL.Vertex3(                s.x,            offset.y,    1f);
    171.      
    172.          //1,1
    173.         GL.TexCoord(new Vector3(1f,                1f,            0f));
    174.         GL.Vertex3(                s.x,            s.y,        1f);
    175.      
    176.         GL.End();
    177.         GL.PopMatrix();
    178.     }
    179.  
    180.     void updateRT(RenderTexture RT, Material MT){
    181.         Graphics.SetRenderTarget(RT);
    182.         GL.PushMatrix();
    183.         GL.LoadOrtho();
    184.         MT.SetPass(0);
    185.  
    186.         Mesh m = GIscene[0].GetComponent<Mesh>();
    187.         Debug.Log(GIscene[0]);
    188.  
    189.         Graphics.DrawMeshNow(m, Vector3.zero, Quaternion.identity);
    190.  
    191.         GL.PopMatrix();
    192.     }
    193.  
    194.  
    195.     //TickAccumulation
    196.     //count cycle
    197.     //pass ray delta
    198.     //if cycle = complete, swap buffer, reset count
    199.     void accumulationTick(){
    200.      
    201.     }
    202.  
    203.     //--------------Lifecycles-----------------
    204.  
    205.     //hide this chunk    //renderfarfield    //show chunk
    206.     //place probe        //renderprobe async    //lightLMGB
    207.  
    208.     void Start(){
    209.         renderProbe();
    210.     }
    211.  
    212.     //TickAccumulation rate
    213.     //if light change then update direct
    214.     //if scene change then update probes
    215.     void Update(){
    216.         //set light direction for shader
    217.         Light dirlit = FindObjectOfType<Light>();
    218.         Vector3 sunny = -dirlit.transform.forward;
    219.         //boxProject.SetVector("_MainLight",sunny);
    220.         //DirectLightMat.SetVector("_MainLight",sunny);
    221.         Shader.SetGlobalVector("_MainLight",sunny);
    222.  
    223.         //updates shaders
    224.         DirectLight.Update();
    225.         //LightAccumulation.Update();
    226.  
    227.         //adjust scene hashing origin to mesh bound
    228.         Mesh m = GIscene[0].GetComponent<MeshFilter>().mesh;
    229.         Renderer r = GIscene[0].GetComponent<Renderer>();
    230.         Bounds b = r.bounds;
    231.         Shader.SetGlobalVector("_Origin",b.min);
    232.         //boxProject.SetVector("_Origin",b.min);
    233.  
    234.         //Debug.Log(b.min);
    235.      
    236.         //Debug.DrawRay(Vector3.zero,Vector3.one*16,Color.red);
    237.      
    238.         // const int numSamples = 64;
    239.         // const float phi = 1.618033988f;
    240.         // const float gAngle = phi * Mathf.PI * 2.0f;
    241.         // Vector3 worldNormal = Vector3.up;
    242.         // for (int i = 0; i < numSamples; i++)
    243.         // {
    244.         //     float fi = (float)i;
    245.         //     float fiN = fi / numSamples;
    246.         //     float longitude = gAngle * fi;
    247.         //     float latitude = Mathf.Asin(fiN * 2.0f - 1.0f);
    248.                  
    249.         //     Vector3 kernel = new Vector3(
    250.         //         Mathf.Cos(latitude) * Mathf.Cos(longitude),
    251.         //         Mathf.Cos(latitude) * Mathf.Sin(longitude),
    252.         //         Mathf.Sin(latitude)
    253.         //     );
    254.         //     kernel = (kernel + worldNormal).normalized;
    255.          
    256.         //     if (i == 0){
    257.         //         kernel = Vector3.up;
    258.         //     }
    259.         //     Debug.DrawRay(Vector3.zero,kernel*16,Color.red);
    260.         //     //traceResult += ConeTrace(voxelOrigin.xyz, kernel.xyz, worldNormal.xyz);
    261.         // }
    262.     }
    263.     //--------------------------------------
    264.  
    265.  
    266.  
    267.  
    268. }
    269.  
     
  2. neoshaman

    neoshaman

    Joined:
    Feb 11, 2011
    Posts:
    6,493
    upload_2022-4-12_4-12-5.png

    So far the profiler does show it's doing something