I am trying to create a retro-reflective material (the material on traffic signs, bicycle reflectors, cats eyes, etc.) in HDRP. I have found an example using URP complete with shader code, but it does not translate well to HDRP. In particular, the shader loops through each light to calculate the retro-reflective contribution, something I don’t know how to do in HDRP (I am new to shader programming in Unity).
Can anyone point me in the right direction on how to do this in HDRP? Can I do something in Shader Graph that I don’t know of (I don’t seem to able to do something per light) or maybe with a custom pass? Any ideas are welcome.
You’d need to loop through all the lights in the custom node and apply your custom lighting inside. Putting the resulting computation in the emissive is hacky but it could work since you don’t have access to lighting customization in ShaderGraph.
I have tried the first approach, since I think the second one is over my head and also possibly harder to maintain with newer Unity versions. I can’t get it to work, however. I am getting this error:
The include path is correct and if I follow some of files included by ShaderVariablesLightLoop.hlsl I eventually get to one where there is a _ViewMatrix at line 15!
Do you know how to solve this or where I can learn more about this approach?
You don’t need this include, it’s already there in the shader. Also this code will not work for the preview of the node and it has to be taken out explicitly (like any HDRP specific code). I think this is why you have this error
Like this:
#ifndef LIGHT_LOOP_TEST
#define LIGHT_LOOP_TEST
#ifndef SHADERGRAPH_PREVIEW
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonLighting.hlsl"
#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/PunctualLightCommon.hlsl"
void calculate_lights_float(float3 positionWS, out float intensity)
{
uint lightCount = _PunctualLightCount;
uint lightStart = 0;
float total = 0;
for (int i = 0; i < _DirectionalLightCount; i++)
{
DirectionalLightData dirLight = _DirectionalLightDatas[i];
total += 1;
}
for (int i = lightStart; i < lightCount; i++)
{
LightData light = _LightDatas[i];
float3 L;
float4 distances;
GetPunctualLightVectors(positionWS, light, L, distances);
float attenuation = PunctualLightAttenuation(distances, light.rangeAttenuationScale, light.rangeAttenuationBias,
light.angleScale, light.angleOffset);
total += attenuation;
}
intensity = total;
}
#else // SHADERGRAPH_PREVIEW
// Can't get lighting info inside ShaderGraph
void calculate_lights_float(float3 positionWS, out float intensity)
{
intensity = 0;
}
#endif // SHADERGRAPH_PREVIEW
#endif // LIGHT_LOOP_TEST
Shadows will not be taken into account with this emissive approach, of course, which would have been nice.
I wish there was a retroreflective shader feature that could be turned on in ShaderGraph settings somewhere. Maybe a retroreflective material type or an option for an existing type. The only special thing would be to adjust the normal toward each individual light in the light loop and calculate a retroreflective contribution, like the URP example, I think. Maybe I should make a feature request from your roadmap?
That’s correct, you can still sample the shadow maps In the code of the custom node but it’s a bit more complicated.
You can try making a feature request but since it’s a niche case it’s unlikely that it’ll get prioritized. Instead you can ask for custom lighting to be implemented in HDRP
Thank you for the tip! I ended up with something similar; Pointing the normals toward a specific light source (in my case a search light) but that required updating the lights position (and is only correct for that light). Your approach is much simpler. I don’t know if it is as physically accurate as what I was trying together with Antoinel, but I like the simplicity and maintainability.