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

Unity中如何实现瓶子旋转时水位的真实动态变化?

实现旋转瓶子时的动态水位效果

一、Shader方案(推荐)

核心是通过Shader根据瓶子旋转角度计算倾斜液面,结合遮罩确保水只在瓶内显示,兼顾性能与真实效果:

  • 步骤1:给瓶子Sprite添加Sprite Mask组件,将水位Sprite的Mask Interaction设置为Visible Inside Mask,限制水的显示范围在瓶子内部。
  • 步骤2:使用以下自定义Shader替换水位Sprite的材质,实现随角度变化的液面裁剪:
Shader "Custom/WaterLevel" {
    Properties {
        _MainTex ("Texture", 2D) = "white" {}
        _WaterHeight ("Water Height", Range(0,1)) = 0.5
        _Rotation ("Bottle Rotation", Float) = 0
    }
    SubShader {
        Tags { "Queue"="Transparent" "RenderType"="Transparent" }
        Blend SrcAlpha OneMinusSrcAlpha
        Cull Off ZWrite Off

        Pass {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

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

            struct v2f {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float4 worldPos : TEXCOORD1;
            };

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _WaterHeight;
            float _Rotation;

            v2f vert (appdata v) {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                return o;
            }

            fixed4 frag (v2f i) : SV_Target {
                // 基于瓶子中心计算倾斜液面
                float2 center = float2(0,0);
                float angleRad = radians(_Rotation);
                float2 dir = float2(cos(angleRad), sin(angleRad));
                float2 offset = i.worldPos.xy - center;
                float proj = dot(offset, dir);
                float maxProj = _WaterHeight * 2; // 适配0-1的高度范围
                // 液面上方的像素直接透明
                if (proj > maxProj) {
                    discard;
                }
                fixed4 col = tex2D(_MainTex, i.uv);
                return col;
            }
            ENDCG
        }
    }
}
  • 步骤3:挂载以下脚本,实时传递瓶子的旋转角度和水位高度给Shader:
using UnityEngine;

public class WaterLevelController : MonoBehaviour
{
    public SpriteRenderer bottleRenderer;
    public Material waterMaterial;
    public float waterFillAmount = 0.5f; // 0为空,1为满

    void Update()
    {
        // 传递瓶子Z轴旋转角度
        waterMaterial.SetFloat("_Rotation", bottleRenderer.transform.eulerAngles.z);
        // 传递水位填充比例
        waterMaterial.SetFloat("_WaterHeight", waterFillAmount);
    }
}

二、非Shader替代方案(快速原型)

若不想编写Shader,可通过Mesh变形模拟液面:

  • 将水位Sprite转换为Mesh(右键Sprite -> Convert to Mesh),添加Mesh Filter和Mesh Renderer组件。
  • 编写脚本,根据瓶子旋转角度遍历Mesh顶点,调整液面区域的顶点Y坐标,模拟倾斜效果。
  • 同样配合Sprite Mask限制显示范围。
  • 缺点:性能略差,效果精度依赖Mesh顶点数量,仅适合简单瓶型。

三、物理小球方案优化

若想继续使用小球模拟,解决穿透问题:

  • 给瓶子添加Polygon Collider 2D,手动编辑碰撞体顶点,完全贴合瓶身Sprite轮廓。
  • 给小球的Rigidbody 2D开启Continuous Collision Detection,避免高速移动穿透。
  • 降低小球的Linear Velocity,增加物理材质的Friction和Bounciness,减少异常运动。

所需效果参考:旋转瓶子后,液面呈倾斜状,贴合瓶内底部,符合重力方向
现有效果参考:旋转瓶子后,液面仍保持水平,未随瓶子角度变化

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 06:05:27