您现在的位置是:首页 >学无止境 >Unity:圆底烧瓶中液体液面升降变化的效果网站首页学无止境

Unity:圆底烧瓶中液体液面升降变化的效果

dzj2021 2024-06-20 00:01:02
简介Unity:圆底烧瓶中液体液面升降变化的效果

一、效果展示

请添加图片描述

二、实现的原理

1、从image的filled模式说起

image的filled模式,适合用来做进度条:
在这里插入图片描述
请添加图片描述

2、能否为一个3D object实现一个image filled 的shader ?

Shader "Custom/FilledImageEffect"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _Color ("Color", Color) = (1, 1, 1, 1)
        _FillAmount ("Fill Amount", Range(0, 1)) = 1
    }

    SubShader
    {
        Tags {"Queue"="Transparent" "RenderType"="Transparent"}
        LOD 100

        CGPROGRAM
        #pragma surface surf Lambert

        sampler2D _MainTex;
        float4 _Color;
        float _FillAmount;

        struct Input
        {
            float2 uv_MainTex;
        };

        void surf (Input IN, inout SurfaceOutput o)
        {
            float2 uv = IN.uv_MainTex;
            float4 c = tex2D(_MainTex, uv) * _Color;

            if (uv.x > _FillAmount)
            {
                c.a = 0;
            }

            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

三、服用方法

  • 1、创建一个液面效果的材质
    在这里插入图片描述

  • 2、把这个材质挂载到瓶子中的【液体】模型上

  • 3、在面板上拖动FillAmout

  • 4、在脚本中设置mat的该属性
    mat.SetFloat(“_FillAmount”, currentValue);

四、附录:C#调用代码

1、液面升降动画的异步方法

/// <summary>
/// 容器的液面变化:化学实验中,量筒中倒入液体或者被吸取液体后,液面会升降
/// 材质用shader,控制其fillAmout参数
/// </summary>
/// <param name="mat">操作的材质</param>
/// <param name="levelStart">起始液面位置</param>
/// <param name="levelEnd">结束页面位置</param>
/// <param name="duration">动画的时间</param>
/// <returns></returns>
public static async UniTask DoLiquidLevel(Material mat, float levelStart, float levelEnd, float duration)
{
    float currentValue = levelStart;
    float timeElapsed = 0f;
    while (timeElapsed < duration)
    {
        currentValue = Mathf.Lerp(levelStart, levelEnd, timeElapsed / duration);
        Debug.Log(currentValue);
        mat.SetFloat("_FillAmount", currentValue);      //变量名字确保与Shader源码中的变量一致。
        await UniTask.Yield();
        timeElapsed += Time.deltaTime;
    }
    mat.SetFloat("_FillAmount", levelEnd);              //确保最终结果准确
}

2、monobehaviour示例脚本

using System;
using Cysharp.Threading.Tasks;
using UnityEngine;
using static txlib;//包含 DoLiquidLevel()

/// <summary>
/// 容器的液面升降控制
/// </summary>
public class ChangeLiquidLevel : MonoBehaviour
{
    /// <summary>
    /// 物体
    /// </summary>
    public GameObject obj;

    /// <summary>
    /// 起始液面
    /// </summary>
    public float levelStart;

    /// <summary>
    /// 终止液面
    /// </summary>
    public float levelEnd;

    /// <summary>
    /// 动画耗时
    /// </summary>
    public float duration;
    
    /// <summary>
    /// 材质
    /// </summary>
    private Material mat;

    [ContextMenu("测试液面")]
    async UniTask Test()
    {
        mat = obj.GetComponent<Renderer>().sharedMaterial;
        while (true)
        {
            await DoLiquidLevel(mat, levelStart, levelEnd, duration);
            await DoLiquidLevel(mat, levelEnd, levelStart, duration);
            await UniTask.Delay(TimeSpan.FromSeconds(0.8f));
        }
    }
}

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。