顶点扭曲Shader案例
💡 可以在Shader当中构建旋转矩阵,来实现顶点的旋转,从而达到模型的扭曲效果
Shader "ShaderLeaning/VertexDistortion/vf1"
{
Properties{
}
SubShader{
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f
{
float4 pos: POSITION;
fixed4 col: COLOR;
};
v2f vert(appdata_base v)
{
v2f o;
float angle=length(v.vertex)*_SinTime.w;//计算顶点到中心点的模长,与SinTime相乘,实现角度的周期性变化
float4x4 m={
cos(angle),0,sin(angle),0,
0,1,0,0,
-sin(angle),0,cos(angle),0,
0,0,0,1
};//构建绕Y轴旋转的矩阵
float4 p=mul(m,v.vertex);//将旋转矩阵与顶点相乘
o.pos=UnityObjectToClipPos(p);
o.col=fixed4(0,1,1,1);
return o;
}
fixed4 frag(v2f v):COLOR
{
return v.col;
}
ENDCG
}
}
}
💡 但是每次顶点程序计算当中,都进行了矩阵乘法运算,掌握了矩阵运算规则 可以发现,顶点只是在x,与z方向上移动,所以y值没有必要参与矩阵乘法 所以可以根据这个规律编写优化的代码,提高执行效率
//优化顶点扭曲变换的代码
float x= x=v.vertex.x*cos(angle)+v.vertex.z*sin(angle);
float z=v.vertex.x*(-sin(angle))+v.vertex.z*cos(angle);
v.vertex.x=x;
v.vertex.z=z;
o.pos=UnityObjectToClipPos(v.vertex);
-
xyz同时旋转扭曲
Shader "ShaderLeaning/VertexDistortion/vf1" { Properties{ } SubShader{ Pass{ CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" struct v2f { float4 pos: POSITION; fixed4 col: COLOR; }; v2f vert(appdata_base v) { v2f o; float angle=length(v.vertex)*_SinTime.w*1.5; float4x4 mx={ 1,0,0,0, 0,cos(angle),-sin(angle),0, 0,sin(angle),cos(angle),0, 0,0,0,1 }; float4x4 my={ cos(angle),0,sin(angle),0, 0,1,0,0, -sin(angle),0,cos(angle),0, 0,0,0,1 }; float4x4 mz={ cos(angle),-sin(angle),0,0, sin(angle),cos(angle),0,0, 0,0,1,0, 0,0,0,1 }; v.vertex= mul(mz,mul(my,mul(mx,v.vertex))); o.pos=UnityObjectToClipPos(v.vertex); o.col=fixed4(0,1,1,1); return o; } fixed4 frag(v2f v):COLOR { return v.col; } ENDCG } }
实现根据根据音量大小实现波动效果
Shader "ShaderLeaning/VertexDistortion/vf2"
{
Properties{
}
SubShader{
Pass{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
uniform float _Height=1;
struct v2f
{
float4 pos: POSITION;
fixed4 col: COLOR;
};
v2f vert(appdata_base v)
{
v2f o;
float angle=length(v.vertex)*_Time.y;
v.vertex.x=v.vertex.x* (sin(angle)/16+1);
v.vertex.z=v.vertex.z* (cos(angle)/16+1);
v.vertex.y=v.vertex.y+(sin(angle)*cos(angle))*_Height;
o.pos=UnityObjectToClipPos(v.vertex);
o.col=fixed4(0,1,1,1);
return o;
}
fixed4 frag(v2f v):COLOR
{
return v.col;
}
ENDCG
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class VoiceControl : MonoBehaviour
{
[SerializeField] float multiplyer=10;
AudioClip clip;
string device=null;
Material mat;
// Start is called before the first frame update
void Start()
{
device= Microphone.devices[0];
clip=Microphone.Start(device,true,999,44100);
mat=GetComponent().sharedMaterial;
}
private void Update() {
var volume= GetVolume();
mat.SetFloat("_Height",volume*multiplyer);
//Debug.Log(volume);
}
public float GetVolume()
{
if(Microphone.IsRecording(device))
{
int sampleSize=128;
float[] samples=new float[sampleSize];
int startPosition= Microphone.GetPosition(device)-(sampleSize+1);
clip.GetData(samples,startPosition);
float levelMax=0;
for (int i = 0; i < sampleSize; i++)
{
float wavePeak=samples[i];
if(levelMax<wavePeak)
{
levelMax=wavePeak;
}
}
return levelMax;
}
return 0;
}
}


...