Hello! I’m building a game with a toon graphic style which requires many lights to be displayed, more than 8 per object (so I can’t use neither deferred nor Forward rendering). I updated Unity to 2022.2.10f1 and URP to 14.0.6, and set the rendering setting to Forward+. I had to adapt my hlsl code to make it work with Forward+, and I modified NedMakesGame’s Lighting.hlsl script (from a toon tutorial video) to make it work with Forward+:
#ifndef CUSTOM_LIGHTING_INCLUDED
#define CUSTOM_LIGHTING_INCLUDED
float GetLightIntensity(float3 color)
{
return max(color.r, max(color.g, color.b));
}
void CalculateMainLight_float(float3 WorldPos, out float3 Direction, out float3 Color, out half DistanceAtten, out half ShadowAtten, out float Intensity)
{
#ifdef SHADERGRAPH_PREVIEW
Direction = half3(0.5, 0.5, 0);
Color = 1;
Intensity = 0;
DistanceAtten = 1;
ShadowAtten = 1;
#else
#if SHADOWS_SCREEN
half4 clipPos = TransformWorldToHClip(WorldPos);
half4 shadowCoord = ComputeScreenPos(clipPos);
#else
half4 shadowCoord = TransformWorldToShadowCoord(WorldPos);
#endif
Light mainLight = GetMainLight(shadowCoord);
Direction = mainLight.direction;
Color = mainLight.color;
DistanceAtten = mainLight.distanceAttenuation;
ShadowAtten = mainLight.shadowAttenuation;
Intensity = GetLightIntensity(mainLight.color);
#endif
}
#ifndef SHADERGRAPH_PREVIEW
// This function gets additional light data and calculates realtime shadows
Light GetAdditionalLightForToon(int pixelLightIndex, float3 worldPosition)
{
// Convert the pixel light index to the light data index
int perObjectLightIndex = GetPerObjectLightIndex(pixelLightIndex);
// Call the URP additional light algorithm. This will not calculate shadows, since we don't pass a shadow mask value
Light light = GetAdditionalPerObjectLight(perObjectLightIndex, worldPosition);
// Manually set the shadow attenuation by calculating realtime shadows
light.shadowAttenuation = AdditionalLightRealtimeShadow(perObjectLightIndex, worldPosition);
return light;
}
#endif
void AddAdditionalLights_float(float Smoothness, float3 WorldPosition, float3 WorldNormal, float3 WorldView,
float MainDiffuse, float MainSpecular, float3 MainColor, float3 ScreenPosition,
out float Diffuse, out float Specular, out float3 Color)
{
float mainIntensity = GetLightIntensity(MainColor);
Diffuse = 0;
Specular = 0;
Color = MainColor;
float totalDiffuse = 0; // Aggiunto per accumulare i valori di thisDiffuse
#ifndef SHADERGRAPH_PREVIEW
InputData inputData = (InputData) 0;
float highestDiffuse = Diffuse;
float maxIntensity = 0;
float intensity = 0;
uint meshRenderingLayers = GetMeshRenderingLayer();
inputData.normalizedScreenSpaceUV = ScreenPosition;
inputData.positionWS = WorldPosition;
uint lightsCount = GetAdditionalLightsCount();
LIGHT_LOOP_BEGIN(lightsCount)
Light light = GetAdditionalLight(lightIndex, WorldPosition);
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
half NdotL = saturate(dot(WorldNormal, light.direction));
half atten = light.distanceAttenuation * light.shadowAttenuation * GetLightIntensity(light.color);
half thisDiffuse = atten * NdotL;
half thisSpecular = LightingSpecular(thisDiffuse, light.direction, WorldNormal, WorldView, 1, Smoothness);
Diffuse += thisDiffuse;
Specular += thisSpecular;
intensity = GetLightIntensity(light.color);
if (thisDiffuse > 0)
{
if (intensity > maxIntensity)
{
maxIntensity = intensity;
Color = light.color;
}
}
}
LIGHT_LOOP_END
#endif
}
#endif
As you can see I’m using the LIGHT_LOOP system and I changed the GetAdditionalPerObjectLight function, and it works. When there are few objects and lights.
If I have many objects and many lights, the game crashes with this error:
This is a big problem and it should mean that the GPU is somehow under great stress, but switching to Forward or Deferred rendering, with the same amount of objects and lights in the same scene, doesn’t make the game crash. So I find a bit weird that a feature that has been literally implemented to handle more lights can’t even handle as many lights as Forward or Deferred do. I guess I’m doing something wrong with the code…
In small scenes with few objects, the Forward+ works correctly even with 20/30 lights, as it should. The scene where the game crashes has thousand of objects (not all of them are nearby a light, I’d say that there are about 30-40 objects inside the lights ranges) and about 4-8 lights.
Could somebody help? My GPU drivers are updated and I’m using a RX480 4GB card.