Search Unity

Using Light Probes to fully light a mesh.

Discussion in 'Global Illumination' started by quinng, Apr 27, 2020.

  1. quinng

    quinng

    Joined:
    Jul 2, 2015
    Posts:
    22
    Hi, I wrote a shader that only takes lighting information from light probes. However I noticed that it did not seem to be capturing the directional light in the scene, and was perhaps only capturing indirect lighting form the point lights. I looked through the different mixed lighting modes, and each of their descriptions seemed to suggest that only part of the scene lighting would be captured by the light probes. Is there a simple setting to ensure that all lighting data is captured, and I can use only light probe data to light my dynamic objects?

    This is my bare-bones shader:
    Code (CSharp):
    1.  
    2. Shader "Custom/FarsideRealtimeShader"
    3. {
    4.     Properties
    5.     {
    6.         _ContextNum("Context Number", Int) = 0
    7.     }
    8.         SubShader
    9.     {
    10.         Tags { "RenderType" = "Opaque" "Queue" = "Geometry+2" "LightMode" = "ForwardBase"}
    11.         LOD 100
    12.         Stencil {
    13.             Ref[_ContextNum]
    14.             Comp equal
    15.         }
    16.         Pass
    17.         {
    18.             Cull Off //Cull is off because some of my meshes might have negative scales.
    19.             CGPROGRAM
    20.             #pragma target 3.0
    21.             #pragma vertex vert
    22.             #pragma fragment frag
    23.             #pragma multi_compile_fog
    24.             #include "UnityCG.cginc"
    25.             #include "UnityStandardUtils.cginc" //For access to ShadeSHPerPixel if I need to use it.
    26.             struct appdata
    27.             {
    28.                 float4 vertex : POSITION;
    29.                 float2 uv : TEXCOORD0;
    30.                 float3 normal : NORMAL;
    31.             };
    32.             struct v2f
    33.             {
    34.                 float2 uv : TEXCOORD0;
    35.                 UNITY_FOG_COORDS(1)
    36.                 float4 vertex : SV_POSITION;
    37.                 float3 worldPos : TEXCOORD2;
    38.                 float3 worldNormal : TEXCOORD3;
    39.             };
    40.             sampler2D _MainTex;
    41.             float4 _MainTex_ST;
    42.             v2f vert(appdata v)
    43.             {
    44.                 v2f o;
    45.                 o.vertex = UnityObjectToClipPos(v.vertex);
    46.                 o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    47.                 UNITY_TRANSFER_FOG(o,o.vertex);
    48.                 o.worldNormal = UnityObjectToWorldNormal(v.normal);
    49.                 o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    50.                 return o;
    51.             }
    52.             fixed4 frag(v2f i) : SV_Target
    53.             {
    54.                 fixed4 col = tex2D(_MainTex, i.uv);
    55.                 half3 ambient = ShadeSH9(half4(i.worldNormal, 1.0));
    56.                 col.xyz *= ambient;
    57.                 // apply fog
    58.                 UNITY_APPLY_FOG(i.fogCoord, col);
    59.                 return col;
    60.             }
    61.             ENDCG
    62.         }
    63.     }
    64. }
    65.  
    I should also mention that my ultimate plan for this shader is to use it with Graphic.DrawMesh to draw duplicates of objects in the scene that exactly replicate the lighting of the original object. This will involve me passing a TRS matrix into the shader, which I am currently not doing.
     
  2. JenniferNordwall

    JenniferNordwall

    Unity Technologies

    Joined:
    Sep 19, 2016
    Posts:
    160
    Hi
    Light probes only capture indirect light, and no direct light. I don't think we are planning on adding more. People usually just use realtime lights for the direct light.
     
  3. quinng

    quinng

    Joined:
    Jul 2, 2015
    Posts:
    22
    Thank you for the clarification. Is there a way to copy the realtime lighting on a dynamic object and reproduce it on an object drawn with Graphics.DrawMesh? I've used lightmaps to do this for static objects, but my impression is that realtime lightmaps are only generated for static objects.

    This project is the first time that I've written shaders, so perhaps I'm not taking the most direct approach. I can pass a matrix4x4 into the shader that will allow each pixel to calculate the corresponding worldspace transform on the original mesh. Perhaps I can sample lighting information based on that point, and apply it to the pixels at the drawn mesh's position.

    Alternatively, can I customize or edit-post-bake the light probe data to imitate direct light? It doesn't need to be particularly realistic. I just need objects lighting to roughly match the lighting of their surroundings.
     
    Last edited: Apr 28, 2020
  4. JenniferNordwall

    JenniferNordwall

    Unity Technologies

    Joined:
    Sep 19, 2016
    Posts:
    160
    I don't think so. The realtime lightmaps doesn't really exist and are generated in realtime. Maybe do an attempt where you have the game objects UV's and do a lookup in the realtime lightmap. Hopefully the realtime lightmap is generated correctly at runtime, and you can just check what you have there, even though the object is moving. But the object would just get the same light as it would if it was still in the previous location, so not sure how that would look.

    No, the probes code is not possible to edit. This guy might have done something similar:
     
  5. JenniferNordwall

    JenniferNordwall

    Unity Technologies

    Joined:
    Sep 19, 2016
    Posts:
    160
    Is there a reason why you can't use mixed lights?
     
  6. quinng

    quinng

    Joined:
    Jul 2, 2015
    Posts:
    22
    My original plan was to use mixed lighting. I already have a pretty good solution for duplicating the lighting of static objects. I tried to do something similar for my dynamic objects, but I had some trouble generating/accessing the real-time lightmaps. Having looked into it a little more, I can probably figure out how to make it work. However, one peculiarity of my project is that I can't have a directional light in the scene, only local light sources, so I'm not sure how much of a benefit there is to using the real-time lightmaps, as I understand that on at least some settings they mostly only capture the main directional light in the scene?

    In the meantime I looked more into light probes and arrived at a rudimentary solution similar to the video you shared. The SphericalHarmonicsL2 class actually has a method for adding direct lighting data to it at runtime, and actually gives an example of how to apply direct light to all probes. To light one of my duplicate meshes, I get an interpolated light probe at the original mesh's position, and then store it in a MaterialBlockProperties along with a matrix4x4 that accounts for differences in rotation between the two meshes (I haven't checked if there is method for pre-applying the matrix to the SphericalHarmonicsL2, but that seems like it might be more efficient). I then make a Graphics.DrawMesh call with LightProbeUsage set to Custom.

    This produces the desired result: The drawn mesh's lighting replicates the original. Its lighting changes only when the original's position and rotation within the light probe field changes, not its own. The lighting looks pretty ugly at the moment because of how rudimentary my shader is, but that is okay for the time being. I just wanted to make sure that I could light meshes drawn via script this way. I'll make performance and quality improvements later.
     
    JenniferNordwall likes this.
  7. JenniferNordwall

    JenniferNordwall

    Unity Technologies

    Joined:
    Sep 19, 2016
    Posts:
    160
    Sweet, happy you solved it :)