Unity引擎制作瓶子里的水

Unity制作瓶子里流动的液体

  之前有网友给我留言,说能不能出一个瓶子里的水的制作教程,所以我就写了一个。由于写得比较匆忙,所以可能有些细节没有考虑到。不过也应该能提供一个思路吧。前面说说原理,后面给源码

一、 原理介绍

  我这个制作的效果并不是很难,主要是分析一下原理。

1、为什么水会流动?

  我这个只是一个Shader的效果,按道理来说,是不会产生真实的水流流动效果的。不过Shader效果很多都是视觉上的欺骗,所以我这里是使用了一个小技巧。

1.clip裁剪

  首先,我们要知道,通过clip函数,我们可以把模型指定的一部分范围的显示裁剪掉。
  这个很重要,因为我这个效果里面,水的模型本身是没有变化过,一直都是满的,让人觉得水会流动的假象,就是因为在一直控制着clip裁剪的范围。

2.世界顶点坐标的计算

  什么情况下的片元才需要被裁剪掉呢?从实际效果看,很明显就是一个高度的问题了。高于某个高度的片元,都应该被裁剪掉。由于这个高度可以控制成一个水平面,所以不论瓶子是正的还是斜的,瓶子里面的水的裁剪上边缘都是水平的:
在这里插入图片描述

  由于这个高度是相对于世界,而不是模型本身的局部,所以计算这个水平面高度,就要用顶点的世界坐标减去瓶子模型本身的坐标原点的世界坐标,求出当前顶点相对于瓶子本身的相对高度。

2、为什么水会抖动?

加粗样式上面说到,水平面是一个水平高度,但实际上,也可以不是,比如说,我们原来值用了世界相对坐标的Y轴计算的高度,那么,同样的,我们可以通过计算X和Z轴,再计算一个偏移,比如x大一点的时候,裁剪的高度就高一点之类。于是,我们就可以控制2个变量,分别是X偏移和Z偏移,作为控制水平面倾斜的参数:
在这里插入图片描述

  然后我们要检测模型本身的Transform,看看对比起上一帧,位置和旋转是否发生了变化,然后控制这两个偏移值,做一个往返的渐变。
  当然,这一步就不是纯Shader可以做到的了,需要配合一下C#脚本去做。

3、模型倾斜后的水平面计算

  刚才说过,我们是通过一个高度来确定裁剪的范围。但有一个问题,瓶子里面的水,在倾斜之后,要表现出水的容量在倾斜前后没什么变化。但如果我们固定给了一个高度来裁剪,那么旋转之后,由于瓶子倾斜实际是变矮了,但水面还是原来的高度,就会发现水在倾斜的时候反而涨高了。这明显是不合理的。
  于是,我们要计算一下,当不同倾斜度的时候,水平面的高度应该有不同的下降。这个计算其实很难准确,因为根据瓶子本身的形状不一样,实际上到了不同的斜度水平面下降的高度应该是不同的。但我们这个毕竟知识模拟,并没有真实的物理计算,所以是求不出准确的水平面高度的。
于是,我是做了一个取巧,在Shader里面添加了瓶子的最低和最高高度,然后水平面是一个0-1的百分比范围。然后当瓶子倾斜的时候,我是使用1-高度百分比,求出在瓶子正立的情况下可以空出的水的高度,然后再通过Sin三角函数,求出一个和角度相关的下降值的。
  这样做的好处是,当瓶子是满的时候,高度百分比是1,那么其实空出来水的高度就是0,不管怎样旋转,都不会下降。然后当瓶子不是满的时候,它能下降的高度范围有限,通过三角函数计算出一个差不多的值,虽然不是很准,但也不会有很大的视觉漏洞。作为模拟效果我觉得是差不多了。
  当然,如果要很准确也行,不过那就要真实的去计算体积和容器之间的关系了。
  这个过程,纯Shader同样是完不成的,于是又是要配合一下C#脚本来做。

4、模型本身要怎样制作?

  我这个例子里面,模型是分为了三部分:
在这里插入图片描述

  瓶子外壳、盖子,这两部分是陪衬的,然后水的模型,就是这次例子的重点。
  接下来是模型中心点的问题,有2种选择:
  第一种,是模型原点在模型的底部:
在这里插入图片描述

  第二种是模型原点在模型的中心:
在这里插入图片描述

  可能对于很多纯美术的朋友来说,会觉得奇怪,为什么需要纠结这个问题呢?有什么区别吗?
  这里的区别还是很大的,因为上面介绍原理的时候,水平面的计算是依赖于顶点的世界坐标减去模型本身原点的世界坐标得出的。那么,模型原点的世界坐标的位置不同, 计算的方式也就会不同。
  如果坐标原点是在底部,那么计算正向的高度时会很简单:
在这里插入图片描述

  但如果把瓶子倒过来后:
在这里插入图片描述

  由于模型原点在底部,现在所有的顶点的世界坐标其实都比坐标原点的世界坐标低,所以就比较难计算水平面,要额外加一个参数去把原点的世界坐标往模型中心点提高。这样才能算出水的底部的顶点坐标是在原点之上。
  既然是这样,我后来还是选择了直接把模型原点定在模型中间算了。当然这样做也有缺点,就是等于把偏移值固定死了。如果原点在模型底部,再通过一个参数来调节中心点,那样会灵活一些但麻烦一些。我这个毕竟知识一个演示,所以我就选择了一个省事的处理方式了。

二、 源码

1、 Shader部分

  我是用ASE编辑器快速连接的,所以这里也只能给出ASE的截图和ASE生成的Shader源码了,虽然没有备注,但应该也不是很难看懂:

1. 水的Shader

  分为了clipVal的高度裁剪部分,offset是顶点世界坐标和原点世界坐标相减的部分,然后Edge是水边缘做了个边缘色的效果,就这么简单而已。
在这里插入图片描述

// Made with Amplify Shader Editor
// Available at the Unity Asset Store - http://u3d.as/y3X 
Shader "bottleWater2"
{
	Properties
	{
		_Cutoff( "Mask Clip Value", Float ) = 0.5
		_baseColor("baseColor", Color) = (1,1,1,1)
		_height("height", Range( 0 , 1)) = 1
		_waveX("waveX", Range( -1 , 1)) = 0
		_waveZ("waveZ", Range( -1 , 1)) = 0
		_down("down", Range( 0 , 1)) = 0
		_minHeight("minHeight", Float) = 0
		_maxHeight("maxHeight", Float) = 1
		_downVal("downVal", Float) = 0.5
		_smoothMin("smoothMin", Range( 0 , 1)) = 0
		_smoothMax("smoothMax", Range( 0 , 1)) = 1
		[HideInInspector] __dirty( "", Int ) = 1
	}

	SubShader
	{
		Tags{ "RenderType" = "Opaque"  "Queue" = "AlphaTest+0" "IgnoreProjector" = "True" "IsEmissive" = "true"  }
		Cull Off
		Blend SrcAlpha OneMinusSrcAlpha
		CGINCLUDE
		#include "UnityPBSLighting.cginc"
		#include "Lighting.cginc"
		#pragma target 3.0
		struct Input
		{
			float3 worldNormal;
			float3 viewDir;
			float3 worldPos;
		};

		uniform float4 _baseColor;
		uniform float _smoothMin;
		uniform float _smoothMax;
		uniform float _height;
		uniform float _down;
		uniform float _downVal;
		uniform float _waveX;
		uniform float _waveZ;
		uniform float _maxHeight;
		uniform float _minHeight;
		uniform float _Cutoff = 0.5;

		void surf( Input i , inout SurfaceOutputStandard o )
		{
			float3 ase_worldNormal = i.worldNormal;
			float dotResult53 = dot( ase_worldNormal , i.viewDir );
			float smoothstepResult55 = smoothstep( _smoothMin , _smoothMax , ( 1.0 - dotResult53 ));
			float edge58 = smoothstepResult55;
			o.Emission = ( _baseColor + ( _baseColor * edge58 ) ).rgb;
			o.Alpha = _baseColor.a;
			float3 ase_worldPos = i.worldPos;
			float3 objToWorld5 = mul( unity_ObjectToWorld, float4( float3( 0,0,0 ), 1 ) ).xyz;
			float xOffset27 = ( ase_worldPos.x - objToWorld5.x );
			float zOffset23 = ( ase_worldPos.z - objToWorld5.z );
			float temp_output_37_0 = ( _maxHeight - _minHeight );
			float yOffset25 = ( ase_worldPos.y - objToWorld5.y );
			float clipVal30 = step( 0.5 , ( ( ( _height - ( ( 1.0 - _height ) * _down * _downVal ) ) + ( xOffset27 * _waveX ) + ( zOffset23 * _waveZ ) ) * ( ( temp_output_37_0 - yOffset25 ) / temp_output_37_0 ) ) );
			clip( clipVal30 - _Cutoff );
		}

		ENDCG
		CGPROGRAM
		#pragma surface surf Standard keepalpha fullforwardshadows 

		ENDCG
		Pass
		{
			Name "ShadowCaster"
			Tags{ "LightMode" = "ShadowCaster" }
			ZWrite On
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma target 3.0
			#pragma multi_compile_shadowcaster
			#pragma multi_compile UNITY_PASS_SHADOWCASTER
			#pragma skip_variants FOG_LINEAR FOG_EXP FOG_EXP2
			#include "HLSLSupport.cginc"
			#if ( SHADER_API_D3D11 || SHADER_API_GLCORE || SHADER_API_GLES || SHADER_API_GLES3 || SHADER_API_METAL || SHADER_API_VULKAN )
				#define CAN_SKIP_VPOS
			#endif
			#include "UnityCG.cginc"
			#include "Lighting.cginc"
			#include "UnityPBSLighting.cginc"
			sampler3D _DitherMaskLOD;
			struct v2f
			{
				V2F_SHADOW_CASTER;
				float3 worldPos : TEXCOORD1;
				float3 worldNormal : TEXCOORD2;
				UNITY_VERTEX_INPUT_INSTANCE_ID
				UNITY_VERTEX_OUTPUT_STEREO
			};
			v2f vert( appdata_full v )
			{
				v2f o;
				UNITY_SETUP_INSTANCE_ID( v );
				UNITY_INITIALIZE_OUTPUT( v2f, o );
				UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO( o );
				UNITY_TRANSFER_INSTANCE_ID( v, o );
				float3 worldPos = mul( unity_ObjectToWorld, v.vertex ).xyz;
				half3 worldNormal = UnityObjectToWorldNormal( v.normal );
				o.worldNormal = worldNormal;
				o.worldPos = worldPos;
				TRANSFER_SHADOW_CASTER_NORMALOFFSET( o )
				return o;
			}
			half4 frag( v2f IN
			#if !defined( CAN_SKIP_VPOS )
			, UNITY_VPOS_TYPE vpos : VPOS
			#endif
			) : SV_Target
			{
				UNITY_SETUP_INSTANCE_ID( IN );
				Input surfIN;
				UNITY_INITIALIZE_OUTPUT( Input, surfIN );
				float3 worldPos = IN.worldPos;
				half3 worldViewDir = normalize( UnityWorldSpaceViewDir( worldPos ) );
				surfIN.viewDir = worldViewDir;
				surfIN.worldPos = worldPos;
				surfIN.worldNormal = IN.worldNormal;
				SurfaceOutputStandard o;
				UNITY_INITIALIZE_OUTPUT( SurfaceOutputStandard, o )
				surf( surfIN, o );
				#if defined( CAN_SKIP_VPOS )
				float2 vpos = IN.pos;
				#endif
				half alphaRef = tex3D( _DitherMaskLOD, float3( vpos.xy * 0.25, o.Alpha * 0.9375 ) ).a;
				clip( alphaRef - 0.01 );
				SHADOW_CASTER_FRAGMENT( IN )
			}
			ENDCG
		}
	}
	Fallback "Diffuse"
	CustomEditor "ASEMaterialInspector"
}
/*ASEBEGIN
Version=18500
1949;75;1920;844;2198.002;1217.579;2.244453;True;True
Node;AmplifyShaderEditor.CommentaryNode;29;-1516.389,-396.4381;Inherit;False;691.1375;551.9038;Comment;8;6;5;20;23;16;27;25;7;offset;1,1,1,1;0;0
Node;AmplifyShaderEditor.CommentaryNode;32;-1000.102,336.6028;Inherit;False;1566.211;978.7283;Comment;22;8;34;30;42;40;44;17;22;43;19;33;37;18;21;28;24;26;36;35;45;47;48;clipVal;1,1,1,1;0;0
Node;AmplifyShaderEditor.TransformPositionNode;5;-1468.628,-77.30353;Inherit;False;Object;World;False;Fast;True;1;0;FLOAT3;0,0,0;False;4;FLOAT3;0;FLOAT;1;FLOAT;2;FLOAT;3
Node;AmplifyShaderEditor.WorldPosInputsNode;6;-1444.554,-334.9102;Inherit;False;0;4;FLOAT3;0;FLOAT;1;FLOAT;2;FLOAT;3
Node;AmplifyShaderEditor.SimpleSubtractOpNode;20;-1266.628,-170.9182;Inherit;False;2;0;FLOAT;0;False;1;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.SimpleSubtractOpNode;7;-1208.619,-1.035345;Inherit;False;2;0;FLOAT;0;False;1;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.CommentaryNode;59;-1541.324,-1123.094;Inherit;False;1284.671;506.2292;Comment;8;56;57;54;58;55;51;53;52;Edge;1,1,1,1;0;0
Node;AmplifyShaderEditor.RangedFloatNode;8;-780.9684,432.2613;Inherit;False;Property;_height;height;2;0;Create;True;0;0;False;0;False;1;1;0;1;0;1;FLOAT;0
Node;AmplifyShaderEditor.SimpleSubtractOpNode;16;-1224.106,-346.4381;Inherit;False;2;0;FLOAT;0;False;1;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.RegisterLocalVarNode;23;-1113.243,-159.0159;Inherit;False;zOffset;-1;True;1;0;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.OneMinusNode;45;-402.2809,458.3837;Inherit;False;1;0;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.WorldNormalVector;51;-1491.325,-1069.161;Inherit;False;False;1;0;FLOAT3;0,0,1;False;4;FLOAT3;0;FLOAT;1;FLOAT;2;FLOAT;3
Node;AmplifyShaderEditor.RangedFloatNode;35;-741.03,1235.183;Inherit;False;Property;_minHeight;minHeight;6;0;Create;True;0;0;False;0;False;0;0;0;0;0;1;FLOAT;0
Node;AmplifyShaderEditor.RangedFloatNode;48;-542.2809,641.3837;Inherit;False;Property;_downVal;downVal;8;0;Create;True;0;0;False;0;False;0.5;0.5;0;0;0;1;FLOAT;0
Node;AmplifyShaderEditor.RegisterLocalVarNode;27;-1086.758,-302.1271;Inherit;False;xOffset;-1;True;1;0;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.RangedFloatNode;36;-721.7227,1137.687;Inherit;False;Property;_maxHeight;maxHeight;7;0;Create;True;0;0;False;0;False;1;1;0;0;0;1;FLOAT;0
Node;AmplifyShaderEditor.RegisterLocalVarNode;25;-1049.251,22.59174;Inherit;False;yOffset;-1;True;1;0;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.ViewDirInputsCoordNode;52;-1445.709,-882.008;Inherit;False;World;False;0;4;FLOAT3;0;FLOAT;1;FLOAT;2;FLOAT;3
Node;AmplifyShaderEditor.RangedFloatNode;33;-756.3199,540.5112;Inherit;False;Property;_down;down;5;0;Create;True;0;0;False;0;False;0;0;0;1;0;1;FLOAT;0
Node;AmplifyShaderEditor.GetLocalVarNode;28;-832.3889,673.2183;Inherit;False;27;xOffset;1;0;OBJECT;;False;1;FLOAT;0
Node;AmplifyShaderEditor.GetLocalVarNode;24;-749.5746,935.7287;Inherit;False;23;zOffset;1;0;OBJECT;;False;1;FLOAT;0
Node;AmplifyShaderEditor.RangedFloatNode;21;-872.9575,1013.426;Inherit;False;Property;_waveZ;waveZ;4;0;Create;True;0;0;False;0;False;0;0;-1;1;0;1;FLOAT;0
Node;AmplifyShaderEditor.GetLocalVarNode;26;-485.745,1047.318;Inherit;False;25;yOffset;1;0;OBJECT;;False;1;FLOAT;0
Node;AmplifyShaderEditor.RangedFloatNode;18;-863.3561,786.5068;Inherit;False;Property;_waveX;waveX;3;0;Create;True;0;0;False;0;False;0;0;-1;1;0;1;FLOAT;0
Node;AmplifyShaderEditor.DotProductOpNode;53;-1265.959,-984.7165;Inherit;True;2;0;FLOAT3;0,0,0;False;1;FLOAT3;0,0,0;False;1;FLOAT;0
Node;AmplifyShaderEditor.SimpleMultiplyOpNode;47;-220.2809,586.3837;Inherit;False;3;3;0;FLOAT;0;False;1;FLOAT;0;False;2;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.SimpleSubtractOpNode;37;-477.1018,1163.828;Inherit;False;2;0;FLOAT;0;False;1;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.SimpleSubtractOpNode;43;-288.8741,1116.207;Inherit;False;2;0;FLOAT;0;False;1;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.SimpleSubtractOpNode;34;-27.81985,585.6115;Inherit;False;2;0;FLOAT;0;False;1;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.SimpleMultiplyOpNode;19;-530.946,750.7196;Inherit;False;2;2;0;FLOAT;0;False;1;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.OneMinusNode;54;-987.3862,-1073.094;Inherit;True;1;0;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.RangedFloatNode;56;-1051.218,-812.8637;Inherit;False;Property;_smoothMin;smoothMin;9;0;Create;True;0;0;False;0;False;0;0;0;1;0;1;FLOAT;0
Node;AmplifyShaderEditor.RangedFloatNode;57;-1044.218,-732.8637;Inherit;False;Property;_smoothMax;smoothMax;10;0;Create;True;0;0;False;0;False;1;0;0;1;0;1;FLOAT;0
Node;AmplifyShaderEditor.SimpleMultiplyOpNode;22;-513.5581,932.8264;Inherit;False;2;2;0;FLOAT;0;False;1;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.SimpleAddOpNode;17;-342.6656,837.5261;Inherit;False;3;3;0;FLOAT;0;False;1;FLOAT;0;False;2;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.SimpleDivideOpNode;44;-136.874,1177.207;Inherit;False;2;0;FLOAT;0;False;1;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.SmoothstepOpNode;55;-710.2175,-998.8643;Inherit;False;3;0;FLOAT;0;False;1;FLOAT;0;False;2;FLOAT;1;False;1;FLOAT;0
Node;AmplifyShaderEditor.RegisterLocalVarNode;58;-480.6512,-964.316;Inherit;False;edge;-1;True;1;0;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.SimpleMultiplyOpNode;40;-153.9579,980.7505;Inherit;False;2;2;0;FLOAT;0;False;1;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.ColorNode;2;-418.2108,-378.1882;Inherit;False;Property;_baseColor;baseColor;0;0;Create;True;0;0;False;0;False;1,1,1,1;0,0,0,0;True;0;5;COLOR;0;FLOAT;1;FLOAT;2;FLOAT;3;FLOAT;4
Node;AmplifyShaderEditor.GetLocalVarNode;60;-358.0052,-89.23291;Inherit;False;58;edge;1;0;OBJECT;;False;1;FLOAT;0
Node;AmplifyShaderEditor.StepOpNode;42;11.12591,943.2076;Inherit;False;2;0;FLOAT;0.5;False;1;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.RegisterLocalVarNode;30;148.3198,980.3279;Inherit;False;clipVal;-1;True;1;0;FLOAT;0;False;1;FLOAT;0
Node;AmplifyShaderEditor.SimpleMultiplyOpNode;63;-122.0052,-227.2329;Inherit;False;2;2;0;COLOR;0,0,0,0;False;1;FLOAT;0;False;1;COLOR;0
Node;AmplifyShaderEditor.GetLocalVarNode;31;88.90555,172.0161;Inherit;False;30;clipVal;1;0;OBJECT;;False;1;FLOAT;0
Node;AmplifyShaderEditor.SimpleAddOpNode;62;167.9948,-232.2329;Inherit;False;2;2;0;COLOR;0,0,0,0;False;1;COLOR;0,0,0,0;False;1;COLOR;0
Node;AmplifyShaderEditor.StandardSurfaceOutputNode;64;508.1245,-167.8784;Float;False;True;-1;2;ASEMaterialInspector;0;0;Standard;bottleWater2;False;False;False;False;False;False;False;False;False;False;False;False;False;False;True;False;False;False;False;False;False;Off;0;False;-1;0;False;-1;False;0;False;-1;0;False;-1;False;0;Custom;0.5;True;True;0;False;Opaque;;AlphaTest;All;14;all;True;True;True;True;0;False;-1;False;0;False;-1;255;False;-1;255;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;False;2;15;10;25;False;0.5;True;2;5;False;-1;10;False;-1;0;5;False;-1;10;False;-1;0;False;-1;0;False;-1;0;False;0;0,0,0,0;VertexOffset;True;False;Cylindrical;False;Relative;0;;-1;-1;-1;-1;0;False;0;0;False;-1;-1;0;False;-1;0;0;0;False;0.1;False;-1;0;False;-1;False;16;0;FLOAT3;0,0,0;False;1;FLOAT3;0,0,0;False;2;FLOAT3;0,0,0;False;3;FLOAT;0;False;4;FLOAT;0;False;5;FLOAT;0;False;6;FLOAT3;0,0,0;False;7;FLOAT3;0,0,0;False;8;FLOAT;0;False;9;FLOAT;0;False;10;FLOAT;0;False;13;FLOAT3;0,0,0;False;11;FLOAT3;0,0,0;False;12;FLOAT3;0,0,0;False;14;FLOAT4;0,0,0,0;False;15;FLOAT3;0,0,0;False;0
WireConnection;20;0;6;3
WireConnection;20;1;5;3
WireConnection;7;0;6;2
WireConnection;7;1;5;2
WireConnection;16;0;6;1
WireConnection;16;1;5;1
WireConnection;23;0;20;0
WireConnection;45;0;8;0
WireConnection;27;0;16;0
WireConnection;25;0;7;0
WireConnection;53;0;51;0
WireConnection;53;1;52;0
WireConnection;47;0;45;0
WireConnection;47;1;33;0
WireConnection;47;2;48;0
WireConnection;37;0;36;0
WireConnection;37;1;35;0
WireConnection;43;0;37;0
WireConnection;43;1;26;0
WireConnection;34;0;8;0
WireConnection;34;1;47;0
WireConnection;19;0;28;0
WireConnection;19;1;18;0
WireConnection;54;0;53;0
WireConnection;22;0;24;0
WireConnection;22;1;21;0
WireConnection;17;0;34;0
WireConnection;17;1;19;0
WireConnection;17;2;22;0
WireConnection;44;0;43;0
WireConnection;44;1;37;0
WireConnection;55;0;54;0
WireConnection;55;1;56;0
WireConnection;55;2;57;0
WireConnection;58;0;55;0
WireConnection;40;0;17;0
WireConnection;40;1;44;0
WireConnection;42;1;40;0
WireConnection;30;0;42;0
WireConnection;63;0;2;0
WireConnection;63;1;60;0
WireConnection;62;0;2;0
WireConnection;62;1;63;0
WireConnection;64;2;62;0
WireConnection;64;9;2;4
WireConnection;64;10;31;0
ASEEND*/
//CHKSM=EDF856E7A0B3411B718379BA9308D69010729E1D

2. 瓶子的Shader

  瓶子因为是陪衬的,随便做了个Matcap假反射效果:
在这里插入图片描述

// Made with Amplify Shader Editor
// Available at the Unity Asset Store - http://u3d.as/y3X 
Shader "bottle"
{
	Properties
	{
		_MainColor("MainColor", Color) = (1,1,1,1)
		_matcapTex("matcapTex", 2D) = "white" {}
		_matcapVal("matcapVal", Range( 0 , 1)) = 0
		_metallic("metallic", Float) = 0
		_smoothness("smoothness", Float) = 0
		_smoothMin("smoothMin", Range( 0 , 1)) = 0
		_smoothMax("smoothMax", Range( 0 , 1)) = 1
		[HideInInspector] __dirty( "", Int ) = 1
	}

	SubShader
	{
		Tags{ "RenderType" = "Transparent"  "Queue" = "Transparent+0" "IgnoreProjector" = "True" "IsEmissive" = "true"  }
		Cull Back
		CGINCLUDE
		#include "UnityShaderVariables.cginc"
		#include "UnityPBSLighting.cginc"
		#include "Lighting.cginc"
		#pragma target 3.0
		struct Input
		{
			float3 worldNormal;
		};

		uniform float4 _MainColor;
		uniform float _smoothMin;
		uniform float _smoothMax;
		uniform sampler2D _matcapTex;
		uniform float _matcapVal;
		uniform float _metallic;
		uniform float _smoothness;

		void surf( Input i , inout SurfaceOutputStandard o )
		{
			float4 temp_cast_0 = (_smoothMin).xxxx;
			float4 temp_cast_1 = (_smoothMax).xxxx;
			float3 ase_worldNormal = i.worldNormal;
			float4 smoothstepResult23 = smoothstep( temp_cast_0 , temp_cast_1 , tex2D( _matcapTex, ( ( (mul( float4( ase_worldNormal , 0.0 ), UNITY_MATRIX_V ).xyz).xy + 1.0 ) * 0.5 ) ));
			float4 matcap27 = ( smoothstepResult23 * _matcapVal );
			o.Emission = ( _MainColor + ( _MainColor * matcap27 ) ).rgb;
			o.Metallic = _metallic;
			o.Smoothness = _smoothness;
			o.Alpha = _MainColor.a;
		}

		ENDCG
		CGPROGRAM
		#pragma surface surf Standard alpha:fade keepalpha fullforwardshadows 

		ENDCG
		Pass
		{
			Name "ShadowCaster"
			Tags{ "LightMode" = "ShadowCaster" }
			ZWrite On
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma target 3.0
			#pragma multi_compile_shadowcaster
			#pragma multi_compile UNITY_PASS_SHADOWCASTER
			#pragma skip_variants FOG_LINEAR FOG_EXP FOG_EXP2
			#include "HLSLSupport.cginc"
			#if ( SHADER_API_D3D11 || SHADER_API_GLCORE || SHADER_API_GLES || SHADER_API_GLES3 || SHADER_API_METAL || SHADER_API_VULKAN )
				#define CAN_SKIP_VPOS
			#endif
			#include "UnityCG.cginc"
			#include "Lighting.cginc"
			#include "UnityPBSLighting.cginc"
			sampler3D _DitherMaskLOD;
			struct v2f
			{
				V2F_SHADOW_CASTER;
				float3 worldPos : TEXCOORD1;
				float3 worldNormal : TEXCOORD2;
				UNITY_VERTEX_INPUT_INSTANCE_ID
				UNITY_VERTEX_OUTPUT_STEREO
			};
			v2f vert( appdata_full v )
			{
				v2f o;
				UNITY_SETUP_INSTANCE_ID( v );
				UNITY_INITIALIZE_OUTPUT( v2f, o );
				UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO( o );
				UNITY_TRANSFER_INSTANCE_ID( v, o );
				float3 worldPos = mul( unity_ObjectToWorld, v.vertex ).xyz;
				half3 worldNormal = UnityObjectToWorldNormal( v.normal );
				o.worldNormal = worldNormal;
				o.worldPos = worldPos;
				TRANSFER_SHADOW_CASTER_NORMALOFFSET( o )
				return o;
			}
			half4 frag( v2f IN
			#if !defined( CAN_SKIP_VPOS )
			, UNITY_VPOS_TYPE vpos : VPOS
			#endif
			) : SV_Target
			{
				UNITY_SETUP_INSTANCE_ID( IN );
				Input surfIN;
				UNITY_INITIALIZE_OUTPUT( Input, surfIN );
				float3 worldPos = IN.worldPos;
				half3 worldViewDir = normalize( UnityWorldSpaceViewDir( worldPos ) );
				surfIN.worldNormal = IN.worldNormal;
				SurfaceOutputStandard o;
				UNITY_INITIALIZE_OUTPUT( SurfaceOutputStandard, o )
				surf( surfIN, o );
				#if defined( CAN_SKIP_VPOS )
				float2 vpos = IN.pos;
				#endif
				half alphaRef = tex3D( _DitherMaskLOD, float3( vpos.xy * 0.25, o.Alpha * 0.9375 ) ).a;
				clip( alphaRef - 0.01 );
				SHADOW_CASTER_FRAGMENT( IN )
			}
			ENDCG
		}
	}
	Fallback "Diffuse"
	CustomEditor "ASEMaterialInspector"
}
/*ASEBEGIN
Version=18500
1949;75;1920;844;3721.083;724.9201;2.449183;True;True
Node;AmplifyShaderEditor.CommentaryNode;29;-2678.475,-149.4738;Inherit;False;1448.328;804.2608;Comment;15;10;3;6;2;11;13;14;15;23;16;25;24;20;26;27;matcap;1,1,1,1;0;0
Node;AmplifyShaderEditor.WorldNormalVector;3;-2628.475,9.917664;Inherit;False;False;1;0;FLOAT3;0,0,1;False;4;FLOAT3;0;FLOAT;1;FLOAT;2;FLOAT;3
Node;AmplifyShaderEditor.ViewMatrixNode;10;-2577.816,233.9494;Inherit;False;0;1;FLOAT4x4;0
Node;AmplifyShaderEditor.SimpleMultiplyOpNode;6;-2344.143,61.42857;Inherit;False;2;2;0;FLOAT3;0,0,0;False;1;FLOAT4x4;0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1;False;1;FLOAT3;0
Node;AmplifyShaderEditor.SwizzleNode;13;-2274.754,-99.47385;Inherit;False;FLOAT2;0;1;2;3;1;0;FLOAT3;0,0,0;False;1;FLOAT2;0
Node;AmplifyShaderEditor.RangedFloatNode;14;-2297.732,152.2957;Inherit;False;Constant;_Float0;Float 0;2;0;Create;True;0;0;False;0;False;1;0;0;0;0;1;FLOAT;0
Node;AmplifyShaderEditor.SimpleAddOpNode;11;-2094.759,-65.27834;Inherit;False;2;2;0;FLOAT2;0,0;False;1;FLOAT;0;False;1;FLOAT2;0
Node;AmplifyShaderEditor.RangedFloatNode;16;-2307.5,307.9061;Inherit;False;Constant;_Float1;Float 1;2;0;Create;True;0;0;False;0;False;0.5;0;0;0;0;1;FLOAT;0
Node;AmplifyShaderEditor.SimpleMultiplyOpNode;15;-2126.121,163.5928;Inherit;False;2;2;0;FLOAT2;0,0;False;1;FLOAT;0;False;1;FLOAT2;0
Node;AmplifyShaderEditor.SamplerNode;2;-1934.571,61.45643;Inherit;True;Property;_matcapTex;matcapTex;1;0;Create;True;0;0;False;0;False;-1;None;None;True;0;False;white;Auto;False;Object;-1;Auto;Texture2D;8;0;SAMPLER2D;;False;1;FLOAT2;0,0;False;2;FLOAT;0;False;3;FLOAT2;0,0;False;4;FLOAT2;0,0;False;5;FLOAT;1;False;6;FLOAT;0;False;7;SAMPLERSTATE;;False;5;COLOR;0;FLOAT;1;FLOAT;2;FLOAT;3;FLOAT;4
Node;AmplifyShaderEditor.RangedFloatNode;25;-2135.081,522.2642;Inherit;False;Property;_smoothMax;smoothMax;6;0;Create;True;0;0;False;0;False;1;1;0;1;0;1;FLOAT;0
Node;AmplifyShaderEditor.RangedFloatNode;24;-2157.178,392.3608;Inherit;False;Property;_smoothMin;smoothMin;5;0;Create;True;0;0;False;0;False;0;0;0;1;0;1;FLOAT;0
Node;AmplifyShaderEditor.RangedFloatNode;20;-1778.056,538.7869;Inherit;False;Property;_matcapVal;matcapVal;2;0;Create;True;0;0;False;0;False;0;0;0;1;0;1;FLOAT;0
Node;AmplifyShaderEditor.SmoothstepOpNode;23;-1752.496,378.6454;Inherit;False;3;0;COLOR;0,0,0,0;False;1;COLOR;0,0,0,0;False;2;COLOR;1,0,0,0;False;1;COLOR;0
Node;AmplifyShaderEditor.SimpleMultiplyOpNode;26;-1529.76,380.28;Inherit;False;2;2;0;COLOR;0,0,0,0;False;1;FLOAT;0;False;1;COLOR;0
Node;AmplifyShaderEditor.RegisterLocalVarNode;27;-1454.147,247.34;Inherit;False;matcap;-1;True;1;0;COLOR;0,0,0,0;False;1;COLOR;0
Node;AmplifyShaderEditor.GetLocalVarNode;28;-726.0388,249.7712;Inherit;False;27;matcap;1;0;OBJECT;;False;1;COLOR;0
Node;AmplifyShaderEditor.ColorNode;1;-845,-276.5;Inherit;False;Property;_MainColor;MainColor;0;0;Create;True;0;0;False;0;False;1,1,1,1;1,1,1,0;True;0;5;COLOR;0;FLOAT;1;FLOAT;2;FLOAT;3;FLOAT;4
Node;AmplifyShaderEditor.SimpleMultiplyOpNode;18;-477.1617,186.3514;Inherit;False;2;2;0;COLOR;0,0,0,0;False;1;COLOR;0,0,0,0;False;1;COLOR;0
Node;AmplifyShaderEditor.SimpleAddOpNode;19;-269.1617,207.3514;Inherit;False;2;2;0;COLOR;0,0,0,0;False;1;COLOR;0,0,0,0;False;1;COLOR;0
Node;AmplifyShaderEditor.RangedFloatNode;21;-252.1617,-98.64856;Inherit;False;Property;_metallic;metallic;3;0;Create;True;0;0;False;0;False;0;0;0;0;0;1;FLOAT;0
Node;AmplifyShaderEditor.RangedFloatNode;22;-235.1617,38.35144;Inherit;False;Property;_smoothness;smoothness;4;0;Create;True;0;0;False;0;False;0;0;0;0;0;1;FLOAT;0
Node;AmplifyShaderEditor.StandardSurfaceOutputNode;0;0,0;Float;False;True;-1;2;ASEMaterialInspector;0;0;Standard;bottle;False;False;False;False;False;False;False;False;False;False;False;False;False;False;True;False;False;False;False;False;False;Back;0;False;-1;0;False;-1;False;0;False;-1;0;False;-1;False;0;Transparent;0.5;True;True;0;False;Transparent;;Transparent;All;14;all;True;True;True;True;0;False;-1;False;0;False;-1;255;False;-1;255;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;False;2;15;10;25;False;0.5;True;2;5;False;-1;10;False;-1;0;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;0;0,0,0,0;VertexOffset;True;False;Cylindrical;False;Relative;0;;-1;-1;-1;-1;0;False;0;0;False;-1;-1;0;False;-1;0;0;0;False;0.1;False;-1;0;False;-1;False;16;0;FLOAT3;0,0,0;False;1;FLOAT3;0,0,0;False;2;FLOAT3;0,0,0;False;3;FLOAT;0;False;4;FLOAT;0;False;5;FLOAT;0;False;6;FLOAT3;0,0,0;False;7;FLOAT3;0,0,0;False;8;FLOAT;0;False;9;FLOAT;0;False;10;FLOAT;0;False;13;FLOAT3;0,0,0;False;11;FLOAT3;0,0,0;False;12;FLOAT3;0,0,0;False;14;FLOAT4;0,0,0,0;False;15;FLOAT3;0,0,0;False;0
WireConnection;6;0;3;0
WireConnection;6;1;10;0
WireConnection;13;0;6;0
WireConnection;11;0;13;0
WireConnection;11;1;14;0
WireConnection;15;0;11;0
WireConnection;15;1;16;0
WireConnection;2;1;15;0
WireConnection;23;0;2;0
WireConnection;23;1;24;0
WireConnection;23;2;25;0
WireConnection;26;0;23;0
WireConnection;26;1;20;0
WireConnection;27;0;26;0
WireConnection;18;0;1;0
WireConnection;18;1;28;0
WireConnection;19;0;1;0
WireConnection;19;1;18;0
WireConnection;0;2;19;0
WireConnection;0;3;21;0
WireConnection;0;4;22;0
WireConnection;0;9;1;4
ASEEND*/
//CHKSM=17A5716A4CC4DDA15823AD99524CA1B511EABC8B

3. 盖子的Shader

盖子就更随便了,简单一个三平面映射纹理:
在这里插入图片描述

[image10]

// Made with Amplify Shader Editor
// Available at the Unity Asset Store - http://u3d.as/y3X 
Shader "cover"
{
	Properties
	{
		_MainTex("MainTex", 2D) = "white" {}
		_tiling("tiling", Vector) = (1,1,0,0)
		[HideInInspector] __dirty( "", Int ) = 1
	}

	SubShader
	{
		Tags{ "RenderType" = "Opaque"  "Queue" = "Geometry+0" "IsEmissive" = "true"  }
		Cull Back
		CGINCLUDE
		#include "UnityShaderVariables.cginc"
		#include "UnityPBSLighting.cginc"
		#include "Lighting.cginc"
		#pragma target 3.0
		#ifdef UNITY_PASS_SHADOWCASTER
			#undef INTERNAL_DATA
			#undef WorldReflectionVector
			#undef WorldNormalVector
			#define INTERNAL_DATA half3 internalSurfaceTtoW0; half3 internalSurfaceTtoW1; half3 internalSurfaceTtoW2;
			#define WorldReflectionVector(data,normal) reflect (data.worldRefl, half3(dot(data.internalSurfaceTtoW0,normal), dot(data.internalSurfaceTtoW1,normal), dot(data.internalSurfaceTtoW2,normal)))
			#define WorldNormalVector(data,normal) half3(dot(data.internalSurfaceTtoW0,normal), dot(data.internalSurfaceTtoW1,normal), dot(data.internalSurfaceTtoW2,normal))
		#endif
		struct Input
		{
			float3 worldPos;
			float3 worldNormal;
			INTERNAL_DATA
		};

		uniform sampler2D _MainTex;
		uniform float2 _tiling;


		inline float4 TriplanarSampling1( sampler2D topTexMap, float3 worldPos, float3 worldNormal, float falloff, float2 tiling, float3 normalScale, float3 index )
		{
			float3 projNormal = ( pow( abs( worldNormal ), falloff ) );
			projNormal /= ( projNormal.x + projNormal.y + projNormal.z ) + 0.00001;
			float3 nsign = sign( worldNormal );
			half4 xNorm; half4 yNorm; half4 zNorm;
			xNorm = tex2D( topTexMap, tiling * worldPos.zy * float2(  nsign.x, 1.0 ) );
			yNorm = tex2D( topTexMap, tiling * worldPos.xz * float2(  nsign.y, 1.0 ) );
			zNorm = tex2D( topTexMap, tiling * worldPos.xy * float2( -nsign.z, 1.0 ) );
			return xNorm * projNormal.x + yNorm * projNormal.y + zNorm * projNormal.z;
		}


		void surf( Input i , inout SurfaceOutputStandard o )
		{
			o.Normal = float3(0,0,1);
			float3 ase_worldPos = i.worldPos;
			float3 ase_worldNormal = WorldNormalVector( i, float3( 0, 0, 1 ) );
			float3 ase_vertex3Pos = mul( unity_WorldToObject, float4( i.worldPos , 1 ) );
			float3 ase_vertexNormal = mul( unity_WorldToObject, float4( ase_worldNormal, 0 ) );
			float4 triplanar1 = TriplanarSampling1( _MainTex, ase_vertex3Pos, ase_vertexNormal, 1.0, _tiling, 1.0, 0 );
			o.Emission = triplanar1.xyz;
			o.Alpha = 1;
		}

		ENDCG
		CGPROGRAM
		#pragma surface surf Standard keepalpha fullforwardshadows 

		ENDCG
		Pass
		{
			Name "ShadowCaster"
			Tags{ "LightMode" = "ShadowCaster" }
			ZWrite On
			CGPROGRAM
			#pragma vertex vert
			#pragma fragment frag
			#pragma target 3.0
			#pragma multi_compile_shadowcaster
			#pragma multi_compile UNITY_PASS_SHADOWCASTER
			#pragma skip_variants FOG_LINEAR FOG_EXP FOG_EXP2
			#include "HLSLSupport.cginc"
			#if ( SHADER_API_D3D11 || SHADER_API_GLCORE || SHADER_API_GLES || SHADER_API_GLES3 || SHADER_API_METAL || SHADER_API_VULKAN )
				#define CAN_SKIP_VPOS
			#endif
			#include "UnityCG.cginc"
			#include "Lighting.cginc"
			#include "UnityPBSLighting.cginc"
			struct v2f
			{
				V2F_SHADOW_CASTER;
				float4 tSpace0 : TEXCOORD1;
				float4 tSpace1 : TEXCOORD2;
				float4 tSpace2 : TEXCOORD3;
				UNITY_VERTEX_INPUT_INSTANCE_ID
				UNITY_VERTEX_OUTPUT_STEREO
			};
			v2f vert( appdata_full v )
			{
				v2f o;
				UNITY_SETUP_INSTANCE_ID( v );
				UNITY_INITIALIZE_OUTPUT( v2f, o );
				UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO( o );
				UNITY_TRANSFER_INSTANCE_ID( v, o );
				float3 worldPos = mul( unity_ObjectToWorld, v.vertex ).xyz;
				half3 worldNormal = UnityObjectToWorldNormal( v.normal );
				half3 worldTangent = UnityObjectToWorldDir( v.tangent.xyz );
				half tangentSign = v.tangent.w * unity_WorldTransformParams.w;
				half3 worldBinormal = cross( worldNormal, worldTangent ) * tangentSign;
				o.tSpace0 = float4( worldTangent.x, worldBinormal.x, worldNormal.x, worldPos.x );
				o.tSpace1 = float4( worldTangent.y, worldBinormal.y, worldNormal.y, worldPos.y );
				o.tSpace2 = float4( worldTangent.z, worldBinormal.z, worldNormal.z, worldPos.z );
				TRANSFER_SHADOW_CASTER_NORMALOFFSET( o )
				return o;
			}
			half4 frag( v2f IN
			#if !defined( CAN_SKIP_VPOS )
			, UNITY_VPOS_TYPE vpos : VPOS
			#endif
			) : SV_Target
			{
				UNITY_SETUP_INSTANCE_ID( IN );
				Input surfIN;
				UNITY_INITIALIZE_OUTPUT( Input, surfIN );
				float3 worldPos = float3( IN.tSpace0.w, IN.tSpace1.w, IN.tSpace2.w );
				half3 worldViewDir = normalize( UnityWorldSpaceViewDir( worldPos ) );
				surfIN.worldPos = worldPos;
				surfIN.worldNormal = float3( IN.tSpace0.z, IN.tSpace1.z, IN.tSpace2.z );
				surfIN.internalSurfaceTtoW0 = IN.tSpace0.xyz;
				surfIN.internalSurfaceTtoW1 = IN.tSpace1.xyz;
				surfIN.internalSurfaceTtoW2 = IN.tSpace2.xyz;
				SurfaceOutputStandard o;
				UNITY_INITIALIZE_OUTPUT( SurfaceOutputStandard, o )
				surf( surfIN, o );
				#if defined( CAN_SKIP_VPOS )
				float2 vpos = IN.pos;
				#endif
				SHADOW_CASTER_FRAGMENT( IN )
			}
			ENDCG
		}
	}
	Fallback "Diffuse"
	CustomEditor "ASEMaterialInspector"
}
/*ASEBEGIN
Version=18500
1949;75;1920;844;1507;421;1;True;True
Node;AmplifyShaderEditor.TexturePropertyNode;3;-1025,-153;Inherit;True;Property;_MainTex;MainTex;0;0;Create;True;0;0;False;0;False;None;None;False;white;Auto;Texture2D;-1;0;2;SAMPLER2D;0;SAMPLERSTATE;1
Node;AmplifyShaderEditor.Vector2Node;4;-975,159;Inherit;False;Property;_tiling;tiling;1;0;Create;True;0;0;False;0;False;1,1;1,1;0;3;FLOAT2;0;FLOAT;1;FLOAT;2
Node;AmplifyShaderEditor.TriplanarNode;1;-684,11;Inherit;True;Spherical;Object;False;Top Texture 0;_TopTexture0;white;-1;None;Mid Texture 0;_MidTexture0;white;-1;None;Bot Texture 0;_BotTexture0;white;-1;None;Triplanar Sampler;Tangent;10;0;SAMPLER2D;;False;5;FLOAT;1;False;1;SAMPLER2D;;False;6;FLOAT;0;False;2;SAMPLER2D;;False;7;FLOAT;0;False;9;FLOAT3;0,0,0;False;8;FLOAT;1;False;3;FLOAT2;1,1;False;4;FLOAT;1;False;5;FLOAT4;0;FLOAT;1;FLOAT;2;FLOAT;3;FLOAT;4
Node;AmplifyShaderEditor.StandardSurfaceOutputNode;0;0,0;Float;False;True;-1;2;ASEMaterialInspector;0;0;Standard;cover;False;False;False;False;False;False;False;False;False;False;False;False;False;False;False;False;False;False;False;False;False;Back;0;False;-1;0;False;-1;False;0;False;-1;0;False;-1;False;0;Opaque;0.5;True;True;0;False;Opaque;;Geometry;All;14;all;True;True;True;True;0;False;-1;False;0;False;-1;255;False;-1;255;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;-1;False;2;15;10;25;False;0.5;True;0;0;False;-1;0;False;-1;0;0;False;-1;0;False;-1;0;False;-1;0;False;-1;0;False;0;0,0,0,0;VertexOffset;True;False;Cylindrical;False;Relative;0;;-1;-1;-1;-1;0;False;0;0;False;-1;-1;0;False;-1;0;0;0;False;0.1;False;-1;0;False;-1;False;16;0;FLOAT3;0,0,0;False;1;FLOAT3;0,0,0;False;2;FLOAT3;0,0,0;False;3;FLOAT;0;False;4;FLOAT;0;False;5;FLOAT;0;False;6;FLOAT3;0,0,0;False;7;FLOAT3;0,0,0;False;8;FLOAT;0;False;9;FLOAT;0;False;10;FLOAT;0;False;13;FLOAT3;0,0,0;False;11;FLOAT3;0,0,0;False;12;FLOAT3;0,0,0;False;14;FLOAT4;0,0,0,0;False;15;FLOAT3;0,0,0;False;0
WireConnection;1;0;3;0
WireConnection;1;3;4;0
WireConnection;0;2;1;0
ASEEND*/
//CHKSM=6279E5B5276CB7A3FE8C553BF4F6A78CAD4219A5

2、C#部分

C#部分写的比较随意,表达了这个意思,分别是计算了旋转的时候水平面应该下降的高度,还有当模型旋转或者位移时,应该产生的抖动效果

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
           
public class BottleWaterCtrl : MonoBehaviour
{
    public GameObject water;
    private Material waterMat;
    public float xOffsetMax = 1;
    public float zOffsetMax = 1;
    private float xOffset;    
    private float zOffset;
    private Vector3 lastPos;
    private Vector3 lastRota;
    private float maxPosOffset = 0.05f;
    private float maxAngleOffset = 30;
    private float waveX = 0;
    private float waveZ = 0;
    private float waveSpeed = 10;
    // Start is called before the first frame update
    void Start()
    {
        if(water!=null)
        {
            Renderer render = water.GetComponent<Renderer>();
            if(render!=null)
            {
                waterMat = render.material;
            } 
        }
        SetCurrentTransform();
    }
               
    // Update is called once per frame
    void Update()
    {
        CheckDown();
        CheckShake();
        SetWaterWave();
    }
    /// 
    
    /// 检查水平面在旋转时的下降    /// 
  



    private void CheckDown()
    {
        if(waterMat == null)
        {
            return;
        }
        Vector3 rota = transform.rotation.eulerAngles;
        float ang = Mathf.Max(rota.x, rota.z);
        float down = Mathf.Abs(Mathf.Sin(ang * Mathf.Deg2Rad));
        waterMat.SetFloat("_down", down);
    }
    /// 
    
    /// 检查抖动效果    /// 
  



    private void CheckShake()
    {
        if(water == null)
        {
            return;
        }
        Vector3 curPos = water.transform.position;
        Vector3 curRota = water.transform.rotation.eulerAngles;
        Vector3 offsetPos = curPos - lastPos;
        Vector3 offsetRota = curRota - lastRota;
        float tx = (offsetPos.x / maxPosOffset*-1)+(offsetPos.y/maxPosOffset*0.5f)+offsetRota.z/maxAngleOffset+offsetRota.y/maxAngleOffset*0.5f;
        float tz = (offsetPos.z / maxPosOffset * -1) + (offsetPos.y / maxPosOffset * 0.5f) + offsetRota.x / maxAngleOffset + offsetRota.y / maxAngleOffset * 0.5f;
        AddXOffset(tx);
        AddZOffset(tz);
        SetCurrentTransform();
    }
               
    private void AddXOffset(float val)
    {
        if(Mathf.Abs(val)==0)
        {
            return;
        }
        xOffset = xOffset + val;
        if(xOffset<-1)
        {
            xOffset = -1;
        }
        if(xOffset > 1)
        {
            xOffset = 1;
        }
    }
           
    private void AddZOffset(float val)
    {
        if (Mathf.Abs(val) == 0)
        {
            return;    
        }
        zOffset = zOffset + val;
        if (zOffset < -1)
        {
            zOffset = -1;
        }
        if (zOffset > 1)
        {
            zOffset = 1;
        }
    }
           
    private void SetCurrentTransform()
    {
        if(water == null)
        {
            return;
        }
        lastPos = water.transform.position;
        lastRota = water.transform.rotation.eulerAngles;
    }
    /// 
    
    /// 把计算的结果往材质球赋值    /// 
  



    private void SetWaterWave()
    {
        if(xOffset!=0)
        {
            waveX = waveX + xOffset * Time.deltaTime * waveSpeed;
            if(xOffset>0)
            {
                if(waveX >= xOffset)
                {
                    waveX = xOffset;
                    xOffset = xOffset * (-0.8f);
           
                }
            }
            else
            {
                if (waveX <= xOffset)
                {
                    waveX = xOffset;
                    xOffset = xOffset * (-0.8f);    
           
                }
            }
            if (Mathf.Abs(xOffset) < 0.01f)
            {
                xOffset = 0;
                waveX = 0;
            }
            if(waterMat)
            {
                waterMat.SetFloat("_waveX", waveX);
            }
        }
           
        if (zOffset != 0)
        {
            waveZ = waveZ + zOffset * Time.deltaTime * waveSpeed;
            if (zOffset > 0)
            {
                if (waveZ >= zOffset)
                {
                    waveZ = zOffset;    
                    zOffset = zOffset * (-0.8f);
           
                }
            }
            else
            {
                if (waveZ <= zOffset)
                {
                    waveZ = zOffset;
                    zOffset = zOffset * (-0.8f);
           
                }
            }
            if (Mathf.Abs(zOffset) < 0.01f)
            {
                zOffset = 0;
                waveZ = 0;
            }
            if (waterMat)
            {
                waterMat.SetFloat("_waveZ", waveZ);
            }    
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值