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

如何修改Unity果冻Shader使其持续生效,解决远距离失效、移动卡顿问题

果冻Shader问题修复方案

问题根源说明

  • 距离过远失效:原Shader采用世界空间计算顶点和波动原点的距离,物体远离初始设置的_ImpactOrigin后,距离值过大导致1/dist趋近于0,顶点偏移量直接归零,看起来就是Shader停止工作。同时你将_ModelOrigin和_ImpactOrigin设为几乎重合的位置,方向计算容易出现浮点精度错误,也会导致效果异常。
  • 移动时卡顿:你调用modelRenderer.material时每次都会生成新的材质实例,频繁赋值会触发重复的内存分配和渲染状态切换,导致卡顿。

修复步骤

1. Shader修改

主要优化点:

  • 内置获取物体自身原点,无需外部传入_ModelOrigin
  • 波动计算改为模型本地空间,不受世界坐标位置影响,不会出现距离过远失效问题
  • 默认使用Unity内置时间参数_Time,无需外部传入_ControlTime
  • 固定默认的波动方向偏移,避免两个原点重合导致的精度问题

修改后的完整Shader代码如下:

// Upgrade NOTE: upgraded instancing buffer 'Props' to new syntax.

Shader "Custom/JellyShader" {
    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
        _Transparency("Transparency", float) = 0.1

        _LocalImpactOffset("本地波动偏移", Vector) = (0.1, 0.1, 0.1, 0)
        _UseExternalParams("启用外部参数控制", Range(0,1)) = 0
        _ControlTime("Time", float) = 0
        _ModelOrigin("Model Origin", Vector) = (0,0,0,0)
        _ImpactOrigin("Impact Origin", Vector) = (-5,0,0,0)

         _Emission("Emission", float) = 0
         [HDR] _EmissionColor("Color", Color) = (0,0,0)


        _Frequency("Frequency", Range(0, 1000)) = 10
        _Amplitude("Amplitude", Range(0, 5)) = 0.1
        _WaveFalloff("Wave Falloff", Range(1, 8)) = 4
        _MaxWaveDistortion("Max Wave Distortion", Range(0.1, 2.0)) = 1
        _ImpactSpeed("Impact Speed", Range(0, 10)) = 0.5
        _WaveSpeed("Wave Speed", Range(-10, 10)) = -5
    }
        SubShader{
            Tags { "Queue" = "Transparent" "RenderType" = "Transparent" }
            LOD 200

            CGPROGRAM
            // Physically based Standard lighting model, and enable shadows on all light types
            #pragma surface surf Standard fullforwardshadows addshadow vertex:vert alpha:fade

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

            sampler2D _MainTex;

            struct Input {
                float2 uv_MainTex;
            };

            half _Glossiness;
            half _Metallic;
            fixed4 _Color;

            fixed4 _EmissionColor;

            float _UseExternalParams;
            float _ControlTime;
            float4 _ModelOrigin;
            float4 _ImpactOrigin;
            float4 _LocalImpactOffset;
            float _Transparency;

            half _Frequency; //Base frequency for our waves.
            half _Amplitude; //Base amplitude for our waves.
            half _WaveFalloff; //How quickly our distortion should fall off given distance.
            half _MaxWaveDistortion; //Smaller number here will lead to larger distortion as the vertex approaches origin.
            half _ImpactSpeed; //How quickly our wave origin moves across the sphere.
            half _WaveSpeed; //Oscillation speed of an individual wave.


            // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
            UNITY_INSTANCING_BUFFER_START(Props)
                // put more per-instance properties here
            UNITY_INSTANCING_BUFFER_END(Props)

            void vert(inout appdata_base v) {
                float4 modelOriginWorld = float4(unity_ObjectToWorld[0].w, unity_ObjectToWorld[1].w, unity_ObjectToWorld[2].w, 1);
                float4 impactOriginWorld = _UseExternalParams ? _ImpactOrigin : modelOriginWorld + _LocalImpactOffset;
                float4 direction = normalize(modelOriginWorld - impactOriginWorld);
                float time = _UseExternalParams ? _ControlTime : _Time.y;
                float4 origin = impactOriginWorld + time * _ImpactSpeed * direction;

                float4 world_space_vertex = mul(unity_ObjectToWorld, v.vertex);
                //Get the distance in model space to avoid distance decay in world space
                float dist = distance(v.vertex, mul(unity_WorldToObject, origin));

                //Adjust our distance to be non-linear.
                dist = pow(dist, _WaveFalloff);

                //Set the max amount a wave can be distorted based on distance.
                dist = max(dist, _MaxWaveDistortion);

                //Convert direction and _ImpactOrigin to model space for later trig magic.
                float4 l_ImpactOrigin = mul(unity_WorldToObject, impactOriginWorld);
                float4 l_direction = mul(unity_WorldToObject, direction);

                //Magic
                float impactAxis = l_ImpactOrigin + dot((v.vertex - l_ImpactOrigin), l_direction);

                v.vertex.xyz += v.normal * sin(impactAxis * _Frequency + time * _WaveSpeed) * _Amplitude * (1 / dist);
            }

            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;
                o.Emission = c.rgb * tex2D(_MainTex, IN.uv_MainTex).a * _EmissionColor;
                o.Smoothness = _Glossiness;
            }
            ENDCG
        }
            FallBack "Diffuse"
}

2. C#代码优化(可选,仅需外部控制时使用)

如果不需要动态修改参数,Shader默认状态下就可以直接运行,无需任何C#代码赋值。如果需要外部控制,使用MaterialPropertyBlock避免创建材质实例,消除卡顿:

private MaterialPropertyBlock mpb;
private Renderer modelRenderer;

void Start()
{
    mpb = new MaterialPropertyBlock();
    modelRenderer = GetComponent<Renderer>();
    // 开启外部参数控制,不需要的话可以省略这部分
    mpb.SetFloat("_UseExternalParams", 1);
}

void Update()
{
    // 仅在参数需要变更时赋值,不要每帧都调用
    mpb.SetVector("_ModelOrigin", transform.position);
    mpb.SetVector("_ImpactOrigin", transform.position + new Vector3(0.001f, 0.001f, 0.001f));
    mpb.SetFloat("_ControlTime", Time.time);
    modelRenderer.SetPropertyBlock(mpb);
}

效果验证

修改后不管物体移动到世界坐标的哪个位置,果冻效果都会始终生效,也不会出现移动时的卡顿问题。可以调整面板上的本地波动偏移参数修改抖动方向,不需要修改代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 21:57:03