输出的是输入的uv以[piv]为锚点旋转后[ang] (单位为弧度)的uv信息。如果ang没有连线,或者ang连线到time节点上,那么[spd]会控制旋转速度。
Piv是旋转操作的锚点,是一个二维数据(x,y)
uv坐标是从(0,0)->(1,1)的二维坐标系,左下角坐标(0,0),右上角坐标(1,1),中心点坐标(0.5,0.5)
举例:以左下角(0,0)为锚点旋转
旋转的角度(以弧度为单位,2PI为一周)
角度值 *PI/180 = 弧度值
旋转的速度,默认值为1.0。
- 当Ang是一个常量的时候,Spd作为Ang的倍数,Spd*Ang是作为实际旋转的角度。
- 当Ang是时间变量的时候,Spd控制着旋转的速度。
旋转后的uv坐标
如果ang是单个数据,那么uv会整体旋转;
如果ang输入的是一个一维数组,那么我们就可以通过数组来控制对应部位的旋转扭曲的强度。
我们来循序渐进的使用书写unity shader代码模拟旋转器节点的功能
Shader "Hidden/testRotator"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags {
"RenderType"="Opaque"
}
Pass
{
Name "FORWARD"
Tags {
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
fixed4 frag (v2f i) : SV_Target
{
float ang = _Time.y;
float spd = 1.0;
float2 piv = float2(0.5,0.5);
// 计算旋转矩阵
float rotateCos = cos(spd*ang);
float rotateSin = sin(spd*ang);
float2x2 rotateM = float2x2(rotateCos,-rotateSin,rotateSin,rotateCos);
// 移动纹理位置,将旋转中心到(0,0)乘以旋转矩阵,再移回原来的位置
float2 uvNew = mul(i.uv-piv,rotateM)+piv;
fixed4 col = tex2D(_MainTex, uvNew);
float3 finalColor = col.rgb;
fixed4 finalRGBA = fixed4(finalColor,1);
return finalRGBA;
}
ENDCG
}
}
}
我们根据ang和spd确定旋转角度,有了旋转角度和旋转中心我们就可以计算出旋转矩阵,将原来的uv乘以旋转矩阵就得到了新的uv
绕任意点的二维旋转
绕原点的旋转是二维旋转最基本的情况,当我们需要进行绕任意点旋转时,我们可以把这种情况转换到绕原点的旋转,思路如下:
1. 首先将旋转点移动到原点处
2. 绕原点的旋转
绕原点旋转θ的矩阵如下所示:
3. 再将旋转点移回到原来的位置
参考:旋转变换(一)旋转矩阵
以锚点位置为中心,旋转ang*spd大小
Shader "Hidden/testRotator"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Ang ("Ang", Range(0.0, 6.28)) = 0.0
_PivX("Pivot X",Float) = 0.5
_PivY("Pivot Y",Float) = 0.5
}
SubShader
{
Tags {
"RenderType"="Opaque"
}
Pass
{
Name "FORWARD"
Tags {
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
float _Ang;
float _PivX;
float _PivY;
// float _spd;
fixed4 frag (v2f i) : SV_Target
{
float ang = _Ang;
// float ang = _ang;
float spd = 1.0;
// float spd = _spd;
float2 piv = float2(_PivX,_PivY);
// 计算旋转矩阵
float rotateCos = cos(spd*ang);
float rotateSin = sin(spd*ang);
float2x2 rotateM = float2x2(rotateCos,-rotateSin,rotateSin,rotateCos);
// 移动纹理位置,将旋转中心到(0,0)乘以旋转矩阵,再移回原来的位置
float2 uvNew = mul(i.uv-piv,rotateM)+piv;
fixed4 col = tex2D(_MainTex, uvNew);
float3 finalColor = col.rgb;
fixed4 finalRGBA = fixed4(finalColor,1);
return finalRGBA;
}
ENDCG
}
}
}
设置Ang,Piv属性,在Inspector面板中控制属性值
Shader "Hidden/testRotator"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
// _Ang ("Ang", Range(0.0, 6.28)) = 0.0
_PivX("Pivot X",Float) = 0.5
_PivY("Pivot Y",Float) = 0.5
_Spd("Spd", Range(0.0,10.0)) = 1.0
}
SubShader
{
Tags {
"RenderType"="Opaque"
}
Pass
{
Name "FORWARD"
Tags {
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
// float _Ang;
float _PivX;
float _PivY;
float _Spd;
fixed4 frag (v2f i) : SV_Target
{
float ang = _Time.y;
float spd = _Spd;
float2 piv = float2(_PivX,_PivY);
// 计算旋转矩阵
float rotateCos = cos(spd*ang);
float rotateSin = sin(spd*ang);
float2x2 rotateM = float2x2(rotateCos,-rotateSin,rotateSin,rotateCos);
// 移动纹理位置,将旋转中心到(0,0)乘以旋转矩阵,再移回原来的位置
float2 uvNew = mul(i.uv-piv,rotateM)+piv;
fixed4 col = tex2D(_MainTex, uvNew);
float3 finalColor = col.rgb;
fixed4 finalRGBA = fixed4(finalColor,1);
return finalRGBA;
}
ENDCG
}
}
}
Shader "Hidden/testRotator"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_AngTex ("Ang Texture", 2D) = "white" {}
_PivX("Pivot X",Float) = 0.5
_PivY("Pivot Y",Float) = 0.5
_Spd("Spd", Range(0.0,10.0)) = 1.0
}
SubShader
{
Tags {
"RenderType"="Opaque"
}
Pass
{
Name "FORWARD"
Tags {
"LightMode"="ForwardBase"
}
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _MainTex;
sampler2D _AngTex;
float _PivX;
float _PivY;
float _Spd;
fixed4 frag (v2f i) : SV_Target
{
float4 colAng = tex2D(_AngTex, i.uv);
float ang = colAng.r;
float spd = _Spd;
float2 piv = float2(_PivX,_PivY);
// 计算旋转矩阵
float rotateCos = cos(spd*ang);
float rotateSin = sin(spd*ang);
float2x2 rotateM = float2x2(rotateCos,-rotateSin,rotateSin,rotateCos);
// 移动纹理位置,将旋转中心到(0,0)乘以旋转矩阵,再移回原来的位置
float2 uvNew = mul(i.uv-piv,rotateM)+piv;
fixed4 col = tex2D(_MainTex, uvNew);
float3 finalColor = col.rgb;
fixed4 finalRGBA = fixed4(finalColor,1);
return finalRGBA;
}
ENDCG
}
}
}
Unity3D开发之Shader实现扭曲效果