透明渲染方式下的渲染顺序问题

 

项目中的角色的眉毛处是可以替换的,所以美术会把角色的模型处做上睫毛的顶点。

这样是为了方便表现睫毛的形状。然后用替换睫毛贴图到角色身上来做成睫毛的更换,并且睫毛在没内容的地方做透明处理就能显示处正常的睫毛。

但是如果我们直接替换睫毛上去其实并不能看到正确的效果,因为睫毛是身体一部分,然后身体上的睫毛这部分是透明的,所以看到的是透明的效果

所以我们需要修改下身体的shader。

 

在输出颜色前设置他的透明度。这里解释下,如果是身体本身贴图是透明的并且睫毛的透明度大于0说明这里要显示睫毛,则设置为睫毛的透明度。其他就不需要解释了。

得到的效果如下:

ok,看上去已经成功了。

但是跑起来并且装扮上头发之后得到的效果是(前提说明,头发的shader和身体的shader是两个shader,并且两个shader都是用的不透明渲染方式)

 

这里我思考了一段时间为什么得到这个效果。因为我们用到的管线是lwrp的,然后从管线代码看,其实没有任何问题,都是正常的渲染每个相机对他做前向渲染

然后看shader中是否是blend导致的效果,然后发现其实也不是,角色的身体先混合,所以没有这个问题。

 

然后换衣是不是AlphaDiscard影响的,隐藏了也没用,因为AlphaDiscard也是对自身的透明度处理,并不会夸drawcall处理

 

后来发现了一个问题,就是渲染顺序,前面也说了,我们用的是不透明渲染方式。

不透明渲染方式有个特点就是越靠近相机越先渲染(当然可以控制渲染顺序),然后前面渲染的像素在后面渲染的内容上是不进行渲染的(也就是如果前面在像素a有像素的,这个像素看上去无论透不透明,后面渲染的物体都不能在这个像素上有内容了)。

 

然后我看了下framedebbug发现

 

头发是在身体后渲染的。然后又根据我们前面表粗体字的论点,可以得知身体上就算是透明的也不会在头发shader上渲染。所以我们可以看到他的睫毛透明处透到背景的效果

知道原因解决办法就有了:

解决办法1:可以用透明度渲染来解决,天生没这个问题

解决办法2:调换两个shader的顺序,因为他们都有深度测试,所以还是会正常显示先后。

 

最终我选择的是方法2,然后就得到了正常的渲染效果了

总结:

1.如果睫毛先渲染,因为是深度写入,所以睫毛先写入了深度中,然后头发再渲染,头发在睫毛这块区域比睫毛深度低,我们正常渲染是ZTest为大于等于的,所以头发的颜色不能写入。所以出现了显示不出睫毛部分的颜色的问题。

2.如果头发先渲染,因为深度写入,所以头发的颜色写入深度中,然后睫毛渲染,又因为我们是透明渲染顺序("Queue" = "Transparent")所以睫毛会叠加再头发上面,所以头发和睫毛都能正常显示。

 

### Unity 中透明渲染的实现方法 在 Unity 的渲染流程中,透明物体的处理是一个较为复杂的过程。由于透明物体通常依赖于其与其他物体之间的相对顺序来正确显示效果,因此需要特别注意渲染顺序 Alpha 融合的技术细节。 #### 1. 渲染队列 (Render Queue) Unity 使用渲染队列来控制对象的绘制顺序。默认情况下,透明物体被分配到 `Transparent` 队列中[^1]。此队列中的物体按照距离摄像机的距离从远到近依次渲染,从而确保透明效果能够正确叠加。然而,在某些特殊场景下(例如重叠较多的透明物体),仅依靠距离排序可能无法完全解决问题。 ```csharp // 设置材质的渲染队列为 Transparent Material material = new Material(Shader.Find("Custom/TransparentShader")); material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent; ``` #### 2. Alpha 测试 (Alpha Testing / Alpha Cutout) 当不需要半透明效果时,可以使用 Alpha 测试剔除部分像素。这种方法不会引入额外的深度冲突问题,但在 MSAA 下可能会出现问题,可以通过启用 `Alpha To Coverage` 来缓解这一情况[^3]。 ```hlsl // HLSL Shader Code Example for Alpha Test clip(tex.a - _Cutoff); ``` #### 3. 半透明融合 (Transparency Blending) 对于真正的半透明效果,需开启颜色缓冲区写入并禁用深度写入,同时保持深度测试以避免不必要的遮挡错误。以下是典型的 Alpha 融合配置: - **源因子**: `SrcAlpha` - **目标因子**: `OneMinusSrcAlpha` ```hlsl Blend SrcAlpha OneMinusSrcAlpha ZWrite Off ``` 这种模式虽然简单有效,但由于缺乏精确的排序机制,可能导致渲染伪影(如鬼影效应)。为了减少此类问题的发生,开发者应尽可能优化几何结构设计,并合理调整模型间的层次关系[^4]。 #### 4. 屏幕空间技术 (Screen Space Techniques) 针对大量动态变化的粒子系统或其他高密度透明体集合,可考虑采用屏幕空间算法代替传统逐三角形渲染方式。例如,基于图像后期处理的方法能显著降低性能开销的同时改善视觉质量。 --- ### 常见问题及解决方案 | **问题** | **原因分析** | **解决办法** | |----------|--------------|---------------| | 深度冲突 (Z-Fighting)| 不同透明面片之间存在微小深度差异导致闪烁现象 | 明确指定前后次序;或者改用更高级别的排序策略比如 Dithering 或 Order Independent Transparency | | 过多Draw Calls影响效率 | 每帧频繁切换状态造成资源浪费 | 合批相似属性的对象;利用 GPU Instancing 技术提升吞吐量 | | 边缘锯齿明显 | 默认抗锯齿方案难以兼顾透明区域平滑需求 | 开启 Multi-Sample Anti-Aliasing(MSAA),配合 Alpha-to-Coverage 功能 | --- ### 示例代码片段 以下展示了一个基础版本支持透明度映射的标准表面着色器定义: ```hlsl Shader "Custom/BasicTransparent" { Properties { _MainTex ("Texture", 2D) = "white" {} _Color ("Tint Color", Color) = (1,1,1,1) } SubShader { Tags { "Queue"="Transparent" "RenderType"="Opaque" } Pass { CGPROGRAM #pragma vertex vert #pragma fragment frag fixed4 _Color; sampler2D _MainTex; struct appdata_t { float4 vertex : POSITION; float2 uv : TEXCOORD0; }; struct v2f { float2 uv : TEXCOORD0; float4 vertex : SV_POSITION; }; v2f vert(appdata_t IN){ v2f OUT; OUT.vertex = UnityObjectToClipPos(IN.vertex); OUT.uv = IN.uv; return OUT; } fixed4 frag(v2f IN):SV_Target{ fixed4 col = tex2D(_MainTex,IN.uv)*_Color; clip(col.a - 0.01); // Optional: Add alpha cutoff here. return col; } ENDCG } } } ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值