Shader教程法线渲染异常:全黑屏幕问题求助
问题排查与解决方案
1. 代码逻辑错误:提前返回导致法线判断失效
你的片段着色器中,计算完edgeNormal后直接执行return edgeNormal;,不仅跳过了后续深度逻辑,更关键的是:如果edgeNormal计算结果始终为0,就会输出全黑画面。先移除这个提前返回,或者确保edgeNormal能正确生成非零值。
2. 法线纹理未解码到有效范围
Unity的_CameraNormalsTexture默认将视图空间法线编码到[0,1]区间,而计算法线差值需要使用[-1,1]的原始法线数据。必须对采样得到的法线进行解码转换:
// 采样后立即解码法线 float3 normal0 = SAMPLE_TEXTURE2D(_CameraNormalsTexture, sampler_CameraNormalsTexture, bottomLeftUV).rgb; normal0 = 2.0 * normal0 - 1.0; // 转换到[-1,1]范围 float3 normal1 = SAMPLE_TEXTURE2D(_CameraNormalsTexture, sampler_CameraNormalsTexture, topRightUV).rgb; normal1 = 2.0 * normal1 - 1.0; float3 normal2 = SAMPLE_TEXTURE2D(_CameraNormalsTexture, sampler_CameraNormalsTexture, bottomRightUV).rgb; normal2 = 2.0 * normal2 - 1.0; float3 normal3 = SAMPLE_TEXTURE2D(_CameraNormalsTexture, sampler_CameraNormalsTexture, topLeftUV).rgb; normal3 = 2.0 * normal3 - 1.0;
3. 检查相机深度纹理配置
Unity新版本(尤其是URP/HDRP管线)中,必须手动开启相机的法线纹理采集:
- 选中场景主相机,在Inspector面板找到Depth Texture Mode
- 设置为
Depth and Normals - 若使用URP,还需在URP Asset的
Rendering设置中确认Depth Texture和Normals Texture已启用
4. 调整法线阈值参数
_NormalThreshold如果设置过高,会导致edgeNormal始终为0(全黑)。建议先将阈值调低至0.1~0.3区间测试效果。
修改后的核心代码片段
float4 Frag(VaryingsDefault i) : SV_Target { float halfScaleFloor = floor(_Scale * 0.5); float halfScaleCeil = ceil(_Scale * 0.5); float2 bottomLeftUV = i.texcoord - float2(_MainTex_TexelSize.x, _MainTex_TexelSize.y) * halfScaleFloor; float2 topRightUV = i.texcoord + float2(_MainTex_TexelSize.x, _MainTex_TexelSize.y) * halfScaleCeil; float2 bottomRightUV = i.texcoord + float2(_MainTex_TexelSize.x * halfScaleCeil, -_MainTex_TexelSize.y * halfScaleFloor); float2 topLeftUV = i.texcoord + float2(-_MainTex_TexelSize.x * halfScaleFloor, _MainTex_TexelSize.y * halfScaleCeil); // 采样并解码法线 float3 normal0 = SAMPLE_TEXTURE2D(_CameraNormalsTexture, sampler_CameraNormalsTexture, bottomLeftUV).rgb; normal0 = 2.0 * normal0 - 1.0; float3 normal1 = SAMPLE_TEXTURE2D(_CameraNormalsTexture, sampler_CameraNormalsTexture, topRightUV).rgb; normal1 = 2.0 * normal1 - 1.0; float3 normal2 = SAMPLE_TEXTURE2D(_CameraNormalsTexture, sampler_CameraNormalsTexture, bottomRightUV).rgb; normal2 = 2.0 * normal2 - 1.0; float3 normal3 = SAMPLE_TEXTURE2D(_CameraNormalsTexture, sampler_CameraNormalsTexture, topLeftUV).rgb; normal3 = 2.0 * normal3 - 1.0; float3 normalFiniteDifference0 = normal1 - normal0; float3 normalFiniteDifference1 = normal3 - normal2; float edgeNormal = sqrt(dot(normalFiniteDifference0, normalFiniteDifference0) + dot(normalFiniteDifference1, normalFiniteDifference1)); edgeNormal = edgeNormal > _NormalThreshold ? 1 : 0; // 深度逻辑(可选,结合法线生成最终轮廓) float depth0 = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_CameraDepthTexture, bottomLeftUV).r; float depth1 = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_CameraDepthTexture, topRightUV).r; float depth2 = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_CameraDepthTexture, bottomRightUV).r; float depth3 = SAMPLE_DEPTH_TEXTURE(_CameraDepthTexture, sampler_CameraDepthTexture, topLeftUV).r; float depthFiniteDifference0 = depth1 - depth0; float depthFiniteDifference1 = depth3 - depth2; float edgeDepth = sqrt(pow(depthFiniteDifference0, 2) + pow(depthFiniteDifference1, 2)) * 100; edgeDepth = edgeDepth > _DepthThreshold ? 1 : 0; float edge = max(edgeDepth, edgeNormal); return edge; }
内容的提问来源于stack exchange,提问作者Xia
相关产品推荐
相关产品推荐

