unity模仿瓶子中的液体晃动
2021-05-29 10:02
标签:output ota tags 交互 pil 意思 minus gre nal 在VR游戏《半条命:Alyx》中,有个酒瓶中液体晃动的交互。 这里在patreon上有个实现了液体晃动的工程,作者忘了叫啥了,记得的话补回来。这里简单分析一下代码的意思,之前也看过,只是不太理解旋转部分的代码,现在重新复习一下。 液体的shader 图3 顶点的x和y互换后,变成右边的图,即顶点是往右图的旋转方向旋转了,液体在X轴向上摆动,左右摆动。 C#脚本把值传入液体的shader里 这传入shader的wobbleAmountX是控制液体左右摆的幅度,同理,wobbleAmountZ是前后摆动的幅度。这里velocity的值是只有在物体移动时才会不等于0,angularVelocity在只有旋转时才会不等于0,即只有移动或旋转时才会晃动液体,移动的增量越大,液体摆动得越大。 最后把玻璃瓶的shader代码贴上 unity模仿瓶子中的液体晃动 标签:output ota tags 交互 pil 意思 minus gre nal 原文地址:https://www.cnblogs.com/MoFishLi/p/14770723.htmlShader "Unlit/SpecialFX/Liquid"
{
Properties
{
_Tint ("Tint", Color) = (1,1,1,1)
_MainTex ("Texture", 2D) = "white" {}
_FillAmount ("Fill Amount", Range(-10,10)) = 0.0
[HideInInspector] _WobbleX ("WobbleX", Range(-1,1)) = 0.0
[HideInInspector] _WobbleZ ("WobbleZ", Range(-1,1)) = 0.0
_TopColor ("Top Color", Color) = (1,1,1,1)
_FoamColor ("Foam Line Color", Color) = (1,1,1,1)
_Rim ("Foam Line Width", Range(0,0.1)) = 0.0
_RimColor ("Rim Color", Color) = (1,1,1,1)
_RimPower ("Rim Power", Range(0,10)) = 0.0
}
SubShader
{
Tags {"Queue"="Geometry" "DisableBatching" = "True" }
Pass
{
Zwrite On
Cull Off // we want the front and back faces
AlphaToMask On // transparency
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
float3 normal : NORMAL;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
float3 viewDir : COLOR;
float3 normal : COLOR2;
float fillEdge : TEXCOORD2;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float _FillAmount, _WobbleX, _WobbleZ;
float4 _TopColor, _RimColor, _FoamColor, _Tint;
float _Rim, _RimPower;
float4 RotateAroundYInDegrees (float4 vertex, float degrees)
{
float alpha = degrees * UNITY_PI / 180;
float sina, cosa;
sincos(alpha, sina, cosa);
float2x2 m = float2x2(cosa, sina, -sina, cosa); //构造一个2x2的旋转矩阵
return float4(vertex.yz , mul(m, vertex.xz)).xzyw ; //mul(m,vertex.xz))是绕y轴旋转degrees的角度,这里传入的是360度,顶点还是保持在原来的位置
//return float4(vertex.yz , vertex.xz).xzyw ; //这里为啥要这么写呢?其实return得到的值表示成float4(vertex.y,vertex.x,vertex.z,vertex.z),由于只要float3,w分量可以忽略。这里其实意思是顶点的x与y互换了。参考图3
//原顶点worldPos的值加上这里return的值(worldPosX),顶点就可以在左右的方向摆动,也就是在XY平面旋转,
//之后的worldPosZ等于float3(vertex.x,vertex.z,vertex.y),就是顶点的z和y互换,在YZ平面旋转,即液体前后摆动。
//
//通过这种方式,不管你玻璃杯怎么旋转,左右晃动玻璃杯,液体也会左右摆动;前后晃动的话,液体就会前后摆动,就跟现实中晃动杯子里的水一样。
}
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o,o.vertex);
// get world position of the vertex
float3 worldPos = mul (unity_ObjectToWorld, v.vertex.xyz);
// rotate it around XY
float3 worldPosX= RotateAroundYInDegrees(float4(worldPos,0),360);
// rotate around ZY
float3 worldPosZ = float3 (worldPosX.y, worldPosX.z, worldPosX.x);
// combine rotations with worldPos, based on sine wave from script
float3 worldPosAdjusted = worldPos + (worldPosX * _WobbleX+worldPosZ * _WobbleZ); //液体原顶点加上在X轴和Z轴上的摆动,这里好奇既然是旋转,为啥液体不是像平常的3d物体那样整个旋转呢。
// how high up the liquid is //其实并没有改变顶点的位置,而是通过计算存储一个值,然后拿到片元中根据y轴的值去剔除,得到最终的颜色值。
o.fillEdge = worldPosAdjusted.y + _FillAmount;
o.viewDir = normalize(ObjSpaceViewDir(v.vertex));
o.normal = v.normal;
return o;
}
fixed4 frag (v2f i, fixed facing : VFACE) : SV_Target
{
// sample the texture
fixed4 col = tex2D(_MainTex, i.uv) * _Tint;
// apply fog
UNITY_APPLY_FOG(i.fogCoord, col);
// rim light //在液体表面有层光晕,菲涅尔。
float dotProduct = 1 - pow(dot(i.normal, i.viewDir), _RimPower);
float4 RimResult = smoothstep(0.5, 1.0, dotProduct);
RimResult *= _RimColor;
// foam edge //在液体水面上的泡沫
float4 foam = ( step(i.fillEdge, 0.5) - step(i.fillEdge, (0.5 - _Rim))) ;
float4 foamColored = foam * (_FoamColor * 0.9);
// rest of the liquid
float4 result = step(i.fillEdge, 0.5) - foam;
float4 resultColored = result * col;
// both together, with the texture
float4 finalResult = resultColored + foamColored;
finalResult.rgb += RimResult;
// color of backfaces/ top
float4 topColor = _TopColor * (foam + result);
//VFACE returns positive for front facing, negative for backfacing
return facing > 0 ? finalResult: topColor;
}
ENDCG
}
}
}using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Wobble : MonoBehaviour
{
Renderer rend;
Vector3 lastPos;
Vector3 velocity;
Vector3 lastRot;
Vector3 angularVelocity;
public float MaxWobble = 0.03f;
public float WobbleSpeed = 1f;
public float Recovery = 1f;
float wobbleAmountX;
float wobbleAmountZ;
float wobbleAmountToAddX;
float wobbleAmountToAddZ;
float pulse;
float time = 0.5f;
// Use this for initialization
void Start()
{
rend = GetComponent
Shader "Toon/Lit Specular Alpha" {
Properties{
_Color("Main Color", Color) = (1,1,1,1)
_SColor("Specular Color", Color) = (1,1,1,1)
_MainTex("Base (RGB)", 2D) = "white" {}
_Ramp("Toon Ramp (RGB)", 2D) = "gray" {}
_RampS("Specular Ramp (RGB)", 2D) = "gray" {} // specular ramp, cutoff point
_SpecSize("Specular Size", Range(0.65,0.999)) = 0.9 // specular size
_SpecOffset("Specular Offset", Range(0.5,1)) = 0.5 // specular offset of the spec Ramp
_TColor("Gradient Overlay Top Color", Color) = (1,1,1,1)
_BottomColor("Gradient Overlay Bottom Color", Color) = (0.23,0,0.95,1)
_Offset("Gradient Offset", Range(-4,4)) = 3.2
[Toggle(RIM)] _RIM("Fresnel Rim?", Float) = 0
_RimColor("Fresnel Rim Color", Color) = (0.49,0.94,0.64,1)
[Toggle(FADE)] _FADE("Fade specular to bottom?", Float) = 0
_TopBottomOffset("Specular Fade Offset", Range(-4,4)) = 3.2
}
SubShader{
Tags{ "Queue" = "Transparent"}
LOD 200
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma surface surf ToonRamp vertex:vert keepalpha
#pragma shader_feature FADE // fade toggle
#pragma shader_feature RIM // rim fresnel toggle
sampler2D _Ramp;
// custom lighting function that uses a texture ramp based
// on angle between light direction and normal
#pragma lighting ToonRamp exclude_path:prepass
inline half4 LightingToonRamp(SurfaceOutput s, half3 lightDir, half atten)
{
#ifndef USING_DIRECTIONAL_LIGHT
lightDir = normalize(lightDir);
#endif
half d = dot(s.Normal, lightDir)*0.5 + 0.5;
half3 ramp = tex2D(_Ramp, float2(d,d)).rgb;
half4 c;
c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
c.a = s.Alpha;
return c;
}
sampler2D _MainTex;
float4 _Color;
float4 _SColor; // specular color
sampler2D _RampS; // specular ramp
float _SpecSize; // specular size
float _SpecOffset; // offset specular ramp
float4 _TColor; // top gradient color
float4 _BottomColor;// bottom gradient color
float _TopBottomOffset; // gradient bottom offset
float _Offset; // specular fade offset
float4 _RimColor; // fresnel rim color
struct Input {
float2 uv_MainTex : TEXCOORD0;
float3 lightDir;
float3 worldPos; // world position
float3 viewDir; // view direction from camera
};
void vert(inout appdata_full v, out Input o)
{
UNITY_INITIALIZE_OUTPUT(Input, o);
o.lightDir = WorldSpaceLightDir(v.vertex); // get the worldspace lighting direction
}
void surf(Input IN, inout SurfaceOutput o) {
float3 localPos = (IN.worldPos - mul(unity_ObjectToWorld, float4(0, 0, 0, 1)).xyz);// local position of the object, with an offset
half4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
half d = dot(o.Normal, IN.lightDir)*0.5 + _SpecOffset; // basing on normal and light direction
half3 rampS = tex2D(_RampS, float2(d, d)).rgb; // specular ramp
float rim = 1 - saturate(dot(IN.viewDir, o.Normal)); // calculate fresnel rim
#if RIM
o.Emission = _RimColor.rgb * pow(rim, 1.5); // fresnel rim
#endif
float specular= (step(_SpecSize, rampS.r)) * rampS * d * _SColor.a;
o.Albedo = specular* _SColor; // specular
o.Alpha = c.a + specular;
#if FADE
float specular2 = (step(_SpecSize, rampS.r)) * rampS * d* saturate(localPos.y + _TopBottomOffset)* _SColor.a;
o.Albedo = specular2* _SColor; // fade specular to bottom
o.Alpha = c.a + specular2;
#endif
o.Albedo += c.rgb*lerp(_BottomColor, _TColor, saturate(localPos.y + _Offset)) * 1.1; // multiply color by gradient lerp
}
ENDCG
}
Fallback "Diffuse"
}
上一篇:常用算法(C语言描述)
下一篇:剖析XAML语言