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

Unity顶点位移Shader无效:平面始终平坦问题求助

Unity顶点位移Shader无效果,平面始终平坦的问题修复

问题描述

尝试实现海洋顶点位移Shader,但平面始终保持平坦,Shader无任何位移效果。已排查材质与平面的关联、GPU实例化开关,均无改善。

原Shader代码

Shader "Custom/Waves"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
        _NormalMap ("Normal Map", 2D) = "bump" {}

        //Wave Properties
        _Direction("Direction", Vector) = (1.0, 0.0, 0.0, 1.0)
        _Steepness("Steepness", Range(0.1,1.0)) = 0.5
        _Freq("Frequency", Range(1.0,10.0)) = 1.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;


        float _Steepness, _Freq;
        float4 _Direction;
        struct Input
        {
            float2 uv_MainTex;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
        // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
        // #pragma instancing_options assumeuniformscaling
        UNITY_INSTANCING_BUFFER_START(Props)
            // put more per-instance properties here
        UNITY_INSTANCING_BUFFER_END(Props)

        void vert(inout appdata_full v){   
            float3 pos = v.vertex.xyz;
            float4 dir = normalize(_Direction);
            float defaultWavelength = 2 * UNITY_PI;
            float wL = defaultWavelength / _Freq;
            float phase = sqrt(9.8/wL);
            float disp = wL * (dot(dir, pos) - (phase * _Time.y));
            float peak = _Steepness/wL;
            pos.x += dir.x * (peak * cos(disp));
            pos.y = peak * sin(disp);
            pos.z += dir.y * (peak * cos(disp));
            v.vertex.xyz = pos;
        }

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

Unity场景截图

Unity截图

问题根源与修复方案

  1. 核心问题:顶点函数未绑定到Surface Shader
    原Shader中,#pragma surface指令没有指定自定义顶点函数,导致vert方法完全不会被执行。需要修改为:

    #pragma surface surf Standard fullforwardshadows vertex:vert
    
  2. 方向向量错误修正

    • _Direction是三维方向,使用float3类型更合理,避免w分量干扰
    • 原代码中pos.z += dir.y是错误的,应该使用dir.z来控制z轴方向的位移
  3. 其他细节优化

    • 明确重力加速度的含义,添加注释
    • 确保顶点位移的计算逻辑符合波浪公式

修正后的完整Shader代码

Shader "Custom/Waves"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
        _NormalMap ("Normal Map", 2D) = "bump" {}

        //Wave Properties
        _Direction("Direction", Vector) = (1.0, 0.0, 1.0, 0.0)
        _Steepness("Steepness", Range(0.1,1.0)) = 0.5
        _Freq("Frequency", Range(1.0,10.0)) = 2.0
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 200

        CGPROGRAM
        // 绑定自定义顶点函数vert
        #pragma surface surf Standard fullforwardshadows vertex:vert

        #pragma target 3.0

        sampler2D _MainTex;

        float _Steepness, _Freq;
        float3 _Direction;

        struct Input
        {
            float2 uv_MainTex;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        UNITY_INSTANCING_BUFFER_START(Props)
        UNITY_INSTANCING_BUFFER_END(Props)

        void vert(inout appdata_full v){   
            float3 pos = v.vertex.xyz;
            // 归一化三维方向向量
            float3 dir = normalize(_Direction);
            // 基础波长为2π,根据频率计算实际波长
            float wL = 2 * UNITY_PI / _Freq;
            // 波浪传播速度(基于重力加速度9.8m/s²)
            float phaseSpeed = sqrt(9.8 / wL);
            // 位移计算因子
            float dispFactor = dot(dir, pos) - phaseSpeed * _Time.y;
            float disp = wL * dispFactor;
            // 波浪振幅
            float amplitude = _Steepness / wL;

            // 计算顶点位移
            pos.x += dir.x * amplitude * cos(disp);
            pos.y = amplitude * sin(disp);
            pos.z += dir.z * amplitude * cos(disp);

            v.vertex.xyz = pos;
        }

        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

额外验证步骤

  • 增加平面细分:平面默认分段数太少,顶点不足会导致波浪效果不明显。创建平面时提高Width Segments和Height Segments,或给平面添加Subdivision Surface组件增加细分等级。
  • 调整参数:建议将_Freq设为2-5,_Steepness设为0.5-0.8,_Direction设为(1,0,1)可以看到斜向波浪。

内容的提问来源于stack exchange,提问作者BaguetteDeP1

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 14:35:17