Unity Shader 制作半透明物体 使用多Pass提前写入深度的方式 避免穿模

基于物理渲染-unity实现PBR shader + 多光源 + 半透明物体和阴影 基于物理渲染-unity实现PBR shader + 多光源 + 半透明物体和阴影一,PBR光照1.1直接光照1.1.1直接光照漫反射1.1.2直接光照镜面反射1.2间接光照1.2.1间接光照漫反射1.2.2间接光照镜面反射二,多光源处理+阴影三,半透明物体3.1 裁剪半透明3.2 混合半透明3.2.1 关闭深度写入的方法3.2.2 开启深度写入的方法四,半透明物体阴影4.1 半透明物体产生半透明阴影4.2 半透明物体接收阴影参考资料 一,PBR光照 pbr贴图知识里学习了次世代的两种流程,金属度粗糙度流 阅读详情

在Unity中,实现半透明效果通常会关闭深度写入(ZWrite Off)。这会导致渲染器无法正确判断物体自身的远近关系,从而在复杂的遮挡或非凸面体上产生排序错误,从视觉上看就像是穿模了。

🛠️ 解决方案:双Pass Shader原理

这个方法通过两个Pass来解决排序问题:

  1. 深度写入Pass (Depth Write Pass): 位于顶部,先执行。它只将模型的精准深度信息写入到深度缓冲区,但不输出任何颜色(ColorMask 0)。这样GPU就能知道模型的正确前后关系了。

  2. 透明混合Pass: 接着执行。利用第一个Pass已经建立好的深度缓冲,关闭深度写入(ZWrite Off),并开启透明度混合(Blend)。它就能准确判断哪些部分应被自身遮挡,从而正确进行半透明渲染。

📝 代码实现与详解

以下是一个典型的URP(通用渲染管线)下的双Pass Shader案例。

Shader "zmx/WhiteSnow_Kimono_A_SKEL_Code"
{
	Properties
	{
		[HideInInspector] _EmissionColor("Emission Color", Color) = (1,1,1,1)
		_RimBase("RimBase", Float) = 0
		_RimScale("RimScale", Range(0, 1)) = 0
		_RimPower("RimPower", Float) = 0
		[HDR] _RimInnerColor("RimInnerColor", Color) = (0, 0, 0, 0)
		[HDR] _RimOutColor("RimOutColor", Color) = (0, 0, 0, 0)
		_FlowMap("FlowMap", 2D) = "black" {}
		_FlowTiling("FlowTiling", Float) = 1
		_FlowSpeed("FlowSpeed", Float) = 0
		_FlowColor("FlowColor", Color) = (0, 0, 0, 0)
		_MaskMap("MaskMap", 2D) = "white" {}
		_MaskTiling("MaskTiling", Float) = 1
		_FlowIntensity("FlowIntensity", Range(0, 100)) = 0

		[HideInInspector] _QueueOffset("_QueueOffset", Float) = 0
		[HideInInspector] _QueueControl("_QueueControl", Float) = -1

		[HideInInspector][NoScaleOffset] unity_Lightmaps("unity_Lightmaps", 2DArray) = "" {}
		[HideInInspector][NoScaleOffset] unity_LightmapsInd("unity_LightmapsInd", 2DArray) = "" {}
		[HideInInspector][NoScaleOffset] unity_ShadowMasks("unity_ShadowMasks", 2DArray) = "" {}

		[HideInInspector][ToggleUI] _AddPrecomputedVelocity("Add Precomputed Velocity", Float) = 1
		[ToggleUI] _ReceiveShadows("Receive Shadows", Float) = 1.0

		[HideInInspector] _XRMotionVectorsPass("_XRMotionVectorsPass", Float) = 1
	}

	SubShader
	{
		LOD 0

		Tags { "RenderPipeline"="UniversalPipeline" "RenderType"="Transparent" "Queue"="Transparent" "UniversalMaterialType"="Unlit" }

		Cull Back
		AlphaToMask Off

		HLSLINCLUDE
		#pragma target 4.5
		#pragma prefer_hlslcc gles
		#if (SHADER_TARGET > 35) && defined(SHADER_API_GLES3)
			#error For WebGL2/GLES3, please set your shader target to 3.5 via SubShader options. URP shaders in ASE use target 4.5 by default.
		#endif
		#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
		#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Filtering.hlsl"
		#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

		CBUFFER_START(UnityPerMaterial)
			float4 _FlowColor;
			float4 _RimInnerColor;
			float4 _RimOutColor;
			float _FlowIntensity;
			float _FlowTiling;
			float _MaskTiling;
			float _FlowSpeed;
			float _RimPower;
			float _RimScale;
			float _RimBase;
		CBUFFER_END

		sampler2D _FlowMap;
		sampler2D _MaskMap;

		void Kimono_FullShading(float3 positionWS, half3 normalForDot, half3 viewDirForDot, out float3 color, out float alpha)
		{
			float3 objToWorld49 = mul(GetObjectToWorldMatrix(), float4(float3(0, 0, 0), 1)).xyz;
			float3 break43 = (positionWS - objToWorld49);
			float2 appendResult40 = float2(break43.x, break43.y);
			float mulTime47 = _TimeParameters.x * _FlowSpeed;
			float2 appendResult50 = float2(0.0, mulTime47);
			float3 var_FinalFlowColor54 = (_FlowColor.rgb * ((1.0 - tex2D(_FlowMap, appendResult40 * _FlowTiling).r) * tex2D(_MaskMap, appendResult40 * _MaskTiling + appendResult50).r));
			half dotResult16 = dot(normalForDot, viewDirForDot);
			float saferPower18 = abs((1.0 - (float)dotResult16));
			float var_Fresnel25 = saturate(((pow(saferPower18, _RimPower) * _RimScale) + _RimBase));
			float3 lerpResult31 = lerp(_RimInnerColor.rgb, _RimOutColor.rgb, var_Fresnel25);
			float3 var_RimColor33 = lerpResult31;
			color = ((0.2 + (sin(_TimeParameters.x) - -1.0) * (1.0 - 0.2) / (1.0 - -1.0)) * _FlowIntensity * var_FinalFlowColor54) + var_RimColor33;
			alpha = saturate(var_Fresnel25);
		}

		void Kimono_FresnelAlpha(float3 normalForDot, float3 viewDirForDot, out float alpha)
		{
			float dotResult16 = dot(normalForDot, viewDirForDot);
			float saferPower18 = abs((1.0 - dotResult16));
			float var_Fresnel25 = saturate(((pow(saferPower18, _RimPower) * _RimScale) + _RimBase));
			alpha = saturate(var_Fresnel25);
		}

		ENDHLSL

		Pass
		{
			Name "ExtraPrePass"

			Blend One Zero
			Cull Off
			ZWrite On
			ZTest LEqual
			Offset 0, 0
			ColorMask 0

			HLSLPROGRAM

			#define _SURFACE_TYPE_TRANSPARENT 1

			#pragma vertex vert
			#pragma fragment frag

			#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"

			#if defined(LOD_FADE_CROSSFADE)
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/LODCrossFade.hlsl"
			#endif

			struct Attributes
			{
				float4 positionOS : POSITION;
				half3 normalOS : NORMAL;
				UNITY_VERTEX_INPUT_INSTANCE_ID
			};

			struct PackedVaryings
			{
				float4 positionCS : SV_POSITION;
				float4 positionWSAndFogFactor : TEXCOORD0;
				half3 normalWS : TEXCOORD1;
				UNITY_VERTEX_INPUT_INSTANCE_ID
				UNITY_VERTEX_OUTPUT_STEREO
			};

			PackedVaryings VertexFunction(Attributes input)
			{
				PackedVaryings output = (PackedVaryings)0;
				UNITY_SETUP_INSTANCE_ID(input);
				UNITY_TRANSFER_INSTANCE_ID(input, output);
				UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);

				float3 vertexValue = float3(0, 0, 0);
				input.positionOS.xyz += vertexValue;
				input.normalOS = input.normalOS;

				VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
				VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS);

				float fogFactor = 0;
				output.positionCS = vertexInput.positionCS;
				output.positionWSAndFogFactor = float4(vertexInput.positionWS, fogFactor);
				output.normalWS = normalInput.normalWS;
				return output;
			}

			PackedVaryings vert(Attributes input)
			{
				return VertexFunction(input);
			}

			half4 frag(PackedVaryings input) : SV_Target
			{
				UNITY_SETUP_INSTANCE_ID(input);
				UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);

				#if defined(_SURFACE_TYPE_TRANSPARENT)
				const bool isTransparent = true;
				#else
				const bool isTransparent = false;
				#endif

				float3 PositionWS = input.positionWSAndFogFactor.xyz;
				half3 NormalWS = normalize(input.normalWS);
				float4 ScreenPosNorm = float4(GetNormalizedScreenSpaceUV(input.positionCS), input.positionCS.zw);
				float4 ClipPos = ComputeClipSpacePosition(ScreenPosNorm.xy, input.positionCS.z) * input.positionCS.w;
				half3 ViewDirWS = GetWorldSpaceNormalizeViewDir(PositionWS);

				float3 Color = float3(0, 0, 0);
				float Alpha = 1;
				float AlphaClipThreshold = 0.5;

				#if defined(_ALPHATEST_ON)
				AlphaDiscard(Alpha, AlphaClipThreshold);
				#endif

				InputData inputData = (InputData)0;
				inputData.positionWS = PositionWS;
				inputData.positionCS = float4(input.positionCS.xy, ClipPos.zw / ClipPos.w);
				inputData.normalizedScreenSpaceUV = ScreenPosNorm.xy;
				inputData.normalWS = NormalWS;
				inputData.viewDirectionWS = ViewDirWS;

				#if defined(LOD_FADE_CROSSFADE)
				LODFadeCrossFade(input.positionCS);
				#endif

				return half4(Color, OutputAlpha(Alpha, isTransparent));
			}
			ENDHLSL
		}

		Pass
		{
			Name "Forward"
			Tags { "LightMode"="UniversalForwardOnly" }

			Blend SrcAlpha OneMinusSrcAlpha, SrcAlpha OneMinusSrcAlpha
			ZWrite On
			ZTest LEqual
			Offset 0, 0
			ColorMask RGBA

			HLSLPROGRAM

			#pragma shader_feature_local_fragment _RECEIVE_SHADOWS_OFF
			#define _SURFACE_TYPE_TRANSPARENT 1

			#pragma multi_compile_fragment _ _DBUFFER_MRT1 _DBUFFER_MRT2 _DBUFFER_MRT3
			#pragma multi_compile_fragment _ DEBUG_DISPLAY

			#pragma vertex vert
			#pragma fragment frag

			#define SHADERPASS SHADERPASS_UNLIT

			#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
			#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RenderingLayers.hlsl"
			#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Fog.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Texture.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureStack.hlsl"
			#include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRenderingKeywords.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRendering.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DBuffer.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShaderPass.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Debug/Debugging3D.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceData.hlsl"

			#if defined(LOD_FADE_CROSSFADE)
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/LODCrossFade.hlsl"
			#endif

			#if defined(ASE_EARLY_Z_DEPTH_OPTIMIZE) && (SHADER_TARGET >= 45)
			#define ASE_SV_DEPTH SV_DepthLessEqual
			#define ASE_SV_POSITION_QUALIFIERS linear noperspective centroid
			#else
			#define ASE_SV_DEPTH SV_Depth
			#define ASE_SV_POSITION_QUALIFIERS
			#endif

			struct Attributes
			{
				float4 positionOS : POSITION;
				half3 normalOS : NORMAL;
				UNITY_VERTEX_INPUT_INSTANCE_ID
			};

			struct PackedVaryings
			{
				ASE_SV_POSITION_QUALIFIERS float4 positionCS : SV_POSITION;
				float4 positionWSAndFogFactor : TEXCOORD0;
				half3 normalWS : TEXCOORD1;
				UNITY_VERTEX_INPUT_INSTANCE_ID
				UNITY_VERTEX_OUTPUT_STEREO
			};

			PackedVaryings VertexFunction(Attributes input)
			{
				PackedVaryings output = (PackedVaryings)0;
				UNITY_SETUP_INSTANCE_ID(input);
				UNITY_TRANSFER_INSTANCE_ID(input, output);
				UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);

				float3 vertexValue = float3(0, 0, 0);
				input.positionOS.xyz += vertexValue;
				input.normalOS = input.normalOS;

				VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
				VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS);

				float fogFactor = 0;
				output.positionCS = vertexInput.positionCS;
				output.positionWSAndFogFactor = float4(vertexInput.positionWS, fogFactor);
				output.normalWS = normalInput.normalWS;
				return output;
			}

			PackedVaryings vert(Attributes input)
			{
				return VertexFunction(input);
			}

			half4 frag(PackedVaryings input
				#if defined(ASE_DEPTH_WRITE_ON)
				, out float outputDepth : ASE_SV_DEPTH
				#endif
				#ifdef _WRITE_RENDERING_LAYERS
				, out uint outRenderingLayers : SV_Target1
				#endif
				) : SV_Target
			{
				UNITY_SETUP_INSTANCE_ID(input);
				UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);

				#if defined(_SURFACE_TYPE_TRANSPARENT)
				const bool isTransparent = true;
				#else
				const bool isTransparent = false;
				#endif

				#if defined(LOD_FADE_CROSSFADE)
				LODFadeCrossFade(input.positionCS);
				#endif

				#if defined(MAIN_LIGHT_CALCULATE_SHADOWS)
				float4 shadowCoord = TransformWorldToShadowCoord(input.positionWSAndFogFactor.xyz);
				#else
				float4 shadowCoord = float4(0, 0, 0, 0);
				#endif

				float3 PositionWS = input.positionWSAndFogFactor.xyz;
				half3 ViewDirWS = GetWorldSpaceNormalizeViewDir(PositionWS);
				float4 ShadowCoord = shadowCoord;
				float4 ScreenPosNorm = float4(GetNormalizedScreenSpaceUV(input.positionCS), input.positionCS.zw);
				float4 ClipPos = ComputeClipSpacePosition(ScreenPosNorm.xy, input.positionCS.z) * input.positionCS.w;
				half3 NormalWS = normalize(input.normalWS);

				float3 Color;
				float Alpha;
				Kimono_FullShading(PositionWS, NormalWS, ViewDirWS, Color, Alpha);

				float AlphaClipThreshold = 0.5;

				#if defined(ASE_DEPTH_WRITE_ON)
				float DeviceDepth = input.positionCS.z;
				#endif

				#if defined(_ALPHATEST_ON)
				AlphaDiscard(Alpha, AlphaClipThreshold);
				#endif

				#if defined(MAIN_LIGHT_CALCULATE_SHADOWS) && defined(ASE_CHANGES_WORLD_POS)
				ShadowCoord = TransformWorldToShadowCoord(PositionWS);
				#endif

				InputData inputData = (InputData)0;
				inputData.positionWS = PositionWS;
				inputData.positionCS = float4(input.positionCS.xy, ClipPos.zw / ClipPos.w);
				inputData.normalizedScreenSpaceUV = ScreenPosNorm.xy;
				inputData.normalWS = NormalWS;
				inputData.viewDirectionWS = ViewDirWS;

				#if defined(_SCREEN_SPACE_OCCLUSION) && !defined(_SURFACE_TYPE_TRANSPARENT)
				float2 normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(input.positionCS);
				AmbientOcclusionFactor aoFactor = GetScreenSpaceAmbientOcclusion(normalizedScreenSpaceUV);
				Color.rgb *= aoFactor.directAmbientOcclusion;
				#endif

				#if defined(_DBUFFER)
				ApplyDecalToBaseColor(input.positionCS, Color);
				#endif

				#if defined(ASE_DEPTH_WRITE_ON)
				outputDepth = DeviceDepth;
				#endif

				#ifdef _WRITE_RENDERING_LAYERS
				outRenderingLayers = EncodeMeshRenderingLayer();
				#endif

				return half4(Color, OutputAlpha(Alpha, isTransparent));
			}
			ENDHLSL
		}

		Pass
		{
			Name "DepthOnly"
			Tags { "LightMode"="DepthOnly" }

			ZWrite On
			ColorMask 0
			AlphaToMask Off

			HLSLPROGRAM

			#define _SURFACE_TYPE_TRANSPARENT 1

			#pragma vertex vert
			#pragma fragment frag

			#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"

			#if defined(LOD_FADE_CROSSFADE)
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/LODCrossFade.hlsl"
			#endif

			#if defined(ASE_EARLY_Z_DEPTH_OPTIMIZE) && (SHADER_TARGET >= 45)
			#define ASE_SV_DEPTH SV_DepthLessEqual
			#define ASE_SV_POSITION_QUALIFIERS linear noperspective centroid
			#else
			#define ASE_SV_DEPTH SV_Depth
			#define ASE_SV_POSITION_QUALIFIERS
			#endif

			struct Attributes
			{
				float4 positionOS : POSITION;
				half3 normalOS : NORMAL;
				UNITY_VERTEX_INPUT_INSTANCE_ID
			};

			struct PackedVaryings
			{
				ASE_SV_POSITION_QUALIFIERS float4 positionCS : SV_POSITION;
				float4 ase_texcoord : TEXCOORD0;
				float4 ase_texcoord1 : TEXCOORD1;
				UNITY_VERTEX_INPUT_INSTANCE_ID
				UNITY_VERTEX_OUTPUT_STEREO
			};

			PackedVaryings VertexFunction(Attributes input)
			{
				PackedVaryings output = (PackedVaryings)0;
				UNITY_SETUP_INSTANCE_ID(input);
				UNITY_TRANSFER_INSTANCE_ID(input, output);
				UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);

				float3 ase_normalWS = TransformObjectToWorldNormal(input.normalOS);
				output.ase_texcoord.xyz = ase_normalWS;
				float3 ase_positionWS = TransformObjectToWorld((input.positionOS).xyz);
				output.ase_texcoord1.xyz = ase_positionWS;
				output.ase_texcoord.w = 0;
				output.ase_texcoord1.w = 0;

				float3 vertexValue = float3(0, 0, 0);
				input.positionOS.xyz += vertexValue;

				VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
				output.positionCS = vertexInput.positionCS;
				return output;
			}

			PackedVaryings vert(Attributes input)
			{
				return VertexFunction(input);
			}

			half4 frag(PackedVaryings input
				#if defined(ASE_DEPTH_WRITE_ON)
				, out float outputDepth : ASE_SV_DEPTH
				#endif
				) : SV_Target
			{
				UNITY_SETUP_INSTANCE_ID(input);
				UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);

				float4 ScreenPosNorm = float4(GetNormalizedScreenSpaceUV(input.positionCS), input.positionCS.zw);
				float4 ClipPos = ComputeClipSpacePosition(ScreenPosNorm.xy, input.positionCS.z) * input.positionCS.w;

				float3 ase_normalWS = input.ase_texcoord.xyz;
				float3 ase_positionWS = input.ase_texcoord1.xyz;
				float3 ase_viewVectorWS = (_WorldSpaceCameraPos.xyz - ase_positionWS);
				float3 ase_viewDirWS = normalize(ase_viewVectorWS);

				float Alpha;
				Kimono_FresnelAlpha(ase_normalWS, ase_viewDirWS, Alpha);
				float AlphaClipThreshold = 0.5;

				#if defined(ASE_DEPTH_WRITE_ON)
				float DeviceDepth = input.positionCS.z;
				#endif

				#if defined(_ALPHATEST_ON)
				AlphaDiscard(Alpha, AlphaClipThreshold);
				#endif

				#if defined(LOD_FADE_CROSSFADE)
				LODFadeCrossFade(input.positionCS);
				#endif

				#if defined(ASE_DEPTH_WRITE_ON)
				outputDepth = DeviceDepth;
				#endif

				return 0;
			}
			ENDHLSL
		}

		Pass
		{
			Name "SceneSelectionPass"
			Tags { "LightMode"="SceneSelectionPass" }

			Cull Off
			AlphaToMask Off

			HLSLPROGRAM

			#define _SURFACE_TYPE_TRANSPARENT 1

			#pragma vertex vert
			#pragma fragment frag

			#define ATTRIBUTES_NEED_NORMAL
			#define ATTRIBUTES_NEED_TANGENT
			#define SHADERPASS SHADERPASS_DEPTHONLY

			#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
			#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RenderingLayers.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Texture.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureStack.hlsl"
			#include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRenderingKeywords.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRendering.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShaderPass.hlsl"

			struct Attributes
			{
				float4 positionOS : POSITION;
				half3 normalOS : NORMAL;
				UNITY_VERTEX_INPUT_INSTANCE_ID
			};

			struct PackedVaryings
			{
				float4 positionCS : SV_POSITION;
				float4 ase_texcoord : TEXCOORD0;
				float4 ase_texcoord1 : TEXCOORD1;
				UNITY_VERTEX_INPUT_INSTANCE_ID
				UNITY_VERTEX_OUTPUT_STEREO
			};

			int _ObjectId;
			int _PassValue;

			struct SurfaceDescription
			{
				float Alpha;
				float AlphaClipThreshold;
			};

			PackedVaryings VertexFunction(Attributes input)
			{
				PackedVaryings output;
				ZERO_INITIALIZE(PackedVaryings, output);

				UNITY_SETUP_INSTANCE_ID(input);
				UNITY_TRANSFER_INSTANCE_ID(input, output);
				UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);

				float3 ase_normalWS = TransformObjectToWorldNormal(input.normalOS);
				output.ase_texcoord.xyz = ase_normalWS;
				float3 ase_positionWS = TransformObjectToWorld((input.positionOS).xyz);
				output.ase_texcoord1.xyz = ase_positionWS;
				output.ase_texcoord.w = 0;
				output.ase_texcoord1.w = 0;

				float3 vertexValue = float3(0, 0, 0);
				input.positionOS.xyz += vertexValue;

				VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
				output.positionCS = vertexInput.positionCS;
				return output;
			}

			PackedVaryings vert(Attributes input)
			{
				return VertexFunction(input);
			}

			half4 frag(PackedVaryings input) : SV_Target
			{
				SurfaceDescription surfaceDescription = (SurfaceDescription)0;

				float3 ase_normalWS = input.ase_texcoord.xyz;
				float3 ase_positionWS = input.ase_texcoord1.xyz;
				float3 ase_viewVectorWS = (_WorldSpaceCameraPos.xyz - ase_positionWS);
				float3 ase_viewDirWS = normalize(ase_viewVectorWS);

				float a;
				Kimono_FresnelAlpha(ase_normalWS, ase_viewDirWS, a);
				surfaceDescription.Alpha = a;
				surfaceDescription.AlphaClipThreshold = 0.5;

				#ifdef _ALPHATEST_ON
				clip(surfaceDescription.Alpha - surfaceDescription.AlphaClipThreshold);
				#endif

				return half4(_ObjectId, _PassValue, 1.0, 1.0);
			}
			ENDHLSL
		}

		Pass
		{
			Name "ScenePickingPass"
			Tags { "LightMode"="Picking" }

			AlphaToMask Off

			HLSLPROGRAM

			#define _SURFACE_TYPE_TRANSPARENT 1

			#pragma vertex vert
			#pragma fragment frag

			#define ATTRIBUTES_NEED_NORMAL
			#define ATTRIBUTES_NEED_TANGENT
			#define SHADERPASS SHADERPASS_DEPTHONLY

			#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
			#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RenderingLayers.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Texture.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureStack.hlsl"
			#include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRenderingKeywords.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRendering.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShaderPass.hlsl"

			#if defined(LOD_FADE_CROSSFADE)
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/LODCrossFade.hlsl"
			#endif

			struct Attributes
			{
				float4 positionOS : POSITION;
				half3 normalOS : NORMAL;
				UNITY_VERTEX_INPUT_INSTANCE_ID
			};

			struct PackedVaryings
			{
				float4 positionCS : SV_POSITION;
				float4 ase_texcoord : TEXCOORD0;
				float4 ase_texcoord1 : TEXCOORD1;
				UNITY_VERTEX_INPUT_INSTANCE_ID
				UNITY_VERTEX_OUTPUT_STEREO
			};

			float4 _SelectionID;

			struct SurfaceDescription
			{
				float Alpha;
				float AlphaClipThreshold;
			};

			PackedVaryings VertexFunction(Attributes input)
			{
				PackedVaryings output;
				ZERO_INITIALIZE(PackedVaryings, output);

				UNITY_SETUP_INSTANCE_ID(input);
				UNITY_TRANSFER_INSTANCE_ID(input, output);
				UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);

				float3 ase_normalWS = TransformObjectToWorldNormal(input.normalOS);
				output.ase_texcoord.xyz = ase_normalWS;
				float3 ase_positionWS = TransformObjectToWorld((input.positionOS).xyz);
				output.ase_texcoord1.xyz = ase_positionWS;
				output.ase_texcoord.w = 0;
				output.ase_texcoord1.w = 0;

				float3 vertexValue = float3(0, 0, 0);
				input.positionOS.xyz += vertexValue;

				VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
				output.positionCS = vertexInput.positionCS;
				return output;
			}

			PackedVaryings vert(Attributes input)
			{
				return VertexFunction(input);
			}

			half4 frag(PackedVaryings input) : SV_Target
			{
				SurfaceDescription surfaceDescription = (SurfaceDescription)0;

				float3 ase_normalWS = input.ase_texcoord.xyz;
				float3 ase_positionWS = input.ase_texcoord1.xyz;
				float3 ase_viewVectorWS = (_WorldSpaceCameraPos.xyz - ase_positionWS);
				float3 ase_viewDirWS = normalize(ase_viewVectorWS);

				float a;
				Kimono_FresnelAlpha(ase_normalWS, ase_viewDirWS, a);
				surfaceDescription.Alpha = a;
				surfaceDescription.AlphaClipThreshold = 0.5;

				#ifdef _ALPHATEST_ON
				clip(surfaceDescription.Alpha - surfaceDescription.AlphaClipThreshold);
				#endif

				half4 outColor = 0;
				outColor = unity_SelectionID;
				return outColor;
			}
			ENDHLSL
		}

		Pass
		{
			Name "DepthNormals"
			Tags { "LightMode"="DepthNormalsOnly" }

			ZTest LEqual
			ZWrite On

			HLSLPROGRAM

			#define _SURFACE_TYPE_TRANSPARENT 1

			#pragma multi_compile_fragment _ _GBUFFER_NORMALS_OCT

			#pragma vertex vert
			#pragma fragment frag

			#define ATTRIBUTES_NEED_NORMAL
			#define ATTRIBUTES_NEED_TANGENT
			#define VARYINGS_NEED_NORMAL_WS
			#define SHADERPASS SHADERPASS_DEPTHNORMALSONLY

			#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
			#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RenderingLayers.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Texture.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureStack.hlsl"
			#include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRenderingKeywords.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRendering.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShaderPass.hlsl"

			#if defined(LOD_FADE_CROSSFADE)
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/LODCrossFade.hlsl"
			#endif

			#if defined(ASE_EARLY_Z_DEPTH_OPTIMIZE) && (SHADER_TARGET >= 45)
			#define ASE_SV_DEPTH SV_DepthLessEqual
			#define ASE_SV_POSITION_QUALIFIERS linear noperspective centroid
			#else
			#define ASE_SV_DEPTH SV_Depth
			#define ASE_SV_POSITION_QUALIFIERS
			#endif

			struct Attributes
			{
				float4 positionOS : POSITION;
				half3 normalOS : NORMAL;
				UNITY_VERTEX_INPUT_INSTANCE_ID
			};

			struct PackedVaryings
			{
				ASE_SV_POSITION_QUALIFIERS float4 positionCS : SV_POSITION;
				half3 normalWS : TEXCOORD0;
				float4 ase_texcoord1 : TEXCOORD1;
				UNITY_VERTEX_INPUT_INSTANCE_ID
				UNITY_VERTEX_OUTPUT_STEREO
			};

			PackedVaryings VertexFunction(Attributes input)
			{
				PackedVaryings output;
				ZERO_INITIALIZE(PackedVaryings, output);

				UNITY_SETUP_INSTANCE_ID(input);
				UNITY_TRANSFER_INSTANCE_ID(input, output);
				UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);

				float3 ase_positionWS = TransformObjectToWorld((input.positionOS).xyz);
				output.ase_texcoord1.xyz = ase_positionWS;
				output.ase_texcoord1.w = 0;

				float3 vertexValue = float3(0, 0, 0);
				input.positionOS.xyz += vertexValue;
				input.normalOS = input.normalOS;

				VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
				VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS);

				output.positionCS = vertexInput.positionCS;
				output.normalWS = normalInput.normalWS;
				return output;
			}

			PackedVaryings vert(Attributes input)
			{
				return VertexFunction(input);
			}

			void frag(PackedVaryings input
				, out half4 outNormalWS : SV_Target0
				#if defined(ASE_DEPTH_WRITE_ON)
				, out float outputDepth : ASE_SV_DEPTH
				#endif
				#ifdef _WRITE_RENDERING_LAYERS
				, out uint outRenderingLayers : SV_Target1
				#endif
				)
			{
				UNITY_SETUP_INSTANCE_ID(input);
				UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);

				half3 NormalWS = normalize(input.normalWS);
				float4 ScreenPosNorm = float4(GetNormalizedScreenSpaceUV(input.positionCS), input.positionCS.zw);
				float4 ClipPos = ComputeClipSpacePosition(ScreenPosNorm.xy, input.positionCS.z) * input.positionCS.w;

				float3 ase_positionWS = input.ase_texcoord1.xyz;
				float3 ase_viewVectorWS = (_WorldSpaceCameraPos.xyz - ase_positionWS);
				float3 ase_viewDirWS = normalize(ase_viewVectorWS);

				float Alpha;
				Kimono_FresnelAlpha((float3)NormalWS, ase_viewDirWS, Alpha);
				float AlphaClipThreshold = 0.5;

				#if defined(ASE_DEPTH_WRITE_ON)
				float DeviceDepth = input.positionCS.z;
				#endif

				#ifdef _ALPHATEST_ON
				clip(Alpha - AlphaClipThreshold);
				#endif

				#if defined(LOD_FADE_CROSSFADE)
				LODFadeCrossFade(input.positionCS);
				#endif

				#if defined(ASE_DEPTH_WRITE_ON)
				outputDepth = DeviceDepth;
				#endif

				#if defined(_GBUFFER_NORMALS_OCT)
				float2 octNormalWS = PackNormalOctQuadEncode(NormalWS);
				float2 remappedOctNormalWS = saturate(octNormalWS * 0.5 + 0.5);
				half3 packedNormalWS = PackFloat2To888(remappedOctNormalWS);
				outNormalWS = half4(packedNormalWS, 0.0);
				#else
				outNormalWS = half4(NormalizeNormalPerPixel(NormalWS), 0.0);
				#endif

				#ifdef _WRITE_RENDERING_LAYERS
				outRenderingLayers = EncodeMeshRenderingLayer();
				#endif
			}
			ENDHLSL
		}

		Pass
		{
			Name "GBuffer"
			Tags { "LightMode"="UniversalGBuffer" }

			Blend SrcAlpha OneMinusSrcAlpha, SrcAlpha OneMinusSrcAlpha
			ZWrite On
			ZTest LEqual
			Offset 0, 0
			ColorMask RGBA

			HLSLPROGRAM

			#pragma shader_feature_local_fragment _RECEIVE_SHADOWS_OFF
			#define _SURFACE_TYPE_TRANSPARENT 1

			#pragma exclude_renderers glcore gles3

			#pragma multi_compile_fragment _ _DBUFFER_MRT1 _DBUFFER_MRT2 _DBUFFER_MRT3
			#pragma multi_compile_fragment _ _GBUFFER_NORMALS_OCT
			#pragma multi_compile_fragment _ _RENDER_PASS_ENABLED

			#pragma vertex vert
			#pragma fragment frag

			#define SHADERPASS SHADERPASS_GBUFFER

			#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DOTS.hlsl"
			#include_with_pragmas "Packages/com.unity.render-pipelines.universal/ShaderLibrary/RenderingLayers.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Texture.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Input.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureStack.hlsl"
			#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRendering.hlsl"
			#include_with_pragmas "Packages/com.unity.render-pipelines.core/ShaderLibrary/FoveatedRenderingKeywords.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DBuffer.hlsl"
			#include "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShaderPass.hlsl"

			#if defined(LOD_FADE_CROSSFADE)
			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/LODCrossFade.hlsl"
			#endif

			#if defined(UNITY_INSTANCING_ENABLED) && defined(_TERRAIN_INSTANCED_PERPIXEL_NORMAL)
			#define ENABLE_TERRAIN_PERPIXEL_NORMAL
			#endif

			#if defined(ASE_EARLY_Z_DEPTH_OPTIMIZE) && (SHADER_TARGET >= 45)
			#define ASE_SV_DEPTH SV_DepthLessEqual
			#define ASE_SV_POSITION_QUALIFIERS linear noperspective centroid
			#else
			#define ASE_SV_DEPTH SV_Depth
			#define ASE_SV_POSITION_QUALIFIERS
			#endif

			struct Attributes
			{
				float4 positionOS : POSITION;
				half3 normalOS : NORMAL;
				UNITY_VERTEX_INPUT_INSTANCE_ID
			};

			struct PackedVaryings
			{
				ASE_SV_POSITION_QUALIFIERS float4 positionCS : SV_POSITION;
				float3 positionWS : TEXCOORD0;
				half3 normalWS : TEXCOORD1;
				UNITY_VERTEX_INPUT_INSTANCE_ID
				UNITY_VERTEX_OUTPUT_STEREO
			};

			#ifdef SCENEPICKINGPASS
			float4 _SelectionID;
			#endif

			#ifdef SCENESELECTIONPASS
			int _ObjectId;
			int _PassValue;
			#endif

			#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/GBufferOutput.hlsl"

			PackedVaryings VertexFunction(Attributes input)
			{
				PackedVaryings output = (PackedVaryings)0;
				UNITY_SETUP_INSTANCE_ID(input);
				UNITY_TRANSFER_INSTANCE_ID(input, output);
				UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output);

				float3 vertexValue = float3(0, 0, 0);
				input.positionOS.xyz += vertexValue;

				VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz);
				VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS);

				output.positionCS = vertexInput.positionCS;
				output.positionWS = vertexInput.positionWS;
				output.normalWS = normalInput.normalWS;
				return output;
			}

			PackedVaryings vert(Attributes input)
			{
				return VertexFunction(input);
			}

			GBufferFragOutput frag(PackedVaryings input
				#if defined(ASE_DEPTH_WRITE_ON)
				, out float outputDepth : ASE_SV_DEPTH
				#endif
				)
			{
				UNITY_SETUP_INSTANCE_ID(input);
				UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(input);

				#if defined(LOD_FADE_CROSSFADE)
				LODFadeCrossFade(input.positionCS);
				#endif

				float3 PositionWS = input.positionWS;
				half3 ViewDirWS = GetWorldSpaceNormalizeViewDir(PositionWS);
				float4 ScreenPosNorm = float4(GetNormalizedScreenSpaceUV(input.positionCS), input.positionCS.zw);
				float4 ClipPos = ComputeClipSpacePosition(ScreenPosNorm.xy, input.positionCS.z) * input.positionCS.w;
				half3 NormalWS = normalize(input.normalWS);

				float3 Color;
				float Alpha;
				Kimono_FullShading(PositionWS, NormalWS, ViewDirWS, Color, Alpha);

				float AlphaClipThreshold = 0.5;

				#if defined(ASE_DEPTH_WRITE_ON)
				float DeviceDepth = input.positionCS.z;
				#endif

				#ifdef _ALPHATEST_ON
				clip(Alpha - AlphaClipThreshold);
				#endif

				InputData inputData = (InputData)0;
				inputData.positionWS = PositionWS;
				inputData.positionCS = float4(input.positionCS.xy, ClipPos.zw / ClipPos.w);
				inputData.normalizedScreenSpaceUV = ScreenPosNorm.xy;
				inputData.normalWS = NormalWS;
				inputData.viewDirectionWS = ViewDirWS;

				#if defined(_DBUFFER)
				ApplyDecalToBaseColor(input.positionCS, Color);
				#endif

				#if defined(ASE_DEPTH_WRITE_ON)
				outputDepth = DeviceDepth;
				#endif

				SurfaceData surfaceData = (SurfaceData)0;
				surfaceData.albedo = Color;
				surfaceData.alpha = Alpha;

				#if defined(_SCREEN_SPACE_OCCLUSION)
				float2 normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(input.positionCS);
				AmbientOcclusionFactor aoFactor = GetScreenSpaceAmbientOcclusion(normalizedScreenSpaceUV);
				surfaceData.occlusion = aoFactor.directAmbientOcclusion;
				#else
				surfaceData.occlusion = 1;
				#endif

				return PackGBuffersSurfaceData(surfaceData, inputData, float3(0, 0, 0));
			}

			ENDHLSL
		}
	}

	FallBack Off
}
  • 性能开销:会额外增加一次完整的绘制调用,因此对渲染性能有一定影响。

  • 渲染限制:仅在物体自身的渲染排序中有效。对于多个半透明物体相互穿插的复杂情况,由于引擎限制,依然可能出现排序错误的穿模现象。

⚖️ 替代方案选择

对于不同的需求,也可以考虑更简单的方案:

  • Alpha Test(透明度测试):也叫“镂空”,通过 clip函数直接丢弃透明度低于阈值的片元,无需关闭深度写入。它不会有排序错误,但效果生硬,非0即1,无法实现边缘柔和的半透明效果。

  • 性能更优的替代:Single Pass + ZWrite On:如果你的Shader逻辑简单(如纯色、无顶点动画),也可以尝试合并为单个Pass并保持ZWrite On,这能避免双Pass的性能浪费,但兼容性不如双Pass方案。

💎 总结与建议

双Pass Shader是解决半透明物体自身穿模问题的“标准答案”。如果你的模型几何关系复杂,或因深度排序混乱导致视觉效果不佳,这个方法值得尝试。但如果对性能要求极高,或需要在移动设备上有良好表现,那么Alpha Test或调整模型使其结构更简单等方案可能更合适。

Unity渲染深度写入ZWrite原理详解与实战避坑指南 深度测试与深度写入是实时渲染中决定像素可见性的核心机制。深度测试通过比较当前片元与深度缓冲中的值,决定像素是否被渲染;深度写入则控制是否更新深度缓冲,为后续渲染建立遮挡关系。正确配置深度状态对于实现正确的物体遮挡、半透明混合及避免视觉瑕疵至关重要,直接影响渲染结果的正确性与性能。在游戏开发、UI界面和特效制作等应用场景中,开发者常需根据物体类型(如不透明、半透明、UI)调整深度写入策略。本文聚焦于Unity Shader中的ZWrite开关,通过剖析其与深度测试、渲染队列的协同原理,并结合半透明排序、粒子特 阅读详情

相关推荐

Unity URP半透明渲染深度解析:双面渲染与深度写入优化实战

在实时图形渲染中,半透明效果是实现玻璃、水体、火焰等视觉元素的关键技术,其核心在于颜色混合与深度管理的平衡。半透明渲染遵循从后往前的绘制顺序,通过Alpha混合公式将当前片段颜色与帧缓冲区已有颜色进行叠加,模拟光线穿透效果。这一过程的技术价值在于在保证视觉真实感的同时,尽可能减少性能开销。然而,半透明物体的自身交叠和排序问题一直是开发中的常见挑战,尤其在追求高性能的URP渲染管线中更为突出。通过双面渲染技术,可以分通道处理模型的正反面,并配合深度写入的精细控制,有效解决内部渲染错乱问题。而Alpha To

weixin_38166557的博客 460

具体介绍下Unity的Shader中Pass

Pass是Shader中的一个重要组成部分,定义了如何渲染物体的特定方面。每个Pass可以实现不同的渲染效果,如基础颜色、光照、阴影等。在渲染过程中,Unity会根据选择的SubShader依次执行每个`pass。Pass在Unity Shader中是实现复杂渲染效果的关键组成部分。通过合理使用多个Pass,开发者可以实现多种渲染效果,如基础颜色、光照、阴影等。接下来我们将继续探讨Pass的更多细节,以及在Unity Shader开发中的最佳实践和常见问题。Pass的灵活性:通过合理使用多个。

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 504

Unity URP热扭曲实战:半透明物体深度重建与分层采样

热扭曲是一种基于屏幕空间UV偏移的后处理视觉效果,其本质依赖深度缓冲进行采样校准,以实现符合物理规律的空气折射模拟。在URP中,由于Transparent队列不写入深度,导致玻璃、烟雾等半透明物体无法参与标准扭曲计算,常出现撕裂、黑边或背景错乱。解决关键在于构建‘虚拟深度’并实施分层采样策略——通过Custom Render Feature生成带深度信息的半透明合成纹理,结合DistortionBuffer与TransparencyDepthBuffer双纹理协同,在Shader Graph中完成深度感知的

weixin_30460489的博客 591

【Unity Shader】第三节 纹理半透明---多个半透明面穿插

很惭愧,本来逼着自己来更新教程,另一个目的就是为了督促自己把这本书看完,结果第三天就断了 依然是为了问题而来更新了博客,没有了技术美术,遇到问题只能自己解决了 问题是这样的:伸出水面的柱子底部有半透明的材质,用来营造水深的效果,水面也是半透明的,放在一起就出现了半透明穿插的问题,渲染序列出错了。 这个问题在计算机图形学上看成经典案例,在unity上解决方法很简单,修改

我是一只夜行的猫仔 5509

Unity URP中Kajiya-Kay头发渲染Shader实现与穿模解决

在实时渲染中,各向异性光照是模拟丝绸、金属拉丝及头发等表面特性的关键技术,其原理在于表面微结构导致光线反射随观察方向变化而产生方向性高光。Kajiya-Kay模型作为经典的各向异性光照模型,通过切线空间计算模拟发丝圆柱体反射,生成沿切线方向拉伸的高光条带,从而在视觉上呈现发丝的丝滑质感与通透光泽。这一技术对于提升角色渲染的真实感与风格化表现具有重要价值,尤其在移动端与跨平台的URP项目中。本文将结合**穿模**问题与**切线空间**计算,详解在URP下实现该模型的Shader代码、光照信息获取、渲染队列配置

weixin_33850015的博客 321

Unity Shader深度写入ZWrite:从原理到实战的透明与不透明渲染抉择

本文深入解析Unity Shader中的深度写入(ZWrite)原理与应用,从不透明物体到半透明物体的渲染策略,提供实战技巧与性能优化建议。通过具体案例和代码示例,帮助开发者解决透明与不透明渲染中的常见问题,提升渲染效果与性能。

weixin_30254435的博客 450

Unity URP 下的 Early-Z / Depth Prepass 解决复杂片元着色器造成的 Overdraw 问题

Overdraw 指的是在渲染过程中,同一个像素被多次绘制的情况。在不透明物体渲染中,只有最靠近相机的像素最终可见,但传统的从前向后渲染顺序会导致大量被遮挡的像素仍然执行了完整的片元着色器计算。// 自定义顶点动画函数 - 确保深度预渲染使用相同的顶点位置// 顶点着色器 - 用于 DepthOnly 和 ForwardLit Pass// 应用与主渲染相同的顶点动画// 配置深度写入状态// 执行深度预渲染。

mxwin的博客 595

Unity URP中深度写入与Blend模式优化半透明渲染实战

本文深入探讨了Unity URP中深度写入与Blend模式优化半透明渲染的实战技巧。通过分析半透明效果的核心挑战,提供了深度写入、混合模式选择和渲染队列优化的详细配置方案,帮助开发者解决物体穿模和渲染顺序错乱问题。文章包含完整的Shader代码解析和性能优化建议,适用于游戏特效、场景渲染等开发场景。

weixin_29008805的博客 270

【Unity Shader 中Pass_CG编译指令相关介绍_第一篇】

着色器函数(本篇不扩展语义和结构体内容。)

暴走约伯的博客 4593

Unity半透明水面阴影实现:Shader双Pass与深度一致性实战

在实时渲染中,阴影映射(Shadow Mapping)是实现动态光影的核心技术,其原理是通过从光源视角生成深度贴图,再与相机视角的深度值进行比较,从而确定像素是否处于阴影中。对于不透明物体,Unity等引擎提供了默认的阴影处理流程,但当涉及半透明表面时,问题变得复杂——标准透明着色器往往无法正确处理阴影投射与接收,导致视觉失真。这背后的技术关键在于深度缓冲(Z-Buffer)与透明度混合(Alpha Blending)的冲突,以及阴影贴图生成时对几何体一致性的要求。为解决这一难题,开发者需要深入Shader

weixin_34013044的博客 485

Unity Shader 之 XRay 物体挡住 X 射线的效果实现

Unity Shader 之 XRay 物体挡住 X 射线的效果实现 目录 Unity Shader 之 XRay 物体挡住 X 射线的效果实现 一、简单介绍 二、实现原理 三、注意事项 四、效果预览 五、实现步骤 一、简单介绍 Shader Language的发展方向是设计出在便携性方面可以和C++、Java等相比的高级语言,“赋予程序员灵活而方便的编程方式”,并“...

仙魁XAN 1796

Unity半透明物体+投射阴影+接受阴影

【前置】 水流动效果+透明 物体实现半透明有透明度测试和透明度混合两种方式,不同方式接受和投射阴影的方式有所差别。 【透明度测试阴影效果图】 正方体的阴影一部分打在了水平面上,一部分在白色平面上。由于透明度测试使得水平面的右半部分为完全透明,所以白色平面会接收到正方体的阴影。 水平面用的纹理贴图本身是完全不透明的物体,为了避免在透明度测试中完全透明和完全不透明的情况,用了下面的一张透明度纹理来代替水平面的透明通道 【透明度测试阴影代码】 Shader "Custom/WaterFlow

enternalstar的博客 9316

unity Pass

unity shader 的Pass的应用和发开 渲染管线的开发。。。。

【Unity Shader编程】之透明物体渲染

unity shader的透明物体渲染,主要是要控制好渲染队列以及是否开启深度写入,当遇到透明渲染队列需要关闭深度写入,以防半透明或者透明物体写入的时候,导致后面的不透明物体因为深度写入的判断杯丢弃,并且半透明或者透明物体,需要在不透明物体之后渲染,而半透明物体渲染,需要渲染前后两面,因而,需要两个pass,一个先渲染背面,另外一个再渲染正面,达到双面渲染的状态。第一个 Pass 的深度写入为第二个 Pass 提供了逐像素的深度基准,而第二个 Pass 仅依赖此基准进行混合(不修改深度缓冲)。

qq1342753906的博客 815

全球半导体设备氧化钇熔射服务行业规模预测:预计未来六年CAGR为7.8%

本文将对“半导体设备氧化钇熔射服务”行业进行深度分析,探讨市场趋势的演变、核心竞争者的战略布局、供应链结构的内外特点、研发创新的最新进展、法规政策环境的适应性调整以及投资机会与风险评估。这一稳健的增长趋势表明半导体设备氧化钇熔射服务在电子行业中的重要性逐渐增强。由于全球对于高效、高精度和可靠的电子解决方案的需求增加,对能够提供这些功能的半导体设备氧化钇熔射服务的需求日益增长。由于半导体设备氧化钇熔射服务主要为就地服务型,其“配送”主要依赖于专业团队和技术设备的及时调配,强调服务的时效性和高质量。

CC1239777的博客 570

梦幻西游端游脚本开发实战:从易语言到大漠多线程全解析

本文详细解析了梦幻西游端游脚本开发的全流程,从易语言基础入门到大漠插件多线程实战。重点介绍了易语言中文编程优势、大漠插件图色识别技术,以及多线程控制台开发技巧,帮助开发者高效实现游戏自动化,提升脚本稳定性和执行效率。

weixin_29251567的博客 1060

Unity Shader多Pass机制详解:从原理到实战应用

在计算机图形学中,渲染管线是决定三维场景如何转换为二维图像的核心流程。其原理基于GPU对顶点和片元的逐层处理,通过深度测试、混合等操作实现复杂视觉效果。这一技术价值在于能够突破单次渲染的限制,实现透明物体、描边、多光源等高级渲染特性。在游戏开发与实时图形应用场景中,Unity引擎的ShaderLab框架通过SubShader与Pass的层级结构,为开发者提供了灵活的渲染控制能力。其中,多Pass机制允许同一物体被多次渲染,通过精心设计的渲染状态(如ZWrite、Blend、Cull)与帧缓冲交互,能够高效实

diankui6178的博客 480

软件项目管理期末复习(看这一篇就够了)

软件项目管理考试复习 🔶🔶🔶🔶🔶加了🔶的是考点 第一章软件项目管理概述 1.1.1项目及其特征 项目定义:🔶 项目就是为了创造一个唯一的产品或提供一个唯一的服务而进行的临时性的努力; 是以一套独特而互相联系的任务为前提,有效地利用资源,在一段时间内满足一系列特定目标的多项相关工作的总称。 日常运作和项目的区别: 项目是一次性的,而日常运作是重复进行的。 项目是以目标为导向的,日常运作是通过效率和有效性体现的。 项目是通过项目经理及其团队工作完成的,日常运作是职能式的线性管理。 项目存在大量的变更管理,

qq_50886857的博客 3万+

Unity Shader入门教程(八) :透明以及半透明效果

在Unity中一般使用两种方式来实现透明效果,即透明度测试和透明度混合。 透明度测试:使用透明度测试只会产生2种结果,要么完全透明,要么完全不透明。原因是只要一个片元的透明度不满足条件(一般是小于某个阈值),那么它对应的片元就会被舍弃。被舍弃的片元将不会再进行任何处理,也不会对颜色缓冲产生任何影响;否则,就会按照普通的不透明物体的处理方式来处理它,即进行深度测试,深度写入等。也就是说,透明度测试...

qq_34818497的博客 2791

统信UOS系统盘扩容保姆级教程:用GParten-分区编辑器5分钟搞定

本文提供统信UOS系统盘扩容的详细图形化教程。针对系统盘空间不足问题,重点介绍如何使用系统自带的GParten-分区编辑器,在5-10分钟内安全、直观地完成扩容操作,无需记忆复杂命令,适合所有用户快速解决存储空间告急的困扰。

e3f4g5的博客 640

智能汽车嘚啵嘚 --- 智能座舱第七稿:智能座舱的升级OTA

智能汽车嘚啵嘚 --- 智能座舱第七稿:智能座舱的升级OTA

Soly_kun的博客 414

半透明物体描边

【代码】半透明物体描边。

qq_22012149的博客 368

【原创】关于西门子S120 的电气图纸设计

我们首先要了解一下模块的基本信息:SINAMICS 功率模块 PM240-2 三相交流380-480V+10/-10% 47-63Hz;至此,我们选择的驱动系统配置的资料都已经查找完毕,接下来就是根据每个部件的功能接口和我们需要实现的功能画出接线连接图,这样关于伺服电机控制,硬件部分设计就完成了。2)FSA - FSC 型功率模块 PM240-2 的屏蔽连接板外形尺寸图,所有数据以毫米(英寸)为单位。1)FSA 型功率模块 PM240-2 的外形尺寸图,所有数据以毫米(英寸)为单位。

Qinmingyue13的博客 2638

【渲染流水线】[逐片元阶段]-[深度写入]以UnityURP为例

本文探讨Unity URP渲染管线中的深度写入机制,重点解析ZWriteOn/Off状态对渲染效果的影响。深度缓冲区通过比较像素深度值实现遮挡计算,ZWriteOn适用于不透明物体确保正确遮挡,ZWriteOff则用于半透明物体避免错误遮挡。文章详细介绍了URP中深度写入的技术原理、发展历程和典型应用场景,包括标准不透明物体渲染、半透明物体的深度预写入技术,以及水体效果的深度交互实现。通过Shader代码示例展示了如何在不同场景下配置深度写入状态,为游戏渲染开发提供实用参考。

设计 AI 玩游戏🎮 937

观测器选择与工程实践建议

摘要:永磁同步电机(PMSM)无传感器控制中,观测器选型需综合考虑应用场景、性能需求与成本。消费级(家电、工具)推荐滑模观测器(SMO),成本低、鲁棒性强;工业级(伺服、泵阀)适用扩展卡尔曼滤波器(EKF),精度高但计算复杂;车规级(EPS、主驱动)需混合观测器(SMO+EKF),兼顾全速域性能与可靠性。低速时需高频注入法,IPMSM更适用。SMO易实现但存在抖振,EKF调试复杂。未来趋势是混合架构与AI增强,提升适应性与性能。选型需权衡速度范围、电机类型、处理器能力及成本。

汽车软件开发 145

基于STM32、HAL库的GZP6816D气压传感器 驱动程序设计

测量范围:0-16kPa(可根据型号不同有变化)工作电压:1.8V-3.6V。高精度:±1% FS。

corlin6688的博客 217
上一篇: Unity SetPassCall和DrawCall的区别是什么
下一篇: Unity Shader 使用Matcap+Ramp 制作薄膜蝉翼甲壳虫
mxwin
博客等级 码龄19年 22粉丝 151原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值