【unity】URP的shader开发中支持多光源,_ADDITIONAL_LIGHTS_VERTEX 和 _ADDITIONAL_LIGHTS 区别

项目里有一个其他同事实现的shader,美术那边希望能支持多个光源, 我一看代码里面, frag 函数里已经实现了
 


				#ifdef _ADDITIONAL_LIGHTS
					uint pixelLightCount = GetAdditionalLightsCount();
					for (uint lightIndex = 0u; lightIndex < pixelLightCount; ++lightIndex)
					{
						Light light = GetAdditionalLight(lightIndex, i.posWorld.xyz);
						half3 attenuatedLightColor = light.color * (light.distanceAttenuation * light.shadowAttenuation);
						lightColor += LightingLambert(attenuatedLightColor, light.direction, normalDirection);
					}
				#endif

代码也加了:

            #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS

材质里加了这个keyword还是没起作用,   若宏控制注了有效。  一开始没搞明白……
想到很可能这个关键字是系统本身控制的, 搜索了一下"_ADDITIONAL_LIGHTS",找到ForwardLights.cs里 确实控制了 _ADDITIONAL_LIGHTS 和 _ADDITIONAL_LIGHTS_VERTEX的开关,且2个只能存在一个(所以 multi_compile 是配置在一起的)
【unity】URP的shader开发中支持多光源,_ADDITIONAL_LIGHTS_VERTEX 和 _ADDITIONAL_LIGHTS 区别_第1张图片
最后发现是 UniversalRenderPipelineAsset 这个自定义配置里Additional Lights的配置:

【unity】URP的shader开发中支持多光源,_ADDITIONAL_LIGHTS_VERTEX 和 _ADDITIONAL_LIGHTS 区别_第2张图片

 perVertex (开 _ADDITIONAL_LIGHTS_VERTEX宏)表示 在顶点着色器 计算时,就取其他光源数据计算 光照值, 这样顶点数少 但像素绘制比较多(片元着色器执行次数更多)的情况,就能节省不少计算。

perPixel (开 _ADDITIONAL_LIGHTS) 表示  在片元着色器计算时,对其他光源做采样计算每个光照值 然后叠加。 (光源越多循环次数越多 性能影响也越大。)


一般来说使用 _ADDITIONAL_LIGHTS_VERTEX,可能要优化一些,但是有局限性,平行光还好,针对点光源,面片比较大的模型就很奇怪了,    这次就遇到这个问题,尝试地表接受一个点光源试试发现没作用,还以为代码没写好…………, 最后发现是它面太大了,顶点离点光源太远了 没计算进去……,如果点光跑到顶点附近 则还是有效果的, 但这个面片就整体发亮很奇怪。  

所以一般点光源 直接用lightmap烘培,运行时不要开,除非有特殊需求, 要么就是放到片元着色器里计算其他光。



自己写shader时如何让其支持  _ADDITIONAL_LIGHTS_VERTEX 或 _ADDITIONAL_LIGHTS呢?
可以参考simplelit.shader等 示例
_ADDITIONAL_LIGHTS比较简单
Fragment初始函数里在主光源后加

SimpleLitForwardPass.hlsl 调用的Lighting.hlsl 里的函数, 看 #ifdef _ADDITIONAL_LIGHTS 部分

half4 UniversalFragmentBlinnPhong(InputData inputData, half3 diffuse, half4 specularGloss, half smoothness, half3 emission, half alpha)
{
    Light mainLight = GetMainLight(inputData.shadowCoord);
    MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, half4(0, 0, 0, 0));

    half3 attenuatedLightColor = mainLight.color * (mainLight.distanceAttenuation * mainLight.shadowAttenuation);
    half3 diffuseColor = inputData.bakedGI + LightingLambert(attenuatedLightColor, mainLight.direction, inputData.normalWS);
#if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR)
    half3 specularColor = LightingSpecular(attenuatedLightColor, mainLight.direction, inputData.normalWS, inputData.viewDirectionWS, specularGloss, smoothness);
#else 
    half3 specularColor = 0;
#endif

#ifdef _ADDITIONAL_LIGHTS
    uint pixelLightCount = GetAdditionalLightsCount();
    for (uint lightIndex = 0u; lightIndex < pixelLightCount; ++lightIndex)
    {
        Light light = GetAdditionalLight(lightIndex, inputData.positionWS);
        half3 attenuatedLightColor = light.color * (light.distanceAttenuation * light.shadowAttenuation);
        diffuseColor += LightingLambert(attenuatedLightColor, light.direction, inputData.normalWS);
#if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR)
        specularColor += LightingSpecular(attenuatedLightColor, light.direction, inputData.normalWS, inputData.viewDirectionWS, specularGloss, smoothness);
#endif
    }
#endif

#ifdef _ADDITIONAL_LIGHTS_VERTEX
    diffuseColor += inputData.vertexLighting;
#endif

    half3 finalColor = diffuseColor * diffuse + emission;

#if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR)
    finalColor += specularColor;
#endif

    return half4(finalColor, alpha);
}

如果shader用的 BRDFData 数据结构的 类似这样加
 


#ifdef _ADDITIONAL_LIGHTS
    uint pixelLightCount = GetAdditionalLightsCount();
    for (uint lightIndex = 0u; lightIndex < pixelLightCount; ++lightIndex)
    {
        Light light = GetAdditionalLight(lightIndex, inputData.positionWS);
        color += LightingPhysicallyBased(brdfData, light, inputData.normalWS, inputData.viewDirectionWS);
    }
#endif

#ifdef _ADDITIONAL_LIGHTS_VERTEX
    color += inputData.vertexLighting * brdfData.diffuse;
#endif

我们自己实现的一个shader:
 


				float4 shadowCoord = TransformWorldToShadowCoord(i.posWorld.xyz);
				Light mainLight = GetMainLight(shadowCoord);
				float NDotL = dot(normalDirection, mainLight.direction);
				//float halfLambert = saturate(NDotL * 0.5 + 0.5);
				float Lambert = saturate(NDotL);

				//half3 gi = SampleSH(normalDirection);
				half3 attenuatedLightColor = mainLight.color * (mainLight.distanceAttenuation * mainLight.shadowAttenuation);
				half3 lightColor = Lambert * attenuatedLightColor;

                half3 bakedGI = SAMPLE_GI(i.lightmapUV, i.vertexSH, normalDirection);
                MixRealtimeAndBakedGI(mainLight, normalDirection, bakedGI, half4(0, 0, 0, 0));
                lightColor += bakedGI;

				#ifdef _ADDITIONAL_LIGHTS
					uint pixelLightCount = GetAdditionalLightsCount();
					for (uint lightIndex = 0u; lightIndex < pixelLightCount; ++lightIndex)
					{
						Light light = GetAdditionalLight(lightIndex, i.posWorld.xyz);
						half3 attenuatedLightColor = light.color * (light.distanceAttenuation * light.shadowAttenuation);
						lightColor += LightingLambert(attenuatedLightColor, light.direction, normalDirection);
					}
				#endif


#ifdef _ADDITIONAL_LIGHTS_VERTEX
                half3 vertexLighting = i.fogFactorAndVertexLight.yzw;
                lightColor += vertexLighting;
#endif

要支持 _ADDITIONAL_LIGHTS_VERTEX , (片元着色器代码 上面有示例了,不贴了)
主要是顶点着色器里的计算 和 怎么传递给片元着色器:
一般需要 结构体 v2f (或者叫 VertexOutput  或者叫 Varyings,反正是自己定义的)

定义一个 
    half4 fogFactorAndVertexLight   : TEXCOORD6; // x: fogFactor, yzw: vertex light
这个是把 unity自带fog的值一起传递了
当然单独加一个也是可以的

#if defined(_ADDITIONAL_LIGHTS_VERTEX) 
    float3 vertexLight                : TEXCOORD7;
#endif
【unity】URP的shader开发中支持多光源,_ADDITIONAL_LIGHTS_VERTEX 和 _ADDITIONAL_LIGHTS 区别_第3张图片

顶点着色器 vert函数里 要加代码
 


#ifdef _ADDITIONAL_LIGHTS_VERTEX
    half3 vertexLight = VertexLighting(vertexInput.positionWS, normalInput.normalWS);
#endif

和fogFactor拼在一起
output.fogFactorAndVertexLight = half4(fogFactor, vertexLight);
传给 片元着色器,   片元着色器计算时 再分别取 它们的值

另一个例子(不和 fogFactor, 单独传递):

#if defined(_ADDITIONAL_LIGHTS_VERTEX) 
    //Pass to fragment shader to apply in Lighting function
    output.vertexLight.rgb = VertexLighting(vertexData.positionWS, vertexData.normalWS);
#endif

你可能感兴趣的:(Unity,shader,unity,游戏引擎)