You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 04:39:19