## 各种定义 根据是否开启天使环渲染与`_MAIN_LIGHT_SHADOWS`来定义顶点输入与输出格式。 ```c# struct VertexInput { float4 vertex : POSITION; float3 normal : NORMAL; float4 tangent : TANGENT; float2 texcoord0 : TEXCOORD0; #ifdef _IS_ANGELRING_OFF float2 lightmapUV : TEXCOORD1; #elif _IS_ANGELRING_ON float2 texcoord1 : TEXCOORD1; float2 lightmapUV : TEXCOORD2; #endif UNITY_VERTEX_INPUT_INSTANCE_ID }; struct VertexOutput { float4 pos : SV_POSITION; float2 uv0 : TEXCOORD0; //v.2.0.4 #ifdef _IS_ANGELRING_OFF float4 posWorld : TEXCOORD1; float3 normalDir : TEXCOORD2; float3 tangentDir : TEXCOORD3; float3 bitangentDir : TEXCOORD4; //v.2.0.7 float mirrorFlag : TEXCOORD5; DECLARE_LIGHTMAP_OR_SH(lightmapUV, vertexSH, 6); #if defined(_ADDITIONAL_LIGHTS_VERTEX) || (VERSION_LOWER(12, 0)) half4 fogFactorAndVertexLight : TEXCOORD7; // x: fogFactor, yzw: vertex light #else half fogFactor : TEXCOORD7; #endif # ifndef _MAIN_LIGHT_SHADOWS float4 positionCS : TEXCOORD8; int mainLightID : TEXCOORD9; # else float4 shadowCoord : TEXCOORD8; float4 positionCS : TEXCOORD9; int mainLightID : TEXCOORD10; # endif UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO // #elif _IS_ANGELRING_ON float2 uv1 : TEXCOORD1; float4 posWorld : TEXCOORD2; float3 normalDir : TEXCOORD3; float3 tangentDir : TEXCOORD4; float3 bitangentDir : TEXCOORD5; //v.2.0.7 float mirrorFlag : TEXCOORD6; DECLARE_LIGHTMAP_OR_SH(lightmapUV, vertexSH, 7); #if defined(_ADDITIONAL_LIGHTS_VERTEX) || (VERSION_LOWER(12, 0)) half4 fogFactorAndVertexLight : TEXCOORD8; // x: fogFactor, yzw: vertex light #else half fogFactor : TEXCOORD8; // x: fogFactor, yzw: vertex light #endif # ifndef _MAIN_LIGHT_SHADOWS float4 positionCS : TEXCOORD9; int mainLightID : TEXCOORD10; # else float4 shadowCoord : TEXCOORD9; float4 positionCS : TEXCOORD10; int mainLightID : TEXCOORD11; # endif UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO #else LIGHTING_COORDS(7,8) UNITY_FOG_COORDS(9) #endif // }; //灯光数据 struct UtsLight { float3 direction; float3 color; float distanceAttenuation; real shadowAttenuation; int type; }; ``` 根据宏定义宏:`_ADDITIONAL_LIGHTS`=>`REQUIRES_WORLD_SPACE_POS_INTERPOLATOR`,`_MAIN_LIGHT_SHADOWS`=>`REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR`。以及一些函数: ```c# // RaytracedHardShadow // This is global texture. what to do with SRP Batcher. #define UNITY_PROJ_COORD(a) a #define UNITY_SAMPLE_SCREEN_SHADOW(tex, uv) tex2Dproj( tex, UNITY_PROJ_COORD(uv) ).r #define TEXTURE2D_SAMPLER2D(textureName, samplerName) Texture2D textureName; SamplerState samplerName TEXTURE2D_SAMPLER2D(_RaytracedHardShadow, sampler_RaytracedHardShadow); float4 _RaytracedHardShadow_TexelSize; //function to rotate the UV: RotateUV() //float2 rotatedUV = RotateUV(i.uv0, (_angular_Verocity*3.141592654), float2(0.5, 0.5), _Time.g); float2 RotateUV(float2 _uv, float _radian, float2 _piv, float _time) { float RotateUV_ang = _radian; float RotateUV_cos = cos(_time*RotateUV_ang); float RotateUV_sin = sin(_time*RotateUV_ang); return (mul(_uv - _piv, float2x2( RotateUV_cos, -RotateUV_sin, RotateUV_sin, RotateUV_cos)) + _piv); } // fixed3 DecodeLightProbe( fixed3 N ){ return ShadeSH9(float4(N,1)); } inline void InitializeStandardLitSurfaceDataUTS(float2 uv, out SurfaceData outSurfaceData) { outSurfaceData = (SurfaceData)0; // half4 albedoAlpha = SampleAlbedoAlpha(uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap)); half4 albedoAlpha = half4(1.0,1.0,1.0,1.0); outSurfaceData.alpha = Alpha(albedoAlpha.a, _BaseColor, _Cutoff); half4 specGloss = SampleMetallicSpecGloss(uv, albedoAlpha.a); outSurfaceData.albedo = albedoAlpha.rgb * _BaseColor.rgb; #if _SPECULAR_SETUP outSurfaceData.metallic = 1.0h; outSurfaceData.specular = specGloss.rgb; #else outSurfaceData.metallic = specGloss.r; outSurfaceData.specular = half3(0.0h, 0.0h, 0.0h); #endif outSurfaceData.smoothness = specGloss.a; outSurfaceData.normalTS = SampleNormal(uv, TEXTURE2D_ARGS(_BumpMap, sampler_BumpMap), _BumpScale); outSurfaceData.occlusion = SampleOcclusion(uv); outSurfaceData.emission = SampleEmission(uv, _EmissionColor.rgb, TEXTURE2D_ARGS(_EmissionMap, sampler_EmissionMap)); } half3 GlobalIlluminationUTS(BRDFData brdfData, half3 bakedGI, half occlusion, half3 normalWS, half3 viewDirectionWS) { half3 reflectVector = reflect(-viewDirectionWS, normalWS); half fresnelTerm = Pow4(1.0 - saturate(dot(normalWS, viewDirectionWS))); half3 indirectDiffuse = bakedGI * occlusion; half3 indirectSpecular = GlossyEnvironmentReflection(reflectVector, brdfData.perceptualRoughness, occlusion); return EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm); } ``` ## 顶点着色器 计算 - 顶点法线、切线、次级法线 - 裁剪过的顶点世界坐标 - 使用`ComputeFogFactor`(FOG_LINEAR、FOG_EXP与FOG_EXP2)计算`fogFactorAndVertexLight`或者`fogFactor`。 - shadowCoord - mainLightID 如果开启天使环渲染,则增加一个TexCoord1为天使环UV坐标。 ```c# VertexOutput vert (VertexInput v) { VertexOutput o = (VertexOutput)0; UNITY_SETUP_INSTANCE_ID(v); UNITY_TRANSFER_INSTANCE_ID(v, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); o.uv0 = v.texcoord0; //v.2.0.4 #ifdef _IS_ANGELRING_OFF // #elif _IS_ANGELRING_ON o.uv1 = v.texcoord1; #endif o.normalDir = UnityObjectToWorldNormal(v.normal); o.tangentDir = normalize( mul( unity_ObjectToWorld, float4( v.tangent.xyz, 0.0 ) ).xyz ); o.bitangentDir = normalize(cross(o.normalDir, o.tangentDir) * v.tangent.w); o.posWorld = mul(unity_ObjectToWorld, v.vertex); o.pos = UnityObjectToClipPos( v.vertex ); //v.2.0.7 Detection of the inside the mirror (right or left-handed) o.mirrorFlag = -1 then "inside the mirror". float3 crossFwd = cross(UNITY_MATRIX_V[0].xyz, UNITY_MATRIX_V[1].xyz); o.mirrorFlag = dot(crossFwd, UNITY_MATRIX_V[2].xyz) < 0 ? 1 : -1; // float3 positionWS = TransformObjectToWorld(v.vertex.xyz); float4 positionCS = TransformWorldToHClip(positionWS); half3 vertexLight = VertexLighting(o.posWorld.xyz, o.normalDir); half fogFactor = ComputeFogFactor(positionCS.z); OUTPUT_LIGHTMAP_UV(v.lightmapUV, unity_LightmapST, o.lightmapUV); OUTPUT_SH(o.normalDir.xyz, o.vertexSH); # if defined(_ADDITIONAL_LIGHTS_VERTEX) || (VERSION_LOWER(12, 0)) o.fogFactorAndVertexLight = half4(fogFactor, vertexLight); #else o.fogFactor = fogFactor; #endif o.positionCS = positionCS; #if defined(_MAIN_LIGHT_SHADOWS) && !defined(_RECEIVE_SHADOWS_OFF) #if SHADOWS_SCREEN o.shadowCoord = ComputeScreenPos(positionCS); #else o.shadowCoord = TransformWorldToShadowCoord(o.posWorld.xyz); #endif o.mainLightID = DetermineUTS_MainLightIndex(o.posWorld.xyz, o.shadowCoord, positionCS); #else o.mainLightID = DetermineUTS_MainLightIndex(o.posWorld.xyz, 0, positionCS); #endif return o; } ``` ## 像素着色器 UTS的着色模式有两种,分别封装在`UniversalToonBodyDoubleShadeWithFeather.hlsl`与`UniversalToonBodyShadingGradeMap`中。 ```c# float4 frag(VertexOutput i, fixed facing : VFACE) : SV_TARGET { #if defined(_SHADINGGRADEMAP) return fragShadingGradeMap(i, facing); #else return fragDoubleShadeFeather(i, facing); #endif } ``` ## 透明与裁剪 `ClippingMode`设置为非off后才会开启裁剪选项。拥有以下功能: - 裁剪Mask反转 - 使用BaseMap的Alpha通道作为Mask - 裁剪强度与透明度强度 这个功能通常用来除了头发之类的透明物体。 ## 完整代码 ```c# #if (SHADER_LIBRARY_VERSION_MAJOR ==7 && SHADER_LIBRARY_VERSION_MINOR >= 3) || (SHADER_LIBRARY_VERSION_MAJOR >= 8) # ifdef _ADDITIONAL_LIGHTS # ifndef REQUIRES_WORLD_SPACE_POS_INTERPOLATOR # define REQUIRES_WORLD_SPACE_POS_INTERPOLATOR # endif # endif #else # ifdef _MAIN_LIGHT_SHADOWS //# if !defined(_MAIN_LIGHT_SHADOWS_CASCADE) # ifndef REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR # define REQUIRES_VERTEX_SHADOW_COORD_INTERPOLATOR # endif //# endif # endif # ifdef _ADDITIONAL_LIGHTS # ifndef REQUIRES_WORLD_SPACE_POS_INTERPOLATOR # define REQUIRES_WORLD_SPACE_POS_INTERPOLATOR # endif # endif #endif // RaytracedHardShadow // This is global texture. what to do with SRP Batcher. #define UNITY_PROJ_COORD(a) a #define UNITY_SAMPLE_SCREEN_SHADOW(tex, uv) tex2Dproj( tex, UNITY_PROJ_COORD(uv) ).r #define TEXTURE2D_SAMPLER2D(textureName, samplerName) Texture2D textureName; SamplerState samplerName TEXTURE2D_SAMPLER2D(_RaytracedHardShadow, sampler_RaytracedHardShadow); float4 _RaytracedHardShadow_TexelSize; //function to rotate the UV: RotateUV() //float2 rotatedUV = RotateUV(i.uv0, (_angular_Verocity*3.141592654), float2(0.5, 0.5), _Time.g); float2 RotateUV(float2 _uv, float _radian, float2 _piv, float _time) { float RotateUV_ang = _radian; float RotateUV_cos = cos(_time*RotateUV_ang); float RotateUV_sin = sin(_time*RotateUV_ang); return (mul(_uv - _piv, float2x2( RotateUV_cos, -RotateUV_sin, RotateUV_sin, RotateUV_cos)) + _piv); } // fixed3 DecodeLightProbe( fixed3 N ){ return ShadeSH9(float4(N,1)); } inline void InitializeStandardLitSurfaceDataUTS(float2 uv, out SurfaceData outSurfaceData) { outSurfaceData = (SurfaceData)0; // half4 albedoAlpha = SampleAlbedoAlpha(uv, TEXTURE2D_ARGS(_BaseMap, sampler_BaseMap)); half4 albedoAlpha = half4(1.0,1.0,1.0,1.0); outSurfaceData.alpha = Alpha(albedoAlpha.a, _BaseColor, _Cutoff); half4 specGloss = SampleMetallicSpecGloss(uv, albedoAlpha.a); outSurfaceData.albedo = albedoAlpha.rgb * _BaseColor.rgb; #if _SPECULAR_SETUP outSurfaceData.metallic = 1.0h; outSurfaceData.specular = specGloss.rgb; #else outSurfaceData.metallic = specGloss.r; outSurfaceData.specular = half3(0.0h, 0.0h, 0.0h); #endif outSurfaceData.smoothness = specGloss.a; outSurfaceData.normalTS = SampleNormal(uv, TEXTURE2D_ARGS(_BumpMap, sampler_BumpMap), _BumpScale); outSurfaceData.occlusion = SampleOcclusion(uv); outSurfaceData.emission = SampleEmission(uv, _EmissionColor.rgb, TEXTURE2D_ARGS(_EmissionMap, sampler_EmissionMap)); } half3 GlobalIlluminationUTS(BRDFData brdfData, half3 bakedGI, half occlusion, half3 normalWS, half3 viewDirectionWS) { half3 reflectVector = reflect(-viewDirectionWS, normalWS); half fresnelTerm = Pow4(1.0 - saturate(dot(normalWS, viewDirectionWS))); half3 indirectDiffuse = bakedGI * occlusion; half3 indirectSpecular = GlossyEnvironmentReflection(reflectVector, brdfData.perceptualRoughness, occlusion); return EnvironmentBRDF(brdfData, indirectDiffuse, indirectSpecular, fresnelTerm); } struct VertexInput { float4 vertex : POSITION; float3 normal : NORMAL; float4 tangent : TANGENT; float2 texcoord0 : TEXCOORD0; #ifdef _IS_ANGELRING_OFF float2 lightmapUV : TEXCOORD1; #elif _IS_ANGELRING_ON float2 texcoord1 : TEXCOORD1; float2 lightmapUV : TEXCOORD2; #endif UNITY_VERTEX_INPUT_INSTANCE_ID }; struct VertexOutput { float4 pos : SV_POSITION; float2 uv0 : TEXCOORD0; //v.2.0.4 #ifdef _IS_ANGELRING_OFF float4 posWorld : TEXCOORD1; float3 normalDir : TEXCOORD2; float3 tangentDir : TEXCOORD3; float3 bitangentDir : TEXCOORD4; //v.2.0.7 float mirrorFlag : TEXCOORD5; DECLARE_LIGHTMAP_OR_SH(lightmapUV, vertexSH, 6); #if defined(_ADDITIONAL_LIGHTS_VERTEX) || (VERSION_LOWER(12, 0)) half4 fogFactorAndVertexLight : TEXCOORD7; // x: fogFactor, yzw: vertex light #else half fogFactor : TEXCOORD7; #endif # ifndef _MAIN_LIGHT_SHADOWS float4 positionCS : TEXCOORD8; int mainLightID : TEXCOORD9; # else float4 shadowCoord : TEXCOORD8; float4 positionCS : TEXCOORD9; int mainLightID : TEXCOORD10; # endif UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO // #elif _IS_ANGELRING_ON float2 uv1 : TEXCOORD1; float4 posWorld : TEXCOORD2; float3 normalDir : TEXCOORD3; float3 tangentDir : TEXCOORD4; float3 bitangentDir : TEXCOORD5; //v.2.0.7 float mirrorFlag : TEXCOORD6; DECLARE_LIGHTMAP_OR_SH(lightmapUV, vertexSH, 7); #if defined(_ADDITIONAL_LIGHTS_VERTEX) || (VERSION_LOWER(12, 0)) half4 fogFactorAndVertexLight : TEXCOORD8; // x: fogFactor, yzw: vertex light #else half fogFactor : TEXCOORD8; // x: fogFactor, yzw: vertex light #endif # ifndef _MAIN_LIGHT_SHADOWS float4 positionCS : TEXCOORD9; int mainLightID : TEXCOORD10; # else float4 shadowCoord : TEXCOORD9; float4 positionCS : TEXCOORD10; int mainLightID : TEXCOORD11; # endif UNITY_VERTEX_INPUT_INSTANCE_ID UNITY_VERTEX_OUTPUT_STEREO #else LIGHTING_COORDS(7,8) UNITY_FOG_COORDS(9) #endif // }; // Abstraction over Light shading data. struct UtsLight { float3 direction; float3 color; float distanceAttenuation; real shadowAttenuation; int type; }; /////////////////////////////////////////////////////////////////////////////// // Light Abstraction // ///////////////////////////////////////////////////////////////////////////// real MainLightRealtimeShadowUTS(float4 shadowCoord, float4 positionCS) { #if !defined(MAIN_LIGHT_CALCULATE_SHADOWS) return 1.0h; #endif ShadowSamplingData shadowSamplingData = GetMainLightShadowSamplingData(); half4 shadowParams = GetMainLightShadowParams(); #if defined(UTS_USE_RAYTRACING_SHADOW) float w = (positionCS.w == 0) ? 0.00001 : positionCS.w; float4 screenPos = ComputeScreenPos(positionCS/ w); return SAMPLE_TEXTURE2D(_RaytracedHardShadow, sampler_RaytracedHardShadow, screenPos); #endif return SampleShadowmap(TEXTURE2D_ARGS(_MainLightShadowmapTexture, sampler_MainLightShadowmapTexture), shadowCoord, shadowSamplingData, shadowParams, false); } real AdditionalLightRealtimeShadowUTS(int lightIndex, float3 positionWS, float4 positionCS) { #if defined(UTS_USE_RAYTRACING_SHADOW) float w = (positionCS.w == 0) ? 0.00001 : positionCS.w; float4 screenPos = ComputeScreenPos(positionCS / w); return SAMPLE_TEXTURE2D(_RaytracedHardShadow, sampler_RaytracedHardShadow, screenPos); #endif // UTS_USE_RAYTRACING_SHADOW #if !defined(ADDITIONAL_LIGHT_CALCULATE_SHADOWS) return 1.0h; #endif ShadowSamplingData shadowSamplingData = GetAdditionalLightShadowSamplingData(); #if USE_STRUCTURED_BUFFER_FOR_LIGHT_DATA lightIndex = _AdditionalShadowsIndices[lightIndex]; // We have to branch here as otherwise we would sample buffer with lightIndex == -1. // However this should be ok for platforms that store light in SSBO. UNITY_BRANCH if (lightIndex < 0) return 1.0; float4 shadowCoord = mul(_AdditionalShadowsBuffer[lightIndex].worldToShadowMatrix, float4(positionWS, 1.0)); #else float4 shadowCoord = mul(_AdditionalLightsWorldToShadow[lightIndex], float4(positionWS, 1.0)); #endif half4 shadowParams = GetAdditionalLightShadowParams(lightIndex); return SampleShadowmap(TEXTURE2D_ARGS(_AdditionalLightsShadowmapTexture, sampler_AdditionalLightsShadowmapTexture), shadowCoord, shadowSamplingData, shadowParams, true); } UtsLight GetUrpMainUtsLight() { UtsLight light; light.direction = _MainLightPosition.xyz; // unity_LightData.z is 1 when not culled by the culling mask, otherwise 0. light.distanceAttenuation = unity_LightData.z; #if defined(LIGHTMAP_ON) || defined(_MIXED_LIGHTING_SUBTRACTIVE) // unity_ProbesOcclusion.x is the mixed light probe occlusion data light.distanceAttenuation *= unity_ProbesOcclusion.x; #endif light.shadowAttenuation = 1.0; light.color = _MainLightColor.rgb; light.type = _MainLightPosition.w; return light; } UtsLight GetUrpMainUtsLight(float4 shadowCoord, float4 positionCS) { UtsLight light = GetUrpMainUtsLight(); light.shadowAttenuation = MainLightRealtimeShadowUTS(shadowCoord, positionCS); return light; } // Fills a light struct given a perObjectLightIndex UtsLight GetAdditionalPerObjectUtsLight(int perObjectLightIndex, float3 positionWS,float4 positionCS) { // 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; half4 lightOcclusionProbeInfo = _AdditionalLightsBuffer[perObjectLightIndex].occlusionProbeChannels; #else float4 lightPositionWS = _AdditionalLightsPosition[perObjectLightIndex]; half3 color = _AdditionalLightsColor[perObjectLightIndex].rgb; half4 distanceAndSpotAttenuation = _AdditionalLightsAttenuation[perObjectLightIndex]; half4 spotDirection = _AdditionalLightsSpotDir[perObjectLightIndex]; half4 lightOcclusionProbeInfo = _AdditionalLightsOcclusionProbes[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)); half attenuation = DistanceAttenuation(distanceSqr, distanceAndSpotAttenuation.xy) * AngleAttenuation(spotDirection.xyz, lightDirection, distanceAndSpotAttenuation.zw); UtsLight light; light.direction = lightDirection; light.distanceAttenuation = attenuation; light.shadowAttenuation = AdditionalLightRealtimeShadowUTS(perObjectLightIndex, positionWS, positionCS); light.color = color; light.type = lightPositionWS.w; // In case we're using light probes, we can sample the attenuation from the `unity_ProbesOcclusion` #if defined(LIGHTMAP_ON) || defined(_MIXED_LIGHTING_SUBTRACTIVE) // First find the probe channel from the light. // Then sample `unity_ProbesOcclusion` for the baked occlusion. // If the light is not baked, the channel is -1, and we need to apply no occlusion. // probeChannel is the index in 'unity_ProbesOcclusion' that holds the proper occlusion value. int probeChannel = lightOcclusionProbeInfo.x; // lightProbeContribution is set to 0 if we are indeed using a probe, otherwise set to 1. half lightProbeContribution = lightOcclusionProbeInfo.y; half probeOcclusionValue = unity_ProbesOcclusion[probeChannel]; light.distanceAttenuation *= max(probeOcclusionValue, lightProbeContribution); #endif return light; } // Fills a light struct given a loop i index. This will convert the i // index to a perObjectLightIndex UtsLight GetAdditionalUtsLight(uint i, float3 positionWS,float4 positionCS) { int perObjectLightIndex = GetPerObjectLightIndex(i); return GetAdditionalPerObjectUtsLight(perObjectLightIndex, positionWS, positionCS); } half3 GetLightColor(UtsLight light) { return light.color * light.distanceAttenuation; } #define INIT_UTSLIGHT(utslight) \ utslight.direction = 0; \ utslight.color = 0; \ utslight.distanceAttenuation = 0; \ utslight.shadowAttenuation = 0; \ utslight.type = 0 int DetermineUTS_MainLightIndex(float3 posW, float4 shadowCoord, float4 positionCS) { UtsLight mainLight; INIT_UTSLIGHT(mainLight); int mainLightIndex = MAINLIGHT_NOT_FOUND; UtsLight nextLight = GetUrpMainUtsLight(shadowCoord, positionCS); if (nextLight.distanceAttenuation > mainLight.distanceAttenuation && nextLight.type == 0) { mainLight = nextLight; mainLightIndex = MAINLIGHT_IS_MAINLIGHT; } int lightCount = GetAdditionalLightsCount(); for (int ii = 0; ii < lightCount; ++ii) { nextLight = GetAdditionalUtsLight(ii, posW, positionCS); if (nextLight.distanceAttenuation > mainLight.distanceAttenuation && nextLight.type == 0) { mainLight = nextLight; mainLightIndex = ii; } } return mainLightIndex; } UtsLight GetMainUtsLightByID(int index,float3 posW, float4 shadowCoord, float4 positionCS) { UtsLight mainLight; INIT_UTSLIGHT(mainLight); if (index == MAINLIGHT_NOT_FOUND) { return mainLight; } if (index == MAINLIGHT_IS_MAINLIGHT) { return GetUrpMainUtsLight(shadowCoord, positionCS); } return GetAdditionalUtsLight(index, posW, positionCS); } VertexOutput vert (VertexInput v) { VertexOutput o = (VertexOutput)0; UNITY_SETUP_INSTANCE_ID(v); UNITY_TRANSFER_INSTANCE_ID(v, o); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o); o.uv0 = v.texcoord0; //v.2.0.4 #ifdef _IS_ANGELRING_OFF // #elif _IS_ANGELRING_ON o.uv1 = v.texcoord1; #endif o.normalDir = UnityObjectToWorldNormal(v.normal); o.tangentDir = normalize( mul( unity_ObjectToWorld, float4( v.tangent.xyz, 0.0 ) ).xyz ); o.bitangentDir = normalize(cross(o.normalDir, o.tangentDir) * v.tangent.w); o.posWorld = mul(unity_ObjectToWorld, v.vertex); o.pos = UnityObjectToClipPos( v.vertex ); //v.2.0.7 Detection of the inside the mirror (right or left-handed) o.mirrorFlag = -1 then "inside the mirror".用于判断是否是渲染镜子反射结果。 //[0]Right unit vector [1] Up unit vector [2] -1 * world space camera Forward unit vector float3 crossFwd = cross(UNITY_MATRIX_V[0].xyz, UNITY_MATRIX_V[1].xyz); o.mirrorFlag = dot(crossFwd, UNITY_MATRIX_V[2].xyz) < 0 ? 1 : -1; // float3 positionWS = TransformObjectToWorld(v.vertex.xyz); float4 positionCS = TransformWorldToHClip(positionWS); half3 vertexLight = VertexLighting(o.posWorld.xyz, o.normalDir); half fogFactor = ComputeFogFactor(positionCS.z); OUTPUT_LIGHTMAP_UV(v.lightmapUV, unity_LightmapST, o.lightmapUV); OUTPUT_SH(o.normalDir.xyz, o.vertexSH); # if defined(_ADDITIONAL_LIGHTS_VERTEX) || (VERSION_LOWER(12, 0)) o.fogFactorAndVertexLight = half4(fogFactor, vertexLight); #else o.fogFactor = fogFactor; #endif o.positionCS = positionCS; #if defined(_MAIN_LIGHT_SHADOWS) && !defined(_RECEIVE_SHADOWS_OFF) #if SHADOWS_SCREEN o.shadowCoord = ComputeScreenPos(positionCS); #else o.shadowCoord = TransformWorldToShadowCoord(o.posWorld.xyz); #endif o.mainLightID = DetermineUTS_MainLightIndex(o.posWorld.xyz, o.shadowCoord, positionCS); #else o.mainLightID = DetermineUTS_MainLightIndex(o.posWorld.xyz, 0, positionCS); #endif return o; } #if defined(_SHADINGGRADEMAP) #include "UniversalToonBodyShadingGradeMap.hlsl" #else //#if defined(_SHADINGGRADEMAP) #include "UniversalToonBodyDoubleShadeWithFeather.hlsl" #endif //#if defined(_SHADINGGRADEMAP) float4 frag(VertexOutput i, fixed facing : VFACE) : SV_TARGET { #if defined(_SHADINGGRADEMAP) return fragShadingGradeMap(i, facing); #else return fragDoubleShadeFeather(i, facing); #endif } ```