Modifying the deferred pixel shaders color calculation for lights

I’m making a project with stylized graphics, materials are made only using base colors and no textures. My problem is that I want to be able to use pure single color channel lights such as “R=1.0, G=0.0, B=0.0” and have those cast light on materials even if the base color does not have any value for that channel, such as a material with base color “R=0.0, G=1.0, B=1.0”.

The LightAccumulator code looks like this:

void LightAccumulator_AddSplit(inout FLightAccumulator In, float3 DiffuseTotalLight, float3 SpecularTotalLight, float3 ScatterableLight, float3 CommonMultiplier, const bool bNeedsSeparateSubsurfaceLightAccumulation)
{

	...

	In.TotalLightDiffuse += DiffuseTotalLight * CommonMultiplier;

	...
}

Where the DiffuseTotalLight is the “material base color” and the CommonMultiplier is the “light color multiplied by intensity”. Currently the light with “R=1.0, G=0.0, B=0.0” would not affect the material without any R value since the shader calculation is done through multiplication.

I would like to change it to something like this instead:

In.TotalLightDiffuse += (DiffuseTotalLight  + LightColor) * LightIntensity

That way the light color would be applied no matter what, like adding a hue to the material based on light color. However like I mentioned this is not possible since the LightColor and LightIntensity does not exist separately at this stage but are instead both baked into the CommonMultiplier value. The CommonMultiplier values are huge so just adding them to the DiffuseTotalLight does not work.

I’ve tried looking through the code but I can’t figure out how the CommonMultiplier is calculated. If I knew how, I might be able to separate them in the LightAccumulator or modify the code so they are passed as two different fields instead.

I can see that the CommonMultiplier is taken from the FDeferredLightData.Color value in DeferredLightingCommon.AccumulateDynamicLighting(), this struct is initialized using the LightDataUniforms.InitDeferredLightFromUniforms() function and the Color value is copied from DeferredLightUniforms.Color. This is where my ush/c++ knowledge is lacking, I cannot figure out what the DeferredLightUniforms even is and where its values comes from. Could anyone more knowledgeable enlighten me on this?

I would of course also be open to some other clever solution to my problem, if you have any ideas how it could be solved :slight_smile:

I sort of solved this. Figured out how the uniform buffers work, separated the light intensity and color and tried to add the material and light colors together in the LightAccumulator shader. After 4 loong hours of rebuilding from source I found out that it did not work as I expected. Everything got waaay too bright…

I then learned how to debug shaders with RenderDoc and found the problem, the material color values in the LightAccumulator was not what I expected. It is not the same value you set in editor since it has already been modified based on the angle towards the light. Even pixels that are directly facing the light have been changed and were around 100000 times smaller than in editor. So it made perfect sense why all the lights were super bright since I was adding something like 0.5 to 0.000005.

I managed to sort of get what I wanted in the end though. I changed the shader so that “mostly white” lights (all channels on similar level) work just like normal, simply increasing the materials brightness. However for colored light I changed it so that they fully replace the material color giving me the type of stylized look I was going for.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.