URP版本16.0.6
打开SimpleLit.shader文件;
SubShader Tags:
Tags
{
"RenderType" = "Opaque"
"RenderPipeline" = "UniversalPipeline" //该SubShader是给 UniversalPipeline 使用的
"UniversalMaterialType" = "SimpleLit" //延迟渲染使用,标识光照模式
"IgnoreProjector" = "True" //忽略投影,非阴影
}
用于前向渲染,渲染几何表面和计算所有的光照影响;
Pass
{
Name "ForwardLit"
Tags
{
"LightMode" = "UniversalForward"
}
// -------------------------------------
// Render State Commands
// Use same blending / depth states as Standard shader
Blend[_SrcBlend][_DstBlend], [_SrcBlendAlpha][_DstBlendAlpha]
ZWrite[_ZWrite]
Cull[_Cull]
AlphaToMask[_AlphaToMask]
HLSLPROGRAM
#pragma target 2.0
// -------------------------------------
// Shader Stages
#pragma vertex LitPassVertexSimple
#pragma fragment LitPassFragmentSimple
// -------------------------------------
// Material Keywords
#pragma shader_feature_local _NORMALMAP
#pragma shader_feature_local_fragment _EMISSION
#pragma shader_feature_local _RECEIVE_SHADOWS_OFF
#pragma shader_feature_local_fragment _SURFACE_TYPE_TRANSPARENT
#pragma shader_feature_local_fragment _ALPHATEST_ON
#pragma shader_feature_local_fragment _ _ALPHAPREMULTIPLY_ON _ALPHAMODULATE_ON
#pragma shader_feature_local_fragment _ _SPECGLOSSMAP _SPECULAR_COLOR
#pragma shader_feature_local_fragment _GLOSSINESS_FROM_BASE_ALPHA
// -------------------------------------
// Universal Pipeline keywords
#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 _ EVALUATE_SH_MIXED EVALUATE_SH_VERTEX
#pragma multi_compile _ LIGHTMAP_SHADOW_MIXING
#pragma multi_compile _ SHADOWS_SHADOWMASK
#pragma multi_compile _ _LIGHT_LAYERS
#pragma multi_compile _ _FORWARD_PLUS
#pragma multi_compile_fragment _ _ADDITIONAL_LIGHT_SHADOWS
#pragma multi_compile_fragment _ _SHADOWS_SOFT
#pragma multi_compile_fragment _ _SHADOWS_SOFT_LOW _SHADOWS_SOFT_MEDIUM _SHADOWS_SOFT_HIGH
#pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION
#pragma multi_compile_fragment _ _DBUFFER_MRT1 _DBUFFER_MRT2 _DBUFFER_MRT3
#pragma multi_compile_fragment _ _LIGHT_COOKIES
#include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRenderingKeywords.hlsl"
#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ProbeVolumeVariants.hlsl"
#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RenderingLayers.hlsl"
// -------------------------------------
// Unity defined keywords
#pragma multi_compile _ DIRLIGHTMAP_COMBINED
#pragma multi_compile _ LIGHTMAP_ON
#pragma multi_compile _ DYNAMICLIGHTMAP_ON
#pragma multi_compile_fog
#pragma multi_compile_fragment _ DEBUG_DISPLAY
#pragma multi_compile_fragment _ LOD_FADE_CROSSFADE
//--------------------------------------
// GPU Instancing
#pragma multi_compile_instancing
#pragma instancing_options renderinglayer
#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
//--------------------------------------
// Defines
#define BUMP_SCALE_NOT_SUPPORTED 1
// -------------------------------------
// Includes
#include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitForwardPass.hlsl"
ENDHLSL
}
Varyings LitPassVertexSimple(Attributes input)
{
Varyings output = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_TRANSFER_INSTANCE_ID(input, output);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
//获取顶点在各坐标系下的位置
VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
//获取切线空间各坐标轴在世界空间下的表示
VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS);
#if defined(_FOG_FRAGMENT)
half fogFactor = 0;
#else
half fogFactor = ComputeFogFactor(vertexInput.positionCS.z);
#endif
output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap);
output.positionWS.xyz = vertexInput.positionWS;
output.positionCS = vertexInput.positionCS;
#ifdef _NORMALMAP
half3 viewDirWS = GetWorldSpaceViewDir(vertexInput.positionWS);
output.normalWS = half4(normalInput.normalWS, viewDirWS.x);
output.tangentWS = half4(normalInput.tangentWS, viewDirWS.y);
output.bitangentWS = half4(normalInput.bitangentWS, viewDirWS.z);
#else
output.normalWS = NormalizeNormalPerVertex(normalInput.normalWS);
#endif
//静态光照贴图uv
OUTPUT_LIGHTMAP_UV(input.staticLightmapUV, unity_LightmapST, output.staticLightmapUV);
#ifdef DYNAMICLIGHTMAP_ON
//动态光照贴图uv
output.dynamicLightmapUV = input.dynamicLightmapUV.xy * unity_DynamicLightmapST.xy + unity_DynamicLightmapST.zw;
#endif
//使用顶点自身的法线,计算顶点球谐光照
OUTPUT_SH4(vertexInput.positionWS, output.normalWS.xyz, GetWorldSpaceNormalizeViewDir(vertexInput.positionWS), output.vertexSH);
#ifdef _ADDITIONAL_LIGHTS_VERTEX
//使用兰伯特漫反射计算额外光源顶点光照
half3 vertexLight = VertexLighting(vertexInput.positionWS, normalInput.normalWS);
output.fogFactorAndVertexLight = half4(fogFactor, vertexLight);
#else
output.fogFactor = fogFactor;
#endif
#if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
//阴影坐标
output.shadowCoord = GetShadowCoord(vertexInput);
#endif
return output;
}
顶点着色器输入输出:
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
float4 tangentOS : TANGENT;
float2 texcoord : TEXCOORD0;
float2 staticLightmapUV : TEXCOORD1;
float2 dynamicLightmapUV : TEXCOORD2;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float2 uv : TEXCOORD0;
float3 positionWS : TEXCOORD1; // xyz: posWS
#ifdef _NORMALMAP
half4 normalWS : TEXCOORD2; // xyz: normal, w: viewDir.x
half4 tangentWS : TEXCOORD3; // xyz: tangent, w: viewDir.y
half4 bitangentWS : TEXCOORD4; // xyz: bitangent, w: viewDir.z
#else
half3 normalWS : TEXCOORD2;
#endif
#ifdef _ADDITIONAL_LIGHTS_VERTEX
half4 fogFactorAndVertexLight : TEXCOORD5; // x: fogFactor, yzw: vertex light
#else
half fogFactor : TEXCOORD5;
#endif
#if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
float4 shadowCoord : TEXCOORD6;
#endif
DECLARE_LIGHTMAP_OR_SH(staticLightmapUV, vertexSH, 7); //根据 LIGHTMAP_ON 来声明其中一个变量
#ifdef DYNAMICLIGHTMAP_ON
float2 dynamicLightmapUV : TEXCOORD8; // Dynamic lightmap UVs
#endif
float4 positionCS : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
获取顶点在各坐标系下的位置:
VertexPositionInputs GetVertexPositionInputs(float3 positionOS)
{
VertexPositionInputs input;
input.positionWS = TransformObjectToWorld(positionOS);
input.positionVS = TransformWorldToView(input.positionWS);
input.positionCS = TransformWorldToHClip(input.positionWS);
//为防止除以w导致非线性插值,留待在片元着色器中执行
float4 ndc = input.positionCS * 0.5f;
input.positionNDC.xy = float2(ndc.x, ndc.y * _ProjectionParams.x) + ndc.w;
input.positionNDC.zw = input.positionCS.zw;
return input;
}
获取切线空间各坐标轴在世界空间下的表示:
VertexNormalInputs GetVertexNormalInputs(float3 normalOS, float4 tangentOS)
{
VertexNormalInputs tbn;
// mikkts space compliant. only normalize when extracting normal at frag.
//tangentOS.w表示切线空间的手性,OddNegativeScale表示xyz中的奇数次缩放
real sign = real(tangentOS.w) * GetOddNegativeScale();
tbn.normalWS = TransformObjectToWorldNormal(normalOS);
tbn.tangentWS = real3(TransformObjectToWorldDir(tangentOS.xyz));
tbn.bitangentWS = real3(cross(tbn.normalWS, float3(tbn.tangentWS))) * sign;
return tbn;
}
计算雾效系数:
real ComputeFogFactor(float zPositionCS)
{
//将zPositionCS的范围修正到[0, Far]
float clipZ_0Far = UNITY_Z_0_FAR_FROM_CLIPSPACE(zPositionCS);
return ComputeFogFactorZ0ToFar(clipZ_0Far);
}
获取世界空间视角方向:
// Computes the world space view direction (pointing towards the viewer).
float3 GetWorldSpaceViewDir(float3 positionWS)
{
if (IsPerspectiveProjection())
{
// Perspective
return GetCurrentViewPosition() - positionWS;
}
else
{
// Orthographic
return -GetViewForwardDir();
}
}
// Returns the forward (central) direction of the current view in the world space.
float3 GetViewForwardDir()
{
//返回摄像机中心在世界坐标下的朝向
//假设view to world矩阵为M,则M的每列对应view中各坐标轴在世界空间下的表示,因此view中z轴对应M的第三列
//viewMat为M的转置,因此view中的z轴对应viewMat的第三行,而view中z与摄像机的朝向相反,故取反处理
float4x4 viewMat = GetWorldToViewMatrix();
return -viewMat[2].xyz;
}
使用兰伯特漫反射计算额外光源顶点光照:
half3 VertexLighting(float3 positionWS, half3 normalWS)
{
half3 vertexLightColor = half3(0.0, 0.0, 0.0);
#ifdef _ADDITIONAL_LIGHTS_VERTEX
uint lightsCount = GetAdditionalLightsCount();
uint meshRenderingLayers = GetMeshRenderingLayer();
//渲染时,urp将所有光源信息传递给shader
LIGHT_LOOP_BEGIN(lightsCount)
Light light = GetAdditionalLight(lightIndex, positionWS);
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
half3 lightColor = light.color * light.distanceAttenuation;
//不考虑阴影,兰伯特漫反射
vertexLightColor += LightingLambert(lightColor, light.direction, normalWS);
}
LIGHT_LOOP_END
#endif
return vertexLightColor;
}
// Fills a light struct given a loop i index. This will convert the i
// index to a perObjectLightIndex
Light GetAdditionalLight(uint i, float3 positionWS)
{
#if USE_FORWARD_PLUS
int lightIndex = i;
#else
int lightIndex = GetPerObjectLightIndex(i);
#endif
return GetAdditionalPerObjectLight(lightIndex, positionWS);
}
// Fills a light struct given a perObjectLightIndex
Light GetAdditionalPerObjectLight(int perObjectLightIndex, float3 positionWS)
{
//读取光源信息
// Abstraction over Light input constants
#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
float4 lightPositionWS = _AdditionalLightsBuffer[perObjectLightIndex].position;
half3 color = _AdditionalLightsBuffer[perObjectLightIndex].color.rgb;
half4 distanceAndSpotAttenuation = _AdditionalLightsBuffer[perObjectLightIndex].attenuation;
half4 spotDirection = _AdditionalLightsBuffer[perObjectLightIndex].spotDirection;
uint lightLayerMask = _AdditionalLightsBuffer[perObjectLightIndex].layerMask;
#else
float4 lightPositionWS = _AdditionalLightsPosition[perObjectLightIndex];
half3 color = _AdditionalLightsColor[perObjectLightIndex].rgb;
half4 distanceAndSpotAttenuation = _AdditionalLightsAttenuation[perObjectLightIndex];
half4 spotDirection = _AdditionalLightsSpotDir[perObjectLightIndex];
uint lightLayerMask = asuint(_AdditionalLightsLayerMasks[perObjectLightIndex]);
#endif
// Directional lights store direction in lightPosition.xyz and have .w set to 0.0.
// This way the following code will work for both directional and punctual lights.
float3 lightVector = lightPositionWS.xyz - positionWS * lightPositionWS.w;
float distanceSqr = max(dot(lightVector, lightVector), HALF_MIN);
half3 lightDirection = half3(lightVector * rsqrt(distanceSqr)); //rsqrt 平方根的倒数
// full-float precision required on some platforms
//计算距离衰减
float attenuation = DistanceAttenuation(distanceSqr, distanceAndSpotAttenuation.xy) * AngleAttenuation(spotDirection.xyz, lightDirection, distanceAndSpotAttenuation.zw);
Light light;
light.direction = lightDirection;
light.distanceAttenuation = attenuation;
//阴影缩减后续计算
light.shadowAttenuation = 1.0; // This value can later be overridden in GetAdditionalLight(uint i, float3 positionWS, half4 shadowMask)
light.color = color;
light.layerMask = lightLayerMask;
return light;
}
计算阴影坐标:
float4 GetShadowCoord(VertexPositionInputs vertexInput)
{
#if defined(_MAIN_LIGHT_SHADOWS_SCREEN) && !defined(_SURFACE_TYPE_TRANSPARENT)
//屏幕空间阴影纹理,和先前计算input.positionNDC一样
return ComputeScreenPos(vertexInput.positionCS);
#else
return TransformWorldToShadowCoord(vertexInput.positionWS);
#endif
}
//将世界坐标转换为阴影坐标
float4 TransformWorldToShadowCoord(float3 positionWS)
{
#ifdef _MAIN_LIGHT_SHADOWS_CASCADE
half cascadeIndex = ComputeCascadeIndex(positionWS);
#else
half cascadeIndex = half(0.0);
#endif
float4 shadowCoord = mul(_MainLightWorldToShadow[cascadeIndex], float4(positionWS, 1.0));
return float4(shadowCoord.xyz, 0);
}
// Used for StandardSimpleLighting shader
void LitPassFragmentSimple(
Varyings input
, out half4 outColor : SV_Target0
#ifdef _WRITE_RENDERING_LAYERS
, out float4 outRenderingLayers : SV_Target1
#endif
)
{
UNITY_SETUP_INSTANCE_ID(input);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
//获取表面数据
SurfaceData surfaceData;
InitializeSimpleLitSurfaceData(input.uv, surfaceData);
#ifdef LOD_FADE_CROSSFADE
LODFadeCrossFade(input.positionCS);
#endif
//获取光照计算相关数据
InputData inputData;
InitializeInputData(input, surfaceData.normalTS, inputData);
SETUP_DEBUG_TEXTURE_DATA(inputData, input.uv, _BaseMap);
#ifdef _DBUFFER
//应用Decal贴花,修改 SurfaceData,以及 InputData 法线
ApplyDecalToSurfaceData(input.positionCS, surfaceData, inputData);
#endif
//使用BlinnPhong光照模型
half4 color = UniversalFragmentBlinnPhong(inputData, surfaceData);
//雾效混合
color.rgb = MixFog(color.rgb, inputData.fogCoord);
color.a = OutputAlpha(color.a, IsSurfaceTypeTransparent(_Surface));
outColor = color;
#ifdef _WRITE_RENDERING_LAYERS
uint renderingLayers = GetMeshRenderingLayer();
outRenderingLayers = float4(EncodeMeshRenderingLayer(renderingLayers), 0, 0, 0);
#endif
}
获取表面数据:
inline void InitializeSimpleLitSurfaceData(float2 uv, out SurfaceData outSurfaceData)
{
outSurfaceData = (SurfaceData)0;
//采样_BaseMap
half4 albedoAlpha = SampleAlbedoAlpha(uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap));
outSurfaceData.alpha = albedoAlpha.a * _BaseColor.a;
//执行透明度测试,以及AlphaToMask相关处理
outSurfaceData.alpha = AlphaDiscard(outSurfaceData.alpha, _Cutoff);
outSurfaceData.albedo = albedoAlpha.rgb * _BaseColor.rgb;
outSurfaceData.albedo = AlphaModulate(outSurfaceData.albedo, outSurfaceData.alpha);
//获取高光颜色和 smoothness
half4 specularSmoothness = SampleSpecularSmoothness(uv, outSurfaceData.alpha, _SpecColor, TEXTURE2D_ARGS(_SpecGlossMap, sampler_SpecGlossMap));
outSurfaceData.metallic = 0.0; // unused
outSurfaceData.specular = specularSmoothness.rgb;
outSurfaceData.smoothness = specularSmoothness.a;
//采样切线空间法线
outSurfaceData.normalTS = SampleNormal(uv, TEXTURE2D_ARGS(_BumpMap, sampler_BumpMap));
outSurfaceData.occlusion = 1.0;
//采样自发光颜色
outSurfaceData.emission = SampleEmission(uv, _EmissionColor.rgb, TEXTURE2D_ARGS(_EmissionMap, sampler_EmissionMap));
}
#endif
初始化光照计算相关数据:
void InitializeInputData(Varyings input, half3 normalTS, out InputData inputData)
{
inputData = (InputData)0;
inputData.positionWS = input.positionWS;
#ifdef _NORMALMAP //使用切线空间下的法线
half3 viewDirWS = half3(input.normalWS.w, input.tangentWS.w, input.bitangentWS.w);
//切线空间到世界空间的变换矩阵得将各坐标轴在世界空间下的表示 按列存放,但是不好构建矩阵,故按行存放
inputData.tangentToWorld = half3x3(input.tangentWS.xyz, input.bitangentWS.xyz, input.normalWS.xyz);
inputData.normalWS = TransformTangentToWorld(normalTS, inputData.tangentToWorld);
#else
half3 viewDirWS = GetWorldSpaceNormalizeViewDir(inputData.positionWS);
inputData.normalWS = input.normalWS;
#endif
inputData.normalWS = NormalizeNormalPerPixel(inputData.normalWS);
//视角方向
viewDirWS = SafeNormalize(viewDirWS);
inputData.viewDirectionWS = viewDirWS;
//阴影坐标
#if defined(REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR)
inputData.shadowCoord = input.shadowCoord;
#elif defined(MAIN_LIGHT_CALCULATE_SHADOWS)
inputData.shadowCoord = TransformWorldToShadowCoord(inputData.positionWS);
#else
inputData.shadowCoord = float4(0, 0, 0, 0);
#endif
//片元雾效系数计算以及提取额外的顶点光照
#ifdef _ADDITIONAL_LIGHTS_VERTEX
inputData.fogCoord = InitializeInputDataFog(float4(inputData.positionWS, 1.0), input.fogFactorAndVertexLight.x);
inputData.vertexLighting = input.fogFactorAndVertexLight.yzw;
#else
inputData.fogCoord = InitializeInputDataFog(float4(inputData.positionWS, 1.0), input.fogFactor);
inputData.vertexLighting = half3(0, 0, 0);
#endif
#if defined(DYNAMICLIGHTMAP_ON) 烘培的光照贴图 和 实时的光照贴图
inputData.bakedGI = SAMPLE_GI(input.staticLightmapUV, input.dynamicLightmapUV, input.vertexSH, inputData.normalWS);
#elif !defined(LIGHTMAP_ON) && (defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2)) //光照探针
inputData.bakedGI = SAMPLE_GI(input.vertexSH,
GetAbsolutePositionWS(inputData.positionWS),
inputData.normalWS,
inputData.viewDirectionWS,
input.positionCS.xy);
#else //逐像素球谐光照
inputData.bakedGI = SAMPLE_GI(input.staticLightmapUV, input.vertexSH, inputData.normalWS);
#endif
//归一化屏幕uv坐标
inputData.normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(input.positionCS);
//采样shadowMask
inputData.shadowMask = SAMPLE_SHADOWMASK(input.staticLightmapUV);
#if defined(DEBUG_DISPLAY)
#if defined(DYNAMICLIGHTMAP_ON)
inputData.dynamicLightmapUV = input.dynamicLightmapUV.xy;
#endif
#if defined(LIGHTMAP_ON)
inputData.staticLightmapUV = input.staticLightmapUV;
#else
inputData.vertexSH = input.vertexSH;
#endif
#endif
}
// this function is intended to work on Normals (handles non-uniform scale)
// tangentToWorld is the matrix representing the transformation of a normal from tangent to world space
real3 TransformTangentToWorld(float3 normalTS, real3x3 tangentToWorld, bool doNormalize = false)
{
//tangentToWorld矩阵是实际矩阵的转置,故计算时要左乘
// Note matrix is in row major convention with left multiplication as it is build on the fly
real3 result = mul(normalTS, tangentToWorld);
if (doNormalize)
return SafeNormalize(result);
return result;
}
采样全局光照:
// We either sample GI from baked lightmap or from probes.
// If lightmap: sampleData.xy = lightmapUV
// If probe: sampleData.xyz = L2 SH terms
#if defined(LIGHTMAP_ON) && defined(DYNAMICLIGHTMAP_ON) //烘培的光照贴图 和 实时的光照贴图
#define SAMPLE_GI(staticLmName, dynamicLmName, shName, normalWSName) SampleLightmap(staticLmName, dynamicLmName, normalWSName)
#elif defined(DYNAMICLIGHTMAP_ON) //实时的光照贴图
#define SAMPLE_GI(staticLmName, dynamicLmName, shName, normalWSName) SampleLightmap(0, dynamicLmName, normalWSName)
#elif defined(LIGHTMAP_ON) //烘培的光照贴图
#define SAMPLE_GI(staticLmName, shName, normalWSName) SampleLightmap(staticLmName, 0, normalWSName)
#elif defined(PROBE_VOLUMES_L1) || defined(PROBE_VOLUMES_L2) //光照探针
#define SAMPLE_GI(shName, absolutePositionWS, normalWS, viewDir, positionSS) SampleProbeVolumePixel(shName, absolutePositionWS, normalWS, viewDir, positionSS)
#else //逐像素球谐光照
#define SAMPLE_GI(staticLmName, shName, normalWSName) SampleSHPixel(shName, normalWSName)
#endif
// Sample baked and/or realtime lightmap. Non-Direction and Directional if available.
half3 SampleLightmap(float2 staticLightmapUV, float2 dynamicLightmapUV, half3 normalWS)
{
#ifdef UNITY_LIGHTMAP_FULL_HDR
bool encodedLightmap = false;
#else
bool encodedLightmap = true;
#endif
half4 decodeInstructions = half4(LIGHTMAP_HDR_MULTIPLIER, LIGHTMAP_HDR_EXPONENT, 0.0h, 0.0h);
// The shader library sample lightmap functions transform the lightmap uv coords to apply bias and scale.
// However, universal pipeline already transformed those coords in vertex. We pass half4(1, 1, 0, 0) and
// the compiler will optimize the transform away.
half4 transformCoords = half4(1, 1, 0, 0);
float3 diffuseLighting = 0;
//烘培的光照贴图
#if defined(LIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED)
diffuseLighting = SampleDirectionalLightmap(TEXTURE2D_LIGHTMAP_ARGS(LIGHTMAP_NAME, LIGHTMAP_SAMPLER_NAME),
TEXTURE2D_LIGHTMAP_ARGS(LIGHTMAP_INDIRECTION_NAME, LIGHTMAP_SAMPLER_NAME),
LIGHTMAP_SAMPLE_EXTRA_ARGS, transformCoords, normalWS, encodedLightmap, decodeInstructions);
#elif defined(LIGHTMAP_ON)
diffuseLighting = SampleSingleLightmap(TEXTURE2D_LIGHTMAP_ARGS(LIGHTMAP_NAME, LIGHTMAP_SAMPLER_NAME), LIGHTMAP_SAMPLE_EXTRA_ARGS, transformCoords, encodedLightmap, decodeInstructions);
#endif
//实时的光照贴图
#if defined(DYNAMICLIGHTMAP_ON) && defined(DIRLIGHTMAP_COMBINED)
diffuseLighting += SampleDirectionalLightmap(TEXTURE2D_ARGS(unity_DynamicLightmap, samplerunity_DynamicLightmap),
TEXTURE2D_ARGS(unity_DynamicDirectionality, samplerunity_DynamicLightmap),
dynamicLightmapUV, transformCoords, normalWS, false, decodeInstructions);
#elif defined(DYNAMICLIGHTMAP_ON)
diffuseLighting += SampleSingleLightmap(TEXTURE2D_ARGS(unity_DynamicLightmap, samplerunity_DynamicLightmap),
dynamicLightmapUV, transformCoords, false, decodeInstructions);
#endif
return diffuseLighting;
}
获取归一化屏幕空间uv:
float2 GetNormalizedScreenSpaceUV(float2 positionCS)
{
//在片元着色器中,positionCS表示屏幕像素坐标,归一化则除以屏幕宽高
float2 normalizedScreenSpaceUV = positionCS.xy * rcp(GetScaledScreenParams().xy);
TransformNormalizedScreenUV(normalizedScreenSpaceUV); //处理UNITY_UV_STARTS_AT_TOP
return normalizedScreenSpaceUV;
}
应用Decal贴花,修改 SurfaceData,以及 InputData 法线:
void ApplyDecalToSurfaceData(float4 positionCS, inout SurfaceData surfaceData, inout InputData inputData)
{
//SimpleLit没定义 _SPECULAR_SETUP,但实际是使用高光模式,此处应该是有问题
#ifdef _SPECULAR_SETUP
half metallic = 0;
ApplyDecal(positionCS,
surfaceData.albedo,
surfaceData.specular,
inputData.normalWS,
metallic,
surfaceData.occlusion,
surfaceData.smoothness);
#else
half3 specular = 0;
ApplyDecal(positionCS,
surfaceData.albedo,
specular,
inputData.normalWS,
surfaceData.metallic,
surfaceData.occlusion,
surfaceData.smoothness);
#endif
}
void ApplyDecal(float4 positionCS,
inout half3 baseColor,
inout half3 specularColor,
inout half3 normalWS,
inout half metallic,
inout half occlusion,
inout half smoothness)
{
//使用Load读取在指定像素处的纹理值
FETCH_DBUFFER(DBuffer, _DBufferTexture, int2(positionCS.xy));
//读取贴花颜色,法线等其他信息
DecalSurfaceData decalSurfaceData;
DECODE_FROM_DBUFFER(DBuffer, decalSurfaceData);
// using alpha compositing https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch23.html, mean weight of 1 is neutral
// Note: We only test weight (i.e decalSurfaceData.xxx.w is < 1.0) if it can save something
baseColor.xyz = baseColor.xyz * decalSurfaceData.baseColor.w + decalSurfaceData.baseColor.xyz;
#if defined(_DBUFFER_MRT2) || defined(_DBUFFER_MRT3)
// Always test the normal as we can have decompression artifact
if (decalSurfaceData.normalWS.w < 1.0)
{
normalWS.xyz = normalize(normalWS.xyz * decalSurfaceData.normalWS.w + decalSurfaceData.normalWS.xyz);
}
#endif
#if defined(_DBUFFER_MRT3)
#ifdef _SPECULAR_SETUP
if (decalSurfaceData.MAOSAlpha.x < 1.0)
{
half3 decalSpecularColor = ComputeFresnel0((decalSurfaceData.baseColor.w < 1.0) ? decalSurfaceData.baseColor.xyz : half3(1.0, 1.0, 1.0), decalSurfaceData.metallic, DEFAULT_SPECULAR_VALUE);
specularColor = specularColor * decalSurfaceData.MAOSAlpha + decalSpecularColor * (1.0f - decalSurfaceData.MAOSAlpha);
}
#else
metallic = metallic * decalSurfaceData.MAOSAlpha + decalSurfaceData.metallic;
#endif
occlusion = occlusion * decalSurfaceData.MAOSAlpha + decalSurfaceData.occlusion;
smoothness = smoothness * decalSurfaceData.MAOSAlpha + decalSurfaceData.smoothness;
#endif
}
使用BlinnPhong光照模型计算光照影响:
half4 UniversalFragmentBlinnPhong(InputData inputData, SurfaceData surfaceData)
{
#if defined(DEBUG_DISPLAY)
half4 debugColor;
if (CanDebugOverrideOutputColor(inputData, surfaceData, debugColor))
{
return debugColor;
}
#endif
//mesh Light Layer
uint meshRenderingLayers = GetMeshRenderingLayer();
half4 shadowMask = CalculateShadowMask(inputData); //此处重复计算了,用inputData.shadowMask就好
//环境遮挡
AmbientOcclusionFactor aoFactor = CreateAmbientOcclusionFactor(inputData, surfaceData);
//获取主光源信息(颜色,方向,衰减)
Light mainLight = GetMainLight(inputData, shadowMask, aoFactor);
//_MIXED_LIGHTING_SUBTRACTIVE时,inputData.bakedGI得减去主光源
MixRealtimeAndBakedGI(mainLight, inputData.normalWS, inputData.bakedGI, aoFactor);
//最终的烘培光照颜色
inputData.bakedGI *= surfaceData.albedo;
//保存各光源光照结果
LightingData lightingData = CreateLightingData(inputData, surfaceData);
//主光源光照颜色
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(mainLight.layerMask, meshRenderingLayers))
#endif
{
lightingData.mainLightColor += CalculateBlinnPhong(mainLight, inputData, surfaceData);
}
//额外逐像素光照颜色
#if defined(_ADDITIONAL_LIGHTS)
uint pixelLightCount = GetAdditionalLightsCount();
#if USE_FORWARD_PLUS
for (uint lightIndex = 0; lightIndex < min(URP_FP_DIRECTIONAL_LIGHTS_COUNT, MAX_VISIBLE_LIGHTS); lightIndex++)
{
FORWARD_PLUS_SUBTRACTIVE_LIGHT_CHECK
Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor);
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
lightingData.additionalLightsColor += CalculateBlinnPhong(light, inputData, surfaceData);
}
}
#endif
//当 USE_FORWARD_PLUS,pixelLightCount为0,全走上面的处理
LIGHT_LOOP_BEGIN(pixelLightCount)
Light light = GetAdditionalLight(lightIndex, inputData, shadowMask, aoFactor);
#ifdef _LIGHT_LAYERS
if (IsMatchingLightLayer(light.layerMask, meshRenderingLayers))
#endif
{
lightingData.additionalLightsColor += CalculateBlinnPhong(light, inputData, surfaceData);
}
LIGHT_LOOP_END
#endif
//额外顶点光照颜色
#if defined(_ADDITIONAL_LIGHTS_VERTEX)
lightingData.vertexLightingColor += inputData.vertexLighting * surfaceData.albedo;
#endif
return CalculateFinalColor(lightingData, surfaceData.alpha);
}
获取主光源信息:
Light GetMainLight(InputData inputData, half4 shadowMask, AmbientOcclusionFactor aoFactor)
{
Light light = GetMainLight(inputData.shadowCoord, inputData.positionWS, shadowMask);
#if defined(_SCREEN_SPACE_OCCLUSION) && !defined(_SURFACE_TYPE_TRANSPARENT)
if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_AMBIENT_OCCLUSION))
{
light.color *= aoFactor.directAmbientOcclusion;
}
#endif
return light;
}
Light GetMainLight(float4 shadowCoord, float3 positionWS, half4 shadowMask)
{
Light light = GetMainLight();
light.shadowAttenuation = MainLightShadow(shadowCoord, positionWS, shadowMask, _MainLightOcclusionProbes);
#if defined(_LIGHT_COOKIES)
real3 cookieColor = SampleMainLightCookie(positionWS);
light.color *= cookieColor;
#endif
return light;
}
Light GetMainLight()
{
Light light;
light.direction = half3(_MainLightPosition.xyz);
#if USE_FORWARD_PLUS
#if defined(LIGHTMAP_ON) && defined(LIGHTMAP_SHADOW_MIXING)
light.distanceAttenuation = _MainLightColor.a;
#else
light.distanceAttenuation = 1.0;
#endif
#else
light.distanceAttenuation = unity_LightData.z; // unity_LightData.z is 1 when not culled by the culling mask, otherwise 0.
#endif
light.shadowAttenuation = 1.0;
light.color = _MainLightColor.rgb;
light.layerMask = _MainLightLayerMask;
return light;
}
half MainLightShadow(float4 shadowCoord, float3 positionWS, half4 shadowMask, half4 occlusionProbeChannels)
{
//实时阴影
half realtimeShadow = MainLightRealtimeShadow(shadowCoord);
//烘培阴影
#ifdef CALCULATE_BAKED_SHADOWS
half bakedShadow = BakedShadow(shadowMask, occlusionProbeChannels);
#else
half bakedShadow = half(1.0);
#endif
#ifdef MAIN_LIGHT_CALCULATE_SHADOWS
half shadowFade = GetMainLightShadowFade(positionWS);
#else
half shadowFade = half(1.0);
#endif
//混合实时阴影和烘培阴影
return MixRealtimeAndBakedShadows(realtimeShadow, bakedShadow, shadowFade);
}
计算各光源光照结果:
LightingData CreateLightingData(InputData inputData, SurfaceData surfaceData)
{
LightingData lightingData;
lightingData.giColor = inputData.bakedGI;
lightingData.emissionColor = surfaceData.emission;
lightingData.vertexLightingColor = 0;
lightingData.mainLightColor = 0;
lightingData.additionalLightsColor = 0;
return lightingData;
}
计算逐像素光源光照颜色:
half3 CalculateBlinnPhong(Light light, InputData inputData, SurfaceData surfaceData)
{
half3 attenuatedLightColor = light.color * (light.distanceAttenuation * light.shadowAttenuation);
//兰伯特漫反射光照
half3 lightDiffuseColor = LightingLambert(attenuatedLightColor, light.direction, inputData.normalWS);
half3 lightSpecularColor = half3(0,0,0);
#if defined(_SPECGLOSSMAP) || defined(_SPECULAR_COLOR)
half smoothness = exp2(10 * surfaceData.smoothness + 1);
//高光反射
lightSpecularColor += LightingSpecular(attenuatedLightColor, light.direction, inputData.normalWS, inputData.viewDirectionWS, half4(surfaceData.specular, 1), smoothness);
#endif
#if _ALPHAPREMULTIPLY_ON
//alpha预乘,这样就不会影响高光反射
return lightDiffuseColor * surfaceData.albedo * surfaceData.alpha + lightSpecularColor;
#else
return lightDiffuseColor * surfaceData.albedo + lightSpecularColor;
#endif
}
//兰伯特漫反射计算
half3 LightingLambert(half3 lightColor, half3 lightDir, half3 normal)
{
half NdotL = saturate(dot(normal, lightDir));
return lightColor * NdotL;
}
//BlinnPhone高光反射计算
half3 LightingSpecular(half3 lightColor, half3 lightDir, half3 normal, half3 viewDir, half4 specular, half smoothness)
{
float3 halfVec = SafeNormalize(float3(lightDir) + float3(viewDir));
half NdotH = half(saturate(dot(normal, halfVec)));
half modifier = pow(NdotH, smoothness);
half3 specularReflection = specular.rgb * modifier;
return lightColor * specularReflection;
}
获取额外光源信息:
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;
}
Light GetAdditionalLight(uint i, float3 positionWS, half4 shadowMask)
{
#if USE_FORWARD_PLUS
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;
}
// Fills a light struct given a perObjectLightIndex
Light GetAdditionalPerObjectLight(int perObjectLightIndex, float3 positionWS)
{
//读取光源信息
// Abstraction over Light input constants
#if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA
float4 lightPositionWS = _AdditionalLightsBuffer[perObjectLightIndex].position;
half3 color = _AdditionalLightsBuffer[perObjectLightIndex].color.rgb;
half4 distanceAndSpotAttenuation = _AdditionalLightsBuffer[perObjectLightIndex].attenuation;
half4 spotDirection = _AdditionalLightsBuffer[perObjectLightIndex].spotDirection;
uint lightLayerMask = _AdditionalLightsBuffer[perObjectLightIndex].layerMask;
#else
float4 lightPositionWS = _AdditionalLightsPosition[perObjectLightIndex];
half3 color = _AdditionalLightsColor[perObjectLightIndex].rgb;
half4 distanceAndSpotAttenuation = _AdditionalLightsAttenuation[perObjectLightIndex];
half4 spotDirection = _AdditionalLightsSpotDir[perObjectLightIndex];
uint lightLayerMask = asuint(_AdditionalLightsLayerMasks[perObjectLightIndex]);
#endif
// Directional lights store direction in lightPosition.xyz and have .w set to 0.0.
// This way the following code will work for both directional and punctual lights.
float3 lightVector = lightPositionWS.xyz - positionWS * lightPositionWS.w;
float distanceSqr = max(dot(lightVector, lightVector), HALF_MIN);
half3 lightDirection = half3(lightVector * rsqrt(distanceSqr)); //rsqrt 平方根的倒数
// full-float precision required on some platforms
//计算距离衰减
float attenuation = DistanceAttenuation(distanceSqr, distanceAndSpotAttenuation.xy) * AngleAttenuation(spotDirection.xyz, lightDirection, distanceAndSpotAttenuation.zw);
Light light;
light.direction = lightDirection;
light.distanceAttenuation = attenuation;
//阴影缩减后续计算
light.shadowAttenuation = 1.0; // This value can later be overridden in GetAdditionalLight(uint i, float3 positionWS, half4 shadowMask)
light.color = color;
light.layerMask = lightLayerMask;
return light;
}
合并所有的光照结果:
half4 CalculateFinalColor(LightingData lightingData, half alpha)
{
half3 finalColor = CalculateLightingColor(lightingData, 1);
return half4(finalColor, alpha);
}
half3 CalculateLightingColor(LightingData lightingData, half3 albedo)
{
half3 lightingColor = 0;
if (IsOnlyAOLightingFeatureEnabled())
{
return lightingData.giColor; // Contains white + AO
}
if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_GLOBAL_ILLUMINATION))
{
lightingColor += lightingData.giColor;
}
if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_MAIN_LIGHT))
{
lightingColor += lightingData.mainLightColor;
}
if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_ADDITIONAL_LIGHTS))
{
lightingColor += lightingData.additionalLightsColor;
}
if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_VERTEX_LIGHTING))
{
lightingColor += lightingData.vertexLightingColor;
}
lightingColor *= albedo;
if (IsLightingFeatureEnabled(DEBUGLIGHTINGFEATUREFLAGS_EMISSION))
{
lightingColor += lightingData.emissionColor;
}
return lightingColor;
}
用于渲染阴影纹理;
Pass
{
Name "ShadowCaster"
Tags
{
"LightMode" = "ShadowCaster"
}
// -------------------------------------
// Render State Commands
ZWrite On
ZTest LEqual
ColorMask 0
Cull[_Cull]
HLSLPROGRAM
#pragma target 2.0
// -------------------------------------
// Shader Stages
#pragma vertex ShadowPassVertex
#pragma fragment ShadowPassFragment
// -------------------------------------
// Material Keywords
#pragma shader_feature_local _ALPHATEST_ON
#pragma shader_feature_local_fragment _GLOSSINESS_FROM_BASE_ALPHA
// -------------------------------------
// Unity defined keywords
#pragma multi_compile_fragment _ LOD_FADE_CROSSFADE
//--------------------------------------
// GPU Instancing
#pragma multi_compile_instancing
#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
// This is used during shadow map generation to differentiate between directional and punctual light shadows, as they use different formulas to apply Normal Bias
#pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW
// -------------------------------------
// Includes
#include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/ShadowCasterPass.hlsl"
ENDHLSL
}
Varyings ShadowPassVertex(Attributes input)
{
Varyings output;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_TRANSFER_INSTANCE_ID(input, output);
#if defined(_ALPHATEST_ON)
output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap);
#endif
output.positionCS = GetShadowPositionHClip(input);
return output;
}
输入输出结构体:
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
#if defined(_ALPHATEST_ON)
float2 uv : TEXCOORD0;
#endif
float4 positionCS : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
计算齐次裁剪坐标:
float4 GetShadowPositionHClip(Attributes input)
{
float3 positionWS = TransformObjectToWorld(input.positionOS.xyz);
float3 normalWS = TransformObjectToWorldNormal(input.normalOS);
#if _CASTING_PUNCTUAL_LIGHT_SHADOW
float3 lightDirectionWS = normalize(_LightPosition - positionWS);
#else
float3 lightDirectionWS = _LightDirection;
#endif
//世界坐标应用ShowBias,再转化到齐次裁剪空间
float4 positionCS = TransformWorldToHClip(ApplyShadowBias(positionWS, normalWS, lightDirectionWS));
//避免由于应用了ShadowBias导致被错误裁剪掉
#if UNITY_REVERSED_Z
positionCS.z = min(positionCS.z, UNITY_NEAR_CLIP_VALUE);
#else
positionCS.z = max(positionCS.z, UNITY_NEAR_CLIP_VALUE);
#endif
return positionCS;
}
half4 ShadowPassFragment(Varyings input) : SV_TARGET
{
UNITY_SETUP_INSTANCE_ID(input);
#if defined(_ALPHATEST_ON)
//alpha 测试
Alpha(SampleAlbedoAlpha(input.uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap)).a, _BaseColor, _Cutoff);
#endif
#if defined(LOD_FADE_CROSSFADE)
LODFadeCrossFade(input.positionCS);
#endif
return 0; //用于渲染深度值,返回的颜色无关紧要
}
alpha测试:
half Alpha(half albedoAlpha, half4 color, half cutoff)
{
#if !defined(_SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A) && !defined(_GLOSSINESS_FROM_BASE_ALPHA)
half alpha = albedoAlpha * color.a;
#else
half alpha = color.a;
#endif
alpha = AlphaDiscard(alpha, cutoff);
return alpha;
}
用于延迟渲染,渲染几何信息到 GBuffer,此处不阅了;
用于渲染深度纹理,类似ShadowCaster Pass;
Pass
{
Name "DepthOnly"
Tags
{
"LightMode" = "DepthOnly"
}
// -------------------------------------
// Render State Commands
ZWrite On
ColorMask R
Cull[_Cull]
HLSLPROGRAM
#pragma target 2.0
// -------------------------------------
// Shader Stages
#pragma vertex DepthOnlyVertex
#pragma fragment DepthOnlyFragment
// -------------------------------------
// Material Keywords
#pragma shader_feature_local _ALPHATEST_ON
#pragma shader_feature_local_fragment _GLOSSINESS_FROM_BASE_ALPHA
// -------------------------------------
// Unity defined keywords
#pragma multi_compile_fragment _ LOD_FADE_CROSSFADE
//--------------------------------------
// GPU Instancing
#pragma multi_compile_instancing
#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
// -------------------------------------
// Includes
#include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/DepthOnlyPass.hlsl"
ENDHLSL
}
Varyings DepthOnlyVertex(Attributes input)
{
Varyings output = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_TRANSFER_INSTANCE_ID(input, output);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
#if defined(_ALPHATEST_ON)
output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap);
#endif
output.positionCS = TransformObjectToHClip(input.position.xyz);
return output;
}
输入输出结构体:
struct Attributes
{
float4 position : POSITION;
float2 texcoord : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
#if defined(_ALPHATEST_ON)
float2 uv : TEXCOORD0;
#endif
float4 positionCS : SV_POSITION;
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
half DepthOnlyFragment(Varyings input) : SV_TARGET
{
UNITY_SETUP_INSTANCE_ID(input);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
#if defined(_ALPHATEST_ON)
Alpha(SampleAlbedoAlpha(input.uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap)).a, _BaseColor, _Cutoff);
#endif
#if defined(LOD_FADE_CROSSFADE)
LODFadeCrossFade(input.positionCS);
#endif
return input.positionCS.z; //归一化的深度值
}
用于渲染法线纹理 _CameraNormalsTexture;
Pass
{
Name "DepthNormals"
Tags
{
"LightMode" = "DepthNormals"
}
// -------------------------------------
// Render State Commands
ZWrite On
Cull[_Cull]
HLSLPROGRAM
#pragma target 2.0
// -------------------------------------
// Shader Stages
#pragma vertex DepthNormalsVertex
#pragma fragment DepthNormalsFragment
// -------------------------------------
// Material Keywords
#pragma shader_feature_local _NORMALMAP
#pragma shader_feature_local _ALPHATEST_ON
#pragma shader_feature_local_fragment _GLOSSINESS_FROM_BASE_ALPHA
// -------------------------------------
// Unity defined keywords
#pragma multi_compile_fragment _ LOD_FADE_CROSSFADE
// Universal Pipeline keywords
#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RenderingLayers.hlsl"
//--------------------------------------
// GPU Instancing
#pragma multi_compile_instancing
#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
// -------------------------------------
// Includes
#include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitDepthNormalsPass.hlsl"
ENDHLSL
}
Varyings DepthNormalsVertex(Attributes input)
{
Varyings output = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_TRANSFER_INSTANCE_ID(input, output);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
#if defined(REQUIRES_UV_INTERPOLATOR)
output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap);
#endif
output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
//获取顶点在各坐标系下的坐标
VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
//获取切线空间各坐标轴在世界空间下的表示
VertexNormalInputs normalInput = GetVertexNormalInputs(input.normal, input.tangentOS);
#if defined(_NORMALMAP)
half3 viewDirWS = GetWorldSpaceNormalizeViewDir(vertexInput.positionWS);
output.normalWS = half4(normalInput.normalWS, viewDirWS.x);
output.tangentWS = half4(normalInput.tangentWS, viewDirWS.y);
output.bitangentWS = half4(normalInput.bitangentWS, viewDirWS.z);
#else
output.normalWS = half3(NormalizeNormalPerVertex(normalInput.normalWS));
#endif
return output;
}
输入输出结构体:
#if defined(_ALPHATEST_ON) || defined(_NORMALMAP)
#define REQUIRES_UV_INTERPOLATOR
#endif
struct Attributes
{
float4 positionOS : POSITION;
float4 tangentOS : TANGENT;
float2 texcoord : TEXCOORD0;
float3 normal : NORMAL;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
#if defined(REQUIRES_UV_INTERPOLATOR)
float2 uv : TEXCOORD1;
#endif
#ifdef _NORMALMAP
half4 normalWS : TEXCOORD2; // xyz: normal, w: viewDir.x
half4 tangentWS : TEXCOORD3; // xyz: tangent, w: viewDir.y
half4 bitangentWS : TEXCOORD4; // xyz: bitangent, w: viewDir.z
#else
half3 normalWS : TEXCOORD2;
half3 viewDir : TEXCOORD3;
#endif
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
void DepthNormalsFragment(
Varyings input
, out half4 outNormalWS : SV_Target0
#ifdef _WRITE_RENDERING_LAYERS
, out float4 outRenderingLayers : SV_Target1
#endif
)
{
UNITY_SETUP_INSTANCE_ID(input);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
#if defined(_ALPHATEST_ON)
Alpha(SampleAlbedoAlpha(input.uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap)).a, _BaseColor, _Cutoff);
#endif
#if defined(LOD_FADE_CROSSFADE)
LODFadeCrossFade(input.positionCS);
#endif
#if defined(_GBUFFER_NORMALS_OCT) //延迟渲染精确Normal
float3 normalWS = normalize(input.normalWS);
float2 octNormalWS = PackNormalOctQuadEncode(normalWS); // values between [-1, +1], must use fp32 on some platforms
float2 remappedOctNormalWS = saturate(octNormalWS * 0.5 + 0.5); // values between [ 0, 1]
half3 packedNormalWS = PackFloat2To888(remappedOctNormalWS); // values between [ 0, 1]
outNormalWS = half4(packedNormalWS, 0.0);
#else
#if defined(_NORMALMAP) //定义了切线空间的法线贴图时
//采样切线空间的法线
half3 normalTS = SampleNormal(input.uv, TEXTURE2D_ARGS(_BumpMap, sampler_BumpMap));
//将切线空间的法线转化到世界空间
half3 normalWS = TransformTangentToWorld(normalTS, half3x3(input.tangentWS.xyz, input.bitangentWS.xyz, input.normalWS.xyz));
#else
half3 normalWS = input.normalWS;
#endif
normalWS = NormalizeNormalPerPixel(normalWS);
outNormalWS = half4(normalWS, 0.0); //输出法线到渲染目标
#endif
#ifdef _WRITE_RENDERING_LAYERS
uint renderingLayers = GetMeshRenderingLayer();
outRenderingLayers = float4(EncodeMeshRenderingLayer(renderingLayers), 0, 0, 0);
#endif
}
用于编辑器下烘培光照贴图;
Pass
{
Name "Meta"
Tags
{
"LightMode" = "Meta"
}
// -------------------------------------
// Render State Commands
Cull Off
HLSLPROGRAM
#pragma target 2.0
// -------------------------------------
// Shader Stages
#pragma vertex UniversalVertexMeta
#pragma fragment UniversalFragmentMetaSimple
// -------------------------------------
// Material Keywords
#pragma shader_feature_local_fragment _EMISSION
#pragma shader_feature_local_fragment _SPECGLOSSMAP
#pragma shader_feature EDITOR_VISUALIZATION
// -------------------------------------
// Includes
#include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl"
#include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitMetaPass.hlsl"
ENDHLSL
}
Varyings UniversalVertexMeta(Attributes input)
{
Varyings output = (Varyings)0;
//顶点转化到齐次裁剪空间
output.positionCS = UnityMetaVertexPosition(input.positionOS.xyz, input.uv1, input.uv2);
output.uv = TRANSFORM_TEX(input.uv0, _BaseMap);
#ifdef EDITOR_VISUALIZATION
UnityEditorVizData(input.positionOS.xyz, input.uv0, input.uv1, input.uv2, output.VizUV, output.LightCoord);
#endif
return output;
}
输入输出结构体:
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
float2 uv0 : TEXCOORD0;
float2 uv1 : TEXCOORD1;
float2 uv2 : TEXCOORD2;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float2 uv : TEXCOORD0;
#ifdef EDITOR_VISUALIZATION
float2 VizUV : TEXCOORD1;
float4 LightCoord : TEXCOORD2;
#endif
};
顶点转化到齐次裁剪空间:
float4 UnityMetaVertexPosition(float3 vertex, float2 uv1, float2 uv2, float4 lightmapST, float4 dynlightmapST)
{
#ifndef EDITOR_VISUALIZATION
if (unity_MetaVertexControl.x)
{
vertex.xy = uv1 * lightmapST.xy + lightmapST.zw;
// OpenGL right now needs to actually use incoming vertex position,
// so use it in a very dummy way
vertex.z = vertex.z > 0 ? REAL_MIN : 0.0f;
}
if (unity_MetaVertexControl.y)
{
vertex.xy = uv2 * dynlightmapST.xy + dynlightmapST.zw;
// OpenGL right now needs to actually use incoming vertex position,
// so use it in a very dummy way
vertex.z = vertex.z > 0 ? REAL_MIN : 0.0f;
}
return TransformWorldToHClip(vertex);
#else
return TransformObjectToHClip(vertex);
#endif
}
half4 UniversalFragmentMeta(Varyings fragIn, MetaInput metaInput)
{
#ifdef EDITOR_VISUALIZATION
metaInput.VizUV = fragIn.VizUV;
metaInput.LightCoord = fragIn.LightCoord;
#endif
return UnityMetaFragment(metaInput); //返回编辑器用的显示数据
}
#endif
half4 UnityMetaFragment (UnityMetaInput IN)
{
half4 res = 0;
#ifndef EDITOR_VISUALIZATION
if (unity_MetaFragmentControl.x)
{
res = half4(IN.Albedo,1);
// Apply Albedo Boost from LightmapSettings.
res.rgb = clamp(pow(abs(res.rgb), saturate(unity_OneOverOutputBoost)), 0, unity_MaxOutputValue);
}
if (unity_MetaFragmentControl.y)
{
half3 emission;
if (unity_UseLinearSpace)
emission = IN.Emission;
else
emission = Gamma20ToLinear(IN.Emission);
res = half4(emission, 1.0);
}
#else
// SRPs don't support EDITORVIZ_PBR_VALIDATION_ALBEDO or EDITORVIZ_PBR_VALIDATION_METALSPECULAR
if (unity_VisualizationMode == EDITORVIZ_TEXTURE)
{
res = tex2D(unity_EditorViz_Texture, IN.VizUV);
if (unity_EditorViz_Decode_HDR.x > 0)
res = half4(DecodeHDREnvironment(res, unity_EditorViz_Decode_HDR), 1);
if (unity_EditorViz_ConvertToLinearSpace)
res.rgb = LinearToGamma20(res.rgb);
res *= unity_EditorViz_ColorMul;
res += unity_EditorViz_ColorAdd;
res *= exp2(unity_EditorViz_Exposure);
}
else if (unity_VisualizationMode == EDITORVIZ_SHOWLIGHTMASK)
{
float result = dot(unity_EditorViz_ChannelSelect, tex2D(unity_EditorViz_Texture, IN.VizUV).rgba);
if (result == 0)
discard;
float atten = 1;
if (unity_EditorViz_LightType == 0)
{
// directional: no attenuation
}
else if (unity_EditorViz_LightType == 1)
{
// point
atten = tex2D(unity_EditorViz_LightTexture, dot(IN.LightCoord.xyz, IN.LightCoord.xyz).xx).r;
}
else if (unity_EditorViz_LightType == 2)
{
// spot
atten = tex2D(unity_EditorViz_LightTexture, dot(IN.LightCoord.xyz, IN.LightCoord.xyz).xx).r;
float cookie = tex2D(unity_EditorViz_LightTextureB, IN.LightCoord.xy / max(IN.LightCoord.w, 0.0001) + 0.5).w;
atten *= (IN.LightCoord.z > 0) * cookie;
}
clip(atten - 0.001f);
res = float4(unity_EditorViz_Color.xyz * result, unity_EditorViz_Color.w);
}
#endif // EDITOR_VISUALIZATION
return res;
}
2D渲染使用,此处不阅了;
用于运动矢量渲染,即前后两帧 ndc坐标 的变化;
Pass
{
Name "MotionVectors"
Tags { "LightMode" = "MotionVectors" }
ColorMask RG
HLSLPROGRAM
#pragma shader_feature_local _ALPHATEST_ON
#pragma multi_compile_fragment _ LOD_FADE_CROSSFADE
#pragma shader_feature_local_vertex _ADD_PRECOMPUTED_VELOCITY
#include "Packages/com.unity.render-pipelines.universal/Shaders/SimpleLitInput.hlsl"
#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ObjectMotionVectors.hlsl"
ENDHLSL
}
Varyings vert(Attributes input)
{
Varyings output = (Varyings)0;
UNITY_SETUP_INSTANCE_ID(input);
UNITY_TRANSFER_INSTANCE_ID(input, output);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);
//获取顶点在各坐标系下的坐标
const VertexPositionInputs vertexInput = GetVertexPositionInputs(input.position.xyz);
#if defined(_ALPHATEST_ON)
output.uv = TRANSFORM_TEX(input.uv, _BaseMap);
#endif
// Jittered. Match the frame.
output.positionCS = vertexInput.positionCS;
output.positionCSNoJitter = mul(_NonJitteredViewProjMatrix, mul(UNITY_MATRIX_M, input.position));
float4 prevPos = (unity_MotionVectorsParams.x == 1) ? float4(input.positionOld, 1) : input.position;
#if _ADD_PRECOMPUTED_VELOCITY
prevPos = prevPos - float4(input.alembicMotionVector, 0);
#endif
output.previousPositionCSNoJitter = mul(_PrevViewProjMatrix, mul(UNITY_PREV_MATRIX_M, prevPos));
ApplyMotionVectorZBias(output.positionCS);
return output;
}
输入输出结构体:
// Structs
struct Attributes
{
float4 position : POSITION;
#if _ALPHATEST_ON
float2 uv : TEXCOORD0;
#endif
float3 positionOld : TEXCOORD4;
#if _ADD_PRECOMPUTED_VELOCITY
float3 alembicMotionVector : TEXCOORD5;
#endif
UNITY_VERTEX_INPUT_INSTANCE_ID
};
struct Varyings
{
float4 positionCS : SV_POSITION;
float4 positionCSNoJitter : POSITION_CS_NO_JITTER;
float4 previousPositionCSNoJitter : PREV_POSITION_CS_NO_JITTER;
#if _ALPHATEST_ON
float2 uv : TEXCOORD0;
#endif
UNITY_VERTEX_INPUT_INSTANCE_ID
UNITY_VERTEX_OUTPUT_STEREO
};
float4 frag(Varyings input) : SV_Target
{
UNITY_SETUP_INSTANCE_ID(input);
UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);
#if defined(_ALPHATEST_ON)
Alpha(SampleAlbedoAlpha(input.uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap)).a, _BaseColor, _Cutoff);
#endif
#if defined(LOD_FADE_CROSSFADE)
LODFadeCrossFade(input.positionCS);
#endif
return float4(CalcNdcMotionVectorFromCsPositions(input.positionCSNoJitter, input.previousPositionCSNoJitter), 0, 0);
}
计算 ndc 变化矢量:
float2 CalcNdcMotionVectorFromCsPositions(float4 posCS, float4 prevPosCS)
{
// Note: unity_MotionVectorsParams.y is 0 is forceNoMotion is enabled
bool forceNoMotion = unity_MotionVectorsParams.y == 0.0;
if (forceNoMotion)
return float2(0.0, 0.0);
// Non-uniform raster needs to keep the posNDC values in float to avoid additional conversions
// since uv remap functions use floats
//除以w来归一化
float2 posNDC = posCS.xy * rcp(posCS.w);
float2 prevPosNDC = prevPosCS.xy * rcp(prevPosCS.w);
float2 velocity;
#if defined(SUPPORTS_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
UNITY_BRANCH if (_FOVEATED_RENDERING_NON_UNIFORM_RASTER)
{
// Convert velocity from NDC space (-1..1) to screen UV 0..1 space since FoveatedRendering remap needs that range.
float2 posUV = RemapFoveatedRenderingResolve(posNDC * 0.5 + 0.5);
float2 prevPosUV = RemapFoveatedRenderingPrevFrameLinearToNonUniform(prevPosNDC * 0.5 + 0.5);
// Calculate forward velocity
velocity = (posUV - prevPosUV);
#if UNITY_UV_STARTS_AT_TOP
velocity.y = -velocity.y;
#endif
}
else
#endif
{
// Calculate forward velocity
velocity = (posNDC.xy - prevPosNDC.xy);
#if UNITY_UV_STARTS_AT_TOP
velocity.y = -velocity.y;
#endif
// Convert velocity from NDC space (-1..1) to UV 0..1 space
// Note: It doesn't mean we don't have negative values, we store negative or positive offset in UV space.
// Note: ((posNDC * 0.5 + 0.5) - (prevPosNDC * 0.5 + 0.5)) = (velocity * 0.5)
velocity.xy *= 0.5;
}
return velocity;
}