I have been studying shaders for a couple of months now, and decided to put that knowledge to test by implementing a custom lighting shader, using shader graph and HLSL for some custom nodes. It is a cartoony shader, and instead of shadows, I want to apply a midtone scaled by the shadow intensity.
The goal is to start with an unlit shader, and implement:
- Main light: diffuse reflection (lambert), specular (phong), distance attenuation and shadows. - This is done.
- Additional lights: Same things.
But that is where my doubts begin:
Multiples lights requires several passes, which shader graph does not do by its own (right?).
I am not following a specific tutorial, but I saw some videos in which the person writes 1 HLSL file with the main AND additional lights implementation (using for loops), and links that in 1 single custom node. For example:
But what I did for dealing with multiple lights was slightly different than this video above.
I wrote one HLSL file (shown below) that counts and run through all the addional lights on the scene, and returns their direction, color and distance attenuation. Plus a bunch of keywords set to global and MultiCompile
But I left to perform the Dot product between the additional light direction and the surface normals in shader graph (also below).
HLSL file:
void AdditionalLights_float(float3 Position, out half3 Direction, out half3 Colors, out half DistanceAtten)
{
#if SHADERGRAPH_PREVIEW
Direction = half3(0.5, 0.5, 0);
Colors = 1;
DistanceAtten = 1;
#else
int LightCount = GetAdditionalLightsCount();
Light lights = GetMainLight();
for(int i = 0; i < LightCount; i++)
{
Light light = GetAdditionalLight(i, Position, 1);
Direction = light.direction;
Colors = light.color;
DistanceAtten = light.distanceAttenuation;
}
#endif
}
Shader Graph
I set up a scene with 2 additional lights.
But it seems only one of them works at a same time, and hich one change based on the direction of the camera.
In this video below I started ith the main light, and one additional light. Move it to show it works alright (no distance attenuation yet). Then enable a second additional light. You can see it does not influences the object. But hen I move the camera, it overrides the previous one. After that, I disable the first additional light, and the second one starts working fine.
So, my guess is:
My custom node only outputs the last light it finds (for loop), and shader graph only calculates the lighting based on this last output. Or rather, the last output overrides the first one.
Because shader graph does not have multiple passes.
In the first you tube video, the guy wrote the calculations inside the node, and it some how considers different passes? This is the part I don’t understand.
Cleary it dos not works, i I will write it all in HLSL, but I want to understand what is going on.
Cheers.