URP下关于RealtimeShadow的一些笔记——Unity学习笔记

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 自言自语
  • 一、ShadowMask
    • 采样unity_ShadowMask
  • 二、AdditionalLight
    • 多光源计算
    • 单Pass额外光源 shader中计算
  • 总结


自言自语

URP经历了几个版本的迭代,内置的一些关于阴影的计算被套娃套的一层有一层。对于美术的我着实头疼。于是一个一个找HLSL,把相关宏,内置变量,相关计算整理出来,方便以后自己查阅(复制粘贴)

在一切复制粘贴工作开始之前,先要声明好灯光和阴影相应的引用定义

#pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN
#pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
#pragma multi_compile_fragment _ _LIGHT_LAYERS
#pragma multi_compile_fragment _ _LIGHT_COOKIES
#pragma multi_compile _ _CLUSTERED_RENDERING
//反射探针使用声明
#pragma multi_compile_fragment _ _REFLECTION_PROBE_BLENDING
#pragma multi_compile_fragment _ _REFLECTION_PROBE_BOX_PROJECTION
//软阴影
#pragma multi_compile_fragment _ _SHADOWS_SOFT
//SSAO屏幕空间AO
#pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION

//Lightmap阴影混合
#pragma multi_compile _ LIGHTMAP_SHADOW_MIXING
//开启shadowMask
#pragma multi_compile _ SHADOWS_SHADOWMASK
#pragma multi_compile _ DIRLIGHTMAP_COMBINED
//开启静态光照烘焙
#pragma multi_compile _ LIGHTMAP_ON
//动态光照贴图开启 实时光照贴图
#pragma multi_compile _ DYNAMICLIGHTMAP_ON
//开启Unity雾效
#pragma multi_compile_fog

一、ShadowMask

URP对于shadowMask进行了重新定义并且采样方式有了变化具体如下
变量名

//如果开启了DOTS则内置变量为如下
#if defined(UNITY_DOTS_INSTANCING_ENABLED)
#define SHADOWMASK_NAME unity_ShadowMasks
#define SHADOWMASK_SAMPLER_NAME samplerunity_ShadowMasks
#define SHADOWMASK_SAMPLE_EXTRA_ARGS , unity_LightmapIndex.x
//否则为正常情况下的变量名
#else
#define SHADOWMASK_NAME unity_ShadowMask
#define SHADOWMASK_SAMPLER_NAME samplerunity_ShadowMask
#define SHADOWMASK_SAMPLE_EXTRA_ARGS 

来了解下什么是DOTS?

DOTS是Data-Oriented-Tech-Stack,官方中文翻译是:多线程式数据导向型技术堆栈。
不明觉厉.不过目前网上大多都说明DOTS虽然实可以解决很大的性能问题.但是坑很多.一般项目或者没有大神程序员的话好像用到的不多,或者用到的只是一小部分.因此我这边主要还是采用 unity_ShadowMask 作为变量.

采样unity_ShadowMask

新版的URP采样shadowmask有了变化,采样器规则变为

#if defined(SHADOWS_SHADOWMASK) && defined(LIGHTMAP_ON)
    #define SAMPLE_SHADOWMASK(uv) SAMPLE_TEXTURE2D_LIGHTMAP(SHADOWMASK_NAME, SHADOWMASK_SAMPLER_NAME, uv SHADOWMASK_SAMPLE_EXTRA_ARGS);
#elif !defined (LIGHTMAP_ON)
    #define SAMPLE_SHADOWMASK(uv) unity_ProbesOcclusion;
#else
    #define SAMPLE_SHADOWMASK(uv) half4(1, 1, 1, 1);
#endif

这段是根据不同情况定义不同的采样 我们一般自己写shader就是要使用

SAMPLE_SHADOWMASK(input.staticLightmapUV);

SAMPLE_TEXTURE2D是不能直接采样shadowMask的。lightmapUV是2U 所以要定义在 TEXCOORD1里 切记

二、AdditionalLight

多光源计算

多光源计算在新版URP下 也有好几个重载。并且分出了 addlight.shadowAttenuation和addlight.distanceAttenuation两个阴影衰减计算.两者相乘才是最终正确的额外光源阴影计算. 一般情况下
addlight.shadowAttenuation =1;
但在GetAddtionalLight()的重载方法里, addlight.shadowAttenuation会被重载复写.

Light GetAdditionalLight(uint i, float3 positionWS, half4 shadowMask)
{
#if USE_CLUSTERED_LIGHTING
    int lightIndex = i;
#else
    int lightIndex = GetPerObjectLightIndex(i);
#endif
    Light light = GetAdditionalPerObjectLight(lightIndex, positionWS);

#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
    half4 occlusionProbeChannels = _AdditionalLightsBuffer[lightIndex].occlusionProbeChannels;
#else
    half4 occlusionProbeChannels = _AdditionalLightsOcclusionProbes[lightIndex];
#endif
    light.shadowAttenuation = AdditionalLightShadow(lightIndex, positionWS, light.direction, shadowMask, occlusionProbeChannels);
#if defined(_LIGHT_COOKIES)
    real3 cookieColor = SampleAdditionalLightCookie(lightIndex, positionWS);
    light.color *= cookieColor;
#endif

    return light;
}

这点其实 GetMainLight()方法也是一样的.具体就不写了 一般自定义的shader里貌似比较少用到.
另外如果要支持ssao 那么灯光的方法也有新的重载

Light GetAdditionalLight(uint i, InputData inputData, half4 shadowMask, AmbientOcclusionFactor aoFactor)
{
    Light light = GetAdditionalLight(i, inputData.positionWS, shadowMask);

    #if defined(_SCREEN_SPACE_OCCLUSION) && !defined(_SURFACE_TYPE_TRANSPARENT)
    if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_AMBIENT_OCCLUSION))
    {
        light.color *= aoFactor.directAmbientOcclusion;
    }
    #endif

    return light;
}

单Pass额外光源 shader中计算

URP的优势在于单Pass多光源计算,即一个pass里就完成了所有灯光的便利和计算.减少DC.
在新版URP中.光照计算增加了 CLUSTERED 的灯光渲染方式. 需要单独开启.开启后额外光源的计算也略微有变化.不过在ADDlight便利计算中都有定义宏来区分

代码如下(示例):

    uint meshRenderingLayers = GetMeshRenderingLightLayer();
    #if defined(_ADDITIONAL_LIGHTS)
    uint pixelLightCount = GetAdditionalLightsCount();

    #if USE_CLUSTERED_LIGHTING
    for (uint lightIndex = 0; lightIndex < min(_AdditionalLightsDirectionalCount, MAX_VISIBLE_LIGHTS); lightIndex++)
    {
        Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor);

        if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
        {
            lightingData.additionalLightsColor += LightingPhysicallyBased(brdfData, brdfDataClearCoat, light,
                                                                          inputData.normalWS, inputData.viewDirectionWS,
                                                                          surfaceData.clearCoatMask, specularHighlightsOff);
        }
    }
    #endif

    LIGHT_LOOP_BEGIN(pixelLightCount)
        Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor);

        if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
        {
            lightingData.additionalLightsColor += LightingPhysicallyBased(brdfData, brdfDataClearCoat, light,
                                                                          inputData.normalWS, inputData.viewDirectionWS,
                                                                          surfaceData.clearCoatMask, specularHighlightsOff);
        }
    LIGHT_LOOP_END
    #endif

原理和处理方法是上面的 我们自定义shader不需要进行那么复杂BRDF计算时 可以简写如下

 #if defined(_ADDITIONAL_LIGHTS)
	uint meshRenderingLayers = GetMeshRenderingLightLayer();
	uint lightCounts = GetAdditionalLightsCount();
	
	for (uint lightIndex = 0 ; lightIndex<lightCounts;lightIndex++)
	{
		//shadowmask 可以用求得的shadowcoord代替 不写此参数则不会有阴影计算
		Light addLight = GetAdditionalLight(lightIndex,i.posWS,ShadowMask);
		if (IsMatchingLightLayer(addLight.layerMask, meshRenderingLayers))
		{
			half3 lightColor = addLight.color*addLight.shadowAttenuation*addLight.distanceAttenuation;
			col.rgb += lightColor;
		}
	}

#endif

这样灯光阴影可以以后拿来copy了

代码三种重载第一种是不带阴影的。 所以Attenuation均为1

Light GetAdditionalLight(uint i, float3 positionWS)
{
#if USE_CLUSTERED_LIGHTING
    int lightIndex = i;
#else
    int lightIndex = GetPerObjectLightIndex(i);
#endif
    return GetAdditionalPerObjectLight(lightIndex, positionWS);
}

Light GetAdditionalLight(uint i, float3 positionWS, half4 shadowMask)
{
#if USE_CLUSTERED_LIGHTING
    int lightIndex = i;
#else
    int lightIndex = GetPerObjectLightIndex(i);
#endif
    Light light = GetAdditionalPerObjectLight(lightIndex, positionWS);

#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
    half4 occlusionProbeChannels = _AdditionalLightsBuffer[lightIndex].occlusionProbeChannels;
#else
    half4 occlusionProbeChannels = _AdditionalLightsOcclusionProbes[lightIndex];
#endif
    light.shadowAttenuation = AdditionalLightShadow(lightIndex, positionWS, light.direction, shadowMask, occlusionProbeChannels);
#if defined(_LIGHT_COOKIES)
    real3 cookieColor = SampleAdditionalLightCookie(lightIndex, positionWS);
    light.color *= cookieColor;
#endif

    return light;
}

Light GetAdditionalLight(uint i, InputData inputData, half4 shadowMask, AmbientOcclusionFactor aoFactor)
{
    Light light = GetAdditionalLight(i, inputData.positionWS, shadowMask);

    #if defined(_SCREEN_SPACE_OCCLUSION) && !defined(_SURFACE_TYPE_TRANSPARENT)
    if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_AMBIENT_OCCLUSION))
    {
        light.color *= aoFactor.directAmbientOcclusion;
    }
    #endif

    return light;
}

总结

学习如逆水行舟,不进则退.然而,我我努力的想进步,却赶不上技术的更新迭代速度.只能继续坚持了.累啊

你可能感兴趣的:(TA个人学习笔记,平面,unity,游戏引擎)