我不是歪神 2025-08-06 19:20 采纳率: 66.7%
浏览 10
已结题

unityshader效果错误

img


第一份是正确的效果,是用shadergraph做的获取水深材质,shadergraph节点如下

img

img

img

第二个是错误的效果,推测是采样贴图的问题,但折腾了两天两夜也没找到哪的问题

img

以下是代码部分,感谢大家帮助了qwq

Shader "Game/Water"
{
    Properties
    {
        [HideInInspector]
        _Gradient("Gradient",2D) = "black"{}
        _Depth("Depth",Range(0.001,100)) = 4
        _HorizonDistance("HorizonDistance",float) = 10
        _HorizonColor("HorizonColor",Color) = (0.5176471,0.4509804,0.5960785,0)
        _RefractionScale("RefractionScale",float) = 0.5
        _RefractionSpeed("RefractionSpeed",float) = 0.05
        _RefractionStrength("RefractionStrength",float) = 0.1
        _FoamColor("FoamColor",Color) = (0.6588235,0.9019608,0.8117647,0.8)
        _FoamDepth("FoamDepth",float) = 3
        _FoamSpeed("FoamSpeed",float) = 0.02
        _FoamOffset("FoamOffset",float) = 100
        _FoamScale("FoamScale",float) = 0.4
        _FoamSeed("FoamSeed",float) = 0
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" 
                "RenderPipeline"="UniversalRenderPipeline" }
        
        LOD 100
        Pass
        {

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include"UnityCG.cginc"

            float _Depth;
            float _HorizonDistance;
            float4 _HorizonColor;
            float _RefractionScale;
            float _RefractionSpeed;
            float _RefractionStrength;
            float4 _FoamColor;
            float _FoamDepth;
            float _FoamSpeed;
            float _FoamOffset;
            float _FoamScale;
            float _FoamSeed;
            sampler2D _Gradient;
            float4 _Gradient_TexelSize;

            uniform sampler2D _CameraDepthTexture;


            struct VertexInput
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct VertexOutput
            {
                float4 vertex : SV_POSITION;
                float2 uv : TEXCOORD0;

                float4 ScreenPos : TEXCOORD1;
                float4 WorldPos : TEXCOORD2;
            };

            float GetSceneDepth_Eye(VertexOutput i , float2 uv)
            {
                float2 screenUV = uv;
                return LinearEyeDepth(tex2D(_CameraDepthTexture,screenUV));
            }

            float4 GetScreenPos_Default(VertexOutput i)
            {
                return float4(i.ScreenPos.xy / i.ScreenPos.w,0,0);
            }

            float3 GetViewVectorInv_World(VertexOutput i)
            {
                return i.WorldPos - _WorldSpaceCameraPos;
            }

            float4 GetScreenPos_Raw(VertexOutput i)
            {
                return i.ScreenPos;
            }

            float2 GetScaleUV(float2 uv)
            {
                float2 scaleUV;
                scaleUV = uv * float2(
                    length(unity_ObjectToWorld[0].xyz),
                    length(unity_ObjectToWorld[2].xyz)
                    );
                return scaleUV;
            }

            float2 GradientNoiseDir(float2 p)
            {
                p = p % 289;
                float x = (34 * p.x + 1) * p.x % 289 + p.y;
                x = (34 * x + 1) * x % 289;
                x = frac(x / 41) * 2 - 1;
                return normalize(float2(x - floor(x + 0.5), abs(x) - 0.5));
            }

            float GetGradientNoise(float2 UV, float Scale)
            {
                float2 ip = floor(UV * Scale);
                float2 fp = frac(UV * Scale);
                float d00 = dot(GradientNoiseDir(ip), fp);
                float d01 = dot(GradientNoiseDir(ip + float2(0, 1)), fp - float2(0, 1));
                float d10 = dot(GradientNoiseDir(ip + float2(1, 0)), fp - float2(1, 0));
                float d11 = dot(GradientNoiseDir(ip + float2(1, 1)), fp - float2(1, 1));
                fp = fp * fp * fp * (fp * (fp * 6 - 15) + 10);
                return lerp(lerp(d00, d01, fp.y), lerp(d10, d11, fp.y), fp.x) + 0.5;
            }

            float4 GetRefractionUV(VertexOutput i)
            {
                float2 uv = GetScaleUV(i.uv);
                uv *= _RefractionScale;
                uv += _RefractionSpeed * _Time;
                float GradientNoise = GetGradientNoise(uv,20);
                GradientNoise = GradientNoise * 2 - 1;
                GradientNoise *= _RefractionStrength;
                return GetScreenPos_Default(i) + GradientNoise;
            }
            float3 GetDepthWorld(VertexOutput i , float2 uv)
            {
                float3 DepthWorld = ( i.WorldPos ) - ( _WorldSpaceCameraPos + ( (GetViewVectorInv_World(i) / GetScreenPos_Raw(i).w) * GetSceneDepth_Eye(i,uv) ) );
                return DepthWorld;
            }
            float GetDepth(VertexOutput i , float2 uv)
            {
                float Depth = saturate(exp( - GetDepthWorld(i,uv).y / _Depth ));
                return Depth;
            }

            float4 GetRefraction(VertexOutput i)
            {
                float4 RefractionUV = GetRefractionUV(i);
                float4 GetScreenPos = GetScreenPos_Default(i);
                float BranchPre = sign(GetDepthWorld(i,RefractionUV).y) / 0.5 + 0.5;
                return lerp(GetScreenPos,lerp(GetScreenPos,RefractionUV,BranchPre),GetDepth(i,RefractionUV)).y;
            }

            float4 GetGradientColor(float Time)
            {
                float4 color = tex2D(_Gradient,float2(Time ,0.25));
                return color;
            }

            VertexOutput vert(VertexInput v)
            {
                VertexOutput o;
                o.WorldPos = mul(unity_ObjectToWorld, v.vertex);
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.ScreenPos = ComputeScreenPos(o.vertex);
                o.uv = v.uv;
                return o;
            }

            float4 frag(VertexOutput i) : SV_Target
            {
                return GetDepth(i,GetRefraction(i));
            }

            ENDCG
        }
    }
}

  • 写回答

3条回答 默认 最新

  • 宝码香车 优质创作者: JavaScript技术领域 2025-08-06 19:26
    关注

    让【宝码香车】来帮您解答,本回答参考DeepSeek编写,并整理提供。

    如果答案让您满意,请采纳、点赞、关注,非常感谢!
    .  
    每日一句正能量,让它带给您好心情:内心的晴朗,能驱散所有阴霾。
    .  

    根据您提供的Shader代码和问题描述,我分析可能存在以下几个问题:

    主要问题分析

    1. 深度采样问题
    • GetSceneDepth_Eye函数中,直接使用tex2D采样深度纹理可能不正确,应该使用SAMPLE_DEPTH_TEXTURE
    • 缺少对深度纹理的声明(UNITY_DECLARE_DEPTH_TEXTURE
    1. 折射UV计算问题
    • GetRefractionUV函数返回的是float4,但在GetRefraction中被当作float2使用
    • 折射计算逻辑可能存在问题
    1. 渲染管线兼容性
    • 标签中声明了URP管线,但代码使用的是CG而不是HLSL

    修改建议

    Shader "Game/Water"
    {
        Properties
        {
            [HideInInspector] _Gradient("Gradient",2D) = "black"{}
            _Depth("Depth",Range(0.001,100)) = 4
            // 其他属性保持不变...
        }
        SubShader
        {
            Tags { 
                "RenderType"="Transparent" 
                "RenderPipeline"="UniversalRenderPipeline" 
                "Queue"="Transparent"
            }
            
            Pass
            {
                HLSLPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                
                #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
                #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/DeclareDepthTexture.hlsl"
    
    
                // 属性声明...
                TEXTURE2D(_Gradient);
                SAMPLER(sampler_Gradient);
                
                struct VertexInput
                {
                    float4 vertex : POSITION;
                    float2 uv : TEXCOORD0;
                };
    
    
                struct VertexOutput
                {
                    float4 vertex : SV_POSITION;
                    float2 uv : TEXCOORD0;
                    float4 ScreenPos : TEXCOORD1;
                    float3 WorldPos : TEXCOORD2;
                };
    
    
                float GetSceneDepth_Eye(VertexOutput i, float2 uv)
                {
                    float2 screenUV = uv;
                    return LinearEyeDepth(SampleSceneDepth(screenUV), _ZBufferParams);
                }
    
    
                // 其他函数修改为使用URP的采样方式...
    
    
                VertexOutput vert(VertexInput v)
                {
                    VertexOutput o;
                    o.WorldPos = TransformObjectToWorld(v.vertex.xyz);
                    o.vertex = TransformWorldToHClip(o.WorldPos);
                    o.ScreenPos = ComputeScreenPos(o.vertex);
                    o.uv = v.uv;
                    return o;
                }
    
    
                half4 frag(VertexOutput i) : SV_Target
                {
                    // 修改后的深度计算逻辑
                    float2 screenUV = i.ScreenPos.xy / i.ScreenPos.w;
                    float sceneDepth = GetSceneDepth_Eye(i, screenUV);
                    float surfaceDepth = i.ScreenPos.w;
                    float waterDepth = sceneDepth - surfaceDepth;
                    
                    // 应用深度和颜色渐变
                    float depthFactor = saturate(waterDepth / _Depth);
                    half4 color = SAMPLE_TEXTURE2D(_Gradient, sampler_Gradient, float2(depthFactor, 0.25));
                    
                    return color;
                }
                ENDHLSL
            }
        }
    }
    

    其他建议

    1. 调试步骤
    • 先单独输出深度值(sceneDepth)查看是否正确
    • 再单独输出水面深度(waterDepth)
    • 最后应用颜色渐变
    1. 常见问题排查
    • 确保相机开启了深度纹理(Camera.main.depthTextureMode = DepthTextureMode.Depth;)
    • 检查渐变纹理的导入设置(应该是Clamp模式)
    • 确保水面物体的渲染队列正确(Transparent)
    1. 性能优化
    • 考虑使用URP的Shader Graph重写,更直观且易于调试
    • 减少复杂噪声计算,可以预计算噪声纹理

    建议先按照URP标准修改Shader结构,确保基础深度计算正确后再添加折射等效果。如果仍有问题,可以提供更具体的错误表现(如截图对比)以便进一步分析。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

问题事件

  • 系统已结题 8月14日
  • 已采纳回答 8月6日
  • 创建了问题 8月6日