[Unity学习教程] Unity:圆底烧瓶中液体液面升降变革的结果

[复制链接]
查看1006 | 回复0 | 2023-8-23 11:55:09 | 显示全部楼层 |阅读模式 来自 中国北京
一、结果展示


二、实现的原理

1、从image的filled模式提及

image的filled模式,适适用来做进度条:


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

  1. Shader "Custom/FilledImageEffect"
  2. {
  3.     Properties
  4.     {
  5.         _MainTex ("Texture", 2D) = "white" {}
  6.         _Color ("Color", Color) = (1, 1, 1, 1)
  7.         _FillAmount ("Fill Amount", Range(0, 1)) = 1
  8.     }
  9.     SubShader
  10.     {
  11.         Tags {"Queue"="Transparent" "RenderType"="Transparent"}
  12.         LOD 100
  13.         CGPROGRAM
  14.         #pragma surface surf Lambert
  15.         sampler2D _MainTex;
  16.         float4 _Color;
  17.         float _FillAmount;
  18.         struct Input
  19.         {
  20.             float2 uv_MainTex;
  21.         };
  22.         void surf (Input IN, inout SurfaceOutput o)
  23.         {
  24.             float2 uv = IN.uv_MainTex;
  25.             float4 c = tex2D(_MainTex, uv) * _Color;
  26.             if (uv.x > _FillAmount)
  27.             {
  28.                 c.a = 0;
  29.             }
  30.             o.Albedo = c.rgb;
  31.             o.Alpha = c.a;
  32.         }
  33.         ENDCG
  34.     }
  35.     FallBack "Diffuse"
  36. }
复制代码
3、液面变革的Shader

  1. Shader "Custom/LiquidBottle"
  2. {
  3.     Properties
  4.     {
  5.         _MainTex ("Texture", 2D) = "white" {}
  6.         _MainColor("MainColor",Color) = (1, 1, 1, 1)
  7.         _TopColor("TopColor",Color) = (1, 1, 0, 1)
  8.         _FillAmount("FillAmout",Range(-1 , 2)) = 0
  9.         _EdgeWidth("EdgeWidth",Range(0 , 1)) = 0.2
  10.         _BottleWidth("BottleWidth",Range(0,1)) = 0.2
  11.         _BottleColor("BottleColor",Color) = (1,1,1,1)
  12.         _RimColor("RimColor",Color)=(1,1,1,1)
  13.         _RimWidth("RimWidth",float)=0.2
  14.     }
  15.     SubShader
  16.     {
  17.         Tags { "RenderType"="Opaque" }
  18.         LOD 100
  19.         Pass
  20.         {
  21.             Cull OFF
  22.             AlphaToMask on
  23.             //ZWrite On
  24.             Blend SrcAlpha OneMinusSrcAlpha
  25.             CGPROGRAM
  26.             #pragma vertex vert
  27.             #pragma fragment frag
  28.             // make fog work
  29.             #pragma multi_compile_fog
  30.             #include "UnityCG.cginc"
  31.             struct appdata
  32.             {
  33.                 float4 vertex : POSITION;
  34.                 float2 uv : TEXCOORD0;
  35.                 float3 normal : NORMAL;
  36.                
  37.             };
  38.             struct v2f
  39.             {
  40.                 float2 uv : TEXCOORD0;
  41.                 UNITY_FOG_COORDS(1)
  42.                 float4 vertex : SV_POSITION;
  43.                 float fillEdge : TEXCOORD1;
  44.                 float3 viewDir : COLOR;
  45.                 float3 normal : COLOR2;
  46.             };
  47.             sampler2D _MainTex;
  48.             float4 _MainTex_ST;
  49.             float4 _MainColor;
  50.             float _FillAmount;
  51.             float4 _TopColor;
  52.             float _EdgeWidth;
  53.             float4 _RimColor;
  54.             float _RimWidth;
  55.             v2f vert (appdata v)
  56.             {
  57.                 v2f o;
  58.                 o.vertex = UnityObjectToClipPos(v.vertex);
  59.                 o.uv = TRANSFORM_TEX(v.uv, _MainTex);
  60.                 UNITY_TRANSFER_FOG(o,o.vertex);
  61.                 o.fillEdge=mul(unity_ObjectToWorld,v.vertex.xyz).y+_FillAmount;
  62.                 o.normal=v.normal;
  63.                 o.viewDir=normalize(ObjSpaceViewDir(v.vertex));
  64.                 return o;
  65.             }
  66.             fixed4 frag (v2f i,fixed facing : VFace) : SV_Target
  67.             {
  68.                 // sample the texture
  69.                 fixed4 col = tex2D(_MainTex, i.uv) * _MainColor;
  70.                 // apply fog
  71.                 UNITY_APPLY_FOG(i.fogCoord, col);
  72.                 float dotProduct = 1-pow(dot(i.normal, i.viewDir),_RimWidth);
  73.                 float4 rimCol=_RimColor*smoothstep(0.5,1,dotProduct);
  74.                 fixed4 edgeVal=step(i.fillEdge,0.5)-step(i.fillEdge,0.5-_EdgeWidth);
  75.                 fixed4 edgeCol=edgeVal *= _TopColor*0.9;
  76.                 fixed4 finalVal=step(i.fillEdge,0.5)-edgeVal;
  77.                 fixed4 finalCol=finalVal*col;
  78.                 finalCol+=edgeCol+rimCol;
  79.                  fixed4 topCol=_TopColor * (edgeVal+finalVal);
  80.                 // float dotVal = 1- pow(dot(i.normal, i.viewDir),0.3);
  81.                 // return float4(dotVal,dotVal,dotVal,1);
  82.                 return facing > 0 ? finalCol : topCol;
  83.             }
  84.             ENDCG
  85.         }
  86.         Pass
  87.         {
  88.             //Cull Front
  89.             Blend SrcAlpha OneMinusSrcAlpha
  90.             CGPROGRAM
  91.             #pragma vertex vert
  92.             #pragma fragment frag
  93.             // make fog work
  94.             #pragma multi_compile_fog
  95.             #include "UnityCG.cginc"
  96.             struct appdata
  97.             {
  98.                 float4 vertex : POSITION;
  99.                 float2 uv : TEXCOORD0;
  100.                 float4 normal : NORMAL;
  101.             };
  102.             struct v2f
  103.             {
  104.                 float2 uv : TEXCOORD0;
  105.                 UNITY_FOG_COORDS(1)
  106.                 float4 vertex : SV_POSITION;
  107.                 float3 viewDir : COLOR;
  108.                 float3 normal :NORMAL;
  109.             };
  110.             float4 _BottleColor;
  111.             float _BottleWidth;
  112.             float4 _RimColor;
  113.             float _RimWidth;
  114.             v2f vert (appdata v)
  115.             {
  116.                 v2f o;
  117.                 v.vertex.xyz+=v.normal.xyz*_BottleWidth;
  118.                 o.vertex = UnityObjectToClipPos(v.vertex);
  119.                 o.uv = v.uv;
  120.                 UNITY_TRANSFER_FOG(o,o.vertex);
  121.                 o.normal=v.normal.xyz;
  122.                 o.viewDir=normalize(ObjSpaceViewDir(v.vertex));
  123.                 return o;
  124.             }
  125.             fixed4 frag (v2f i,fixed facing : VFace) : SV_Target
  126.             {
  127.                 // sample the texture
  128.                 fixed4 col = _BottleColor;
  129.                 // apply fog
  130.                 UNITY_APPLY_FOG(i.fogCoord, col);
  131.                 float dotProduct = 1-pow(dot(i.normal, i.viewDir),_RimWidth);//1-pow(dot(i.normal, i.viewDir),_RimWidth/10);
  132.                 float4 rimCol=_RimColor*smoothstep(0.2,1,dotProduct);
  133.               
  134.                 return rimCol;
  135.             }
  136.             ENDCG
  137.         }
  138.     }
  139. }
复制代码
三、服用方法



  • 1、创建一个液面结果的材质

  • 2、把这个材质挂载到瓶子中的【液体】模型上
  • 3、在面板上拖动FillAmout
  • 4、在脚本中设置mat的该属性
    mat.SetFloat(“_FillAmount”, currentValue);
四、附录:C#调用代码

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

  1. /// <summary>
  2. /// 容器的液面变化:化学实验中,量筒中倒入液体或者被吸取液体后,液面会升降
  3. /// 材质用shader,控制其fillAmout参数
  4. /// </summary>
  5. /// <param name="mat">操作的材质</param>
  6. /// <param name="levelStart">起始液面位置</param>
  7. /// <param name="levelEnd">结束页面位置</param>
  8. /// <param name="duration">动画的时间</param>
  9. /// <returns></returns>
  10. public static async UniTask DoLiquidLevel(Material mat, float levelStart, float levelEnd, float duration)
  11. {
  12.     float currentValue = levelStart;
  13.     float timeElapsed = 0f;
  14.     while (timeElapsed < duration)
  15.     {
  16.         currentValue = Mathf.Lerp(levelStart, levelEnd, timeElapsed / duration);
  17.         Debug.Log(currentValue);
  18.         mat.SetFloat("_FillAmount", currentValue);      //变量名字确保与Shader源码中的变量一致。
  19.         await UniTask.Yield();
  20.         timeElapsed += Time.deltaTime;
  21.     }
  22.     mat.SetFloat("_FillAmount", levelEnd);              //确保最终结果准确
  23. }
复制代码
2、monobehaviour示例脚本

  1. using System;
  2. using Cysharp.Threading.Tasks;
  3. using UnityEngine;
  4. using static txlib;//包含 DoLiquidLevel()
  5. /// <summary>
  6. /// 容器的液面升降控制
  7. /// </summary>
  8. public class ChangeLiquidLevel : MonoBehaviour
  9. {
  10.     /// <summary>
  11.     /// 物体
  12.     /// </summary>
  13.     public GameObject obj;
  14.     /// <summary>
  15.     /// 起始液面
  16.     /// </summary>
  17.     public float levelStart;
  18.     /// <summary>
  19.     /// 终止液面
  20.     /// </summary>
  21.     public float levelEnd;
  22.     /// <summary>
  23.     /// 动画耗时
  24.     /// </summary>
  25.     public float duration;
  26.    
  27.     /// <summary>
  28.     /// 材质
  29.     /// </summary>
  30.     private Material mat;
  31.     [ContextMenu("测试液面")]
  32.     async UniTask Test()
  33.     {
  34.         mat = obj.GetComponent<Renderer>().sharedMaterial;
  35.         while (true)
  36.         {
  37.             await DoLiquidLevel(mat, levelStart, levelEnd, duration);
  38.             await DoLiquidLevel(mat, levelEnd, levelStart, duration);
  39.             await UniTask.Delay(TimeSpan.FromSeconds(0.8f));
  40.         }
  41.     }
  42. }
复制代码
来源:https://blog.csdn.net/dzj2021/article/details/130819256
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则