提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
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
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 作为变量.
新版的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里 切记
多光源计算在新版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;
}
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;
}
学习如逆水行舟,不进则退.然而,我我努力的想进步,却赶不上技术的更新迭代速度.只能继续坚持了.累啊