Search Unity

Feature Request Extract additianal information about lights in custom shader

Discussion in 'Universal Render Pipeline' started by RichardGoesToNightSchool, Jun 23, 2022.

  1. RichardGoesToNightSchool

    RichardGoesToNightSchool

    Joined:
    Dec 9, 2020
    Posts:
    27
    We are buulding a custom toon shader that models directional lights and point lights diffrently.

    Specifically point lights don't consider surface normal only distance attenuation.

    Our problem is that there appears to be no way to tell if a light is a directional or point light using the provided realtime lightiing functions.

    Is there ANY way I could get this information. Even if I had to encode it into another value I do have access to?

    Are there any plans to provide access to additional values in upcoming updates?

    I'v attached a sample of our hlsl code.

    Thank you

    Code (CSharp):
    1.  
    2.     Light mainLight = GetMainLight(d.shadowCoord, d.positionWS, d.shadowMask);
    3.  
    4.     CustomDirectionalLightHandling(d, mainLight, MainLightDiffuseTerm, MainLightSpecularTerm, MainLightColor);
    5.  
    6.     StrongestPointLightColor = MainLightColor;
    7.    
    8.     #ifdef _ADDITIONAL_LIGHTS
    9.     uint numAdditionalLights = GetAdditionalLightsCount();
    10.     for (uint lightI = 0; lightI < numAdditionalLights; lightI++)
    11.     {
    12.  
    13.         Light light = GetAdditionalLight(lightI, d.positionWS, d.shadowMask);
    14.         CustomPointLightHandling(d, light,  thisDiffuse, thisSpecular,  normalizedColor);
    15.            
    16.         if (thisDiffuse > StrongestPointLightDiffuseTerm)
    17.         {
    18.             StrongestPointLightDiffuseTerm = thisDiffuse;
    19.             StrongestPointLightColor = normalizedColor;
    20.             StrongestPointLightSpecularTerm = thisSpecular;
    21.         }
    22.     }
     
  2. revolute

    revolute

    Joined:
    Jul 28, 2014
    Posts:
    50
    The difference between directional lights and non directional lights is that their positions are encoded with different w values. W is encoded as 0 when directional, 1 when points, spots ( punctual lights is the word Unity uses ).
    However this is only for additional lights, not mainlights.
    You may wish to use _AdditionalLightsPosition[] and GetPerObjectLightIndex(uint i) and check whether the position's W component is non zero.
     
  3. RichardGoesToNightSchool

    RichardGoesToNightSchool

    Joined:
    Dec 9, 2020
    Posts:
    27
    What!? Amazing! How do you know this esoteric knowledge??

    Quick branching question:

    If I wrote the following code am I correct in my understanding that it would evaluate both branches and discard the one that isn't used. Effectively it would evaluate CustomPointLightHandling() and CustomDirectionalLightHandling() for every light?

    Code (CSharp):
    1.  int lightIndex = GetPerObjectLightIndex(lightI);
    2.        
    3.         float4 lightPositionWS = _AdditionalLightsPosition[lightIndex];
    4.  
    5.         Light light = GetAdditionalLight(lightI, d.positionWS, d.shadowMask);
    6.         if(lightPositionWS.w == 1)
    7.             CustomPointLightHandling(d, light,  thisDiffuse, thisSpecular,  normalizedColor);
    8.         else
    9.             CustomDirectionalLightHandling(d, light,  thisDiffuse, thisSpecular,  normalizedColor);
    10.        
     
  4. funkyCoty

    funkyCoty

    Joined:
    May 22, 2018
    Posts:
    727
    It depends. On older hardware you may have that behavior. On recent hardware, you will likely have an actual branch. Although, because this information is technically known ahead of time (since its a uniform variable) it may just evaluate one side of the branch. If you are not doing any sort of texture sampling within those functions you likely will not need to worry about the performance implications of a branch like this - although if you are, it may be problematic depending on your target hardware.
     
  5. revolute

    revolute

    Joined:
    Jul 28, 2014
    Posts:
    50
    URP code and shaders reveal how they are done internally.
    RealtimeLights.hlsl line 188 should be near
    GetAdditionalPerObjectLight
    and you can see how w component gets used.
    UniversalRenderPipelineCore.cs line near 822
    InitializeLightConstants_Common
    :
    Code (CSharp):
    1.  
    2.             VisibleLight lightData = lights[lightIndex];
    3.             if (lightData.lightType == LightType.Directional)
    4.             {
    5.                 Vector4 dir = -lightData.localToWorldMatrix.GetColumn(2);
    6.                 lightPos = new Vector4(dir.x, dir.y, dir.z, 0.0f);
    7.             }
    8.             else
    9.             {
    10.                 Vector4 pos = lightData.localToWorldMatrix.GetColumn(3);
    11.                 lightPos = new Vector4(pos.x, pos.y, pos.z, 1.0f);
    12.             }
    13.  
     
  6. RichardGoesToNightSchool

    RichardGoesToNightSchool

    Joined:
    Dec 9, 2020
    Posts:
    27
    Big brain :)
     
  7. RichardGoesToNightSchool

    RichardGoesToNightSchool

    Joined:
    Dec 9, 2020
    Posts:
    27
    I sampling a 1 x 8 ramp texture
     
  8. RichardGoesToNightSchool

    RichardGoesToNightSchool

    Joined:
    Dec 9, 2020
    Posts:
    27
    Do you think it would ever be possible to get the intensity and light color as separate value or is there some technical reason they have to be pre multiplied?
     
  9. migueltuliompg

    migueltuliompg

    Joined:
    Feb 12, 2018
    Posts:
    63
    Sorry to necro but I would also like to know this. I'm having difficulty with toon ramping on additional lights while preserving their intensity values.