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
相关产品推荐
相关产品推荐

