作为一个刚学习shader的菜鸟,当看到TexturePanner这样的组合式的shader,让人眼前一亮,忍不住有一种想探究它的好奇心,想了解一下内部是怎么实现的,顺便学学大佬的思路,所有今天就简单的梳理一下源码,先贴一下shader源码(删除了一部分无用的注释):
// Made with Amplify Shader Editor
// Available at the Unity Asset Store - http://u3d.as/y3X
Shader "AdultLink/TexturePanner"
{
Properties
{
[NoScaleOffset]_Tex("Tex", 2D) = "white" {}
[NoScaleOffset]_Masktexture("Mask texture", 2D) = "white" {}
_Tiling("Tiling", Vector) = (1,1,0,0)
_Offset("Offset", Vector) = (0,0,0,0)
[HDR]_Color("Color", Color) = (0,0,0,0)
[KeywordEnum(Original,Hueshift,Multiply,Replace)] _Colormode("Color mode", Float) = 2
[Toggle]_Globalemissionflicker("Global emission flicker", Float) = 0
_Globalemissionflickeramplitude("Global emission flicker amplitude", Float) = 0.5
_Globalemissionflickerfreq("Global emission flicker freq", Float) = 1
_Globalemissionflickeroffset("Global emission flicker offset", Float) = 1
[Toggle]_ScanlinesY("Scanlines Y", Float) = 0
[Toggle]_ScanlinesZ("Scanlines Z", Float) = 0
[Toggle]_ScanlinesX("Scanlines X", Float) = 0
_ScanlinesscaleZ("Scanlines scale Z", Float) = 30
_ScanlinesscaleX("Scanlines scale X", Float) = 30
_ScanlinesscaleY("Scanlines scale Y", Float) = 30
_ScanlinesspeedX("Scanlines speed X", Float) = -5
_ScanlinesspeedY("Scanlines speed Y", Float) = -5
_ScanlinesspeedZ("Scanlines speed Z", Float) = -5
[Toggle]_SharpY("SharpY", Float) = 1
[Toggle]_SharpZ("SharpZ", Float) = 1
[Toggle]_SharpX("SharpX", Float) = 1
_ScrollingspeedX("Scrolling speed X", Float) = -1
_ScrollingspeedY("Scrolling speed Y", Float) = 0
[Toggle]_Horizontalstretch("Horizontalstretch", Float) = 0
[Toggle]_Verticalstretch("Vertical stretch", Float) = 0
_Horizontalstretchamplitude("Horizontal stretch amplitude", Range( 0 , 1)) = 0.5
_Verticalstretchamplitude("Vertical stretch amplitude", Range( 0 , 1)) = 0.5
_Horizontalstretchfreq("Horizontal stretch freq", Float) = 0.5
_Verticalstretchfreq("Vertical stretch freq", Float) = 0.5
_Horizontalstretchoffset("Horizontal stretch offset", Float) = 0
_Verticalstretchoffset("Vertical stretch offset", Float) = 0
_Verticalstretchpivotpoint("Vertical stretch pivot point", Range( -1 , 1)) = -0.06438866
_Horizontalstretchpivotpoint("Horizontal stretch pivot point", Range( -1 , 1)) = 0
[Toggle]_Horizontalmovement("Horizontalmovement", Float) = 0
[Toggle]_Verticalmovement("Vertical movement", Float) = 0
_Horizontalmovementamplitude("Horizontal movement amplitude", Float) = 0.5
_Verticalmovementamplitude("Vertical movement amplitude", Float) = 0.5
_Horizontalmovementfreq("Horizontal movement freq", Float) = 1
_Verticalmovementfreq("Vertical movement freq", Float) = 1
_Horizontalmovementoffset("Horizontal movement offset", Float) = 0
_Verticalmovementoffset("Vertical movement offset", Float) = 0
_RotationSpeed("Rotation Speed", Float) = 1
_Masktexturerotationspeed("Mask texture rotation speed", Float) = 0
[KeywordEnum(Scroll,Rotate,None)] _Scrollrotate("Scroll rotate", Float) = 0
_Masktexturetiling("Mask texture tiling", Vector) = (1,1,0,0)
_Masktextureoffset("Mask texture offset", Vector) = (0,0,0,0)
[HideInInspector] _texcoord( "", 2D ) = "white" {}
[HideInInspector] __dirty( "", Int ) = 1
}
SubShader
{
Tags{ "RenderType" = "Transparent" "Queue" = "Transparent+0" "IgnoreProjector" = "True" "IsEmissive" = "true" }
Cull Off
CGPROGRAM
#include "UnityShaderVariables.cginc"
#pragma target 3.0
#pragma shader_feature _COLORMODE_ORIGINAL _COLORMODE_HUESHIFT _COLORMODE_MULTIPLY _COLORMODE_REPLACE
#pragma shader_feature _SCROLLROTATE_SCROLL _SCROLLROTATE_ROTATE _SCROLLROTATE_NONE
#pragma surface surf Standard alpha:fade keepalpha noshadow vertex:vertexDataFunc
struct Input
{
float2 uv_texcoord;
float3 worldPos;
};
uniform float _Horizontalmovement;
uniform float _Horizontalmovementfreq;
uniform float _Horizontalmovementamplitude;
uniform float _Horizontalmovementoffset;
uniform float _Horizontalstretch;
uniform float _Horizontalstretchfreq;
uniform float _Horizontalstretchamplitude;
uniform float _Horizontalstretchoffset;
uniform float _Horizontalstretchpivotpoint;
uniform float _Verticalmovement;
uniform float _Verticalmovementfreq;
uniform float _Verticalmovementamplitude;
uniform float _Verticalmovementoffset;
uniform float _Verticalstretch;
uniform float _Verticalstretchfreq;
uniform float _Verticalstretchamplitude;
uniform float _Verticalstretchoffset;
uniform float _Verticalstretchpivotpoint;
uniform float _Globalemissionflicker;
uniform float _Globalemissionflickerfreq;
uniform float _Globalemissionflickeramplitude;
uniform float _Globalemissionflickeroffset;
uniform float _ScanlinesX;
uniform float _SharpX;
uniform float _ScanlinesscaleX;
uniform float _ScanlinesspeedX;
uniform float _ScanlinesY;
uniform float _SharpY;
uniform float _ScanlinesscaleY;
uniform float _ScanlinesspeedY;
uniform float _ScanlinesZ;
uniform float _SharpZ;
uniform float _ScanlinesscaleZ;
uniform float _ScanlinesspeedZ;
uniform sampler2D _Tex;
uniform float _ScrollingspeedX;
uniform float _ScrollingspeedY;
uniform float2 _Tiling;
uniform float2 _Offset;
uniform float _RotationSpeed;
uniform float4 _Color;
uniform sampler2D _Masktexture;
uniform float2 _Masktexturetiling;
uniform float2 _Masktextureoffset;
uniform float _Masktexturerotationspeed;
float3 HSVToRGB( float3 c )
{
float4 K = float4( 1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0 );
float3 p = abs( frac( c.xxx + K.xyz ) * 6.0 - K.www );
return c.z * lerp( K.xxx, saturate( p - K.xxx ), c.y );
}
float3 RGBToHSV(float3 c)
{
float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
float4 p = lerp( float4( c.bg, K.wz ), float4( c.gb, K.xy ), step( c.b, c.g ) );
float4 q = lerp( float4( p.xyw, c.r ), float4( c.r, p.yzx ), step( p.x, c.r ) );
float d = q.x - min( q.w, q.y );
float e = 1.0e-10;
return float3( abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
void vertexDataFunc( inout appdata_full v, out Input o )
{
UNITY_INITIALIZE_OUTPUT( Input, o );
float mulTime201 = _Time.y * _Horizontalmovementfreq;
float HorizontalMovement212 = lerp(0.0,(sin( mulTime201 )*_Horizontalmovementamplitude + _Horizontalmovementoffset),_Horizontalmovement);
float mulTime190 = _Time.y * _Horizontalstretchfreq;
float3 ase_vertex3Pos = v.vertex.xyz;
float3 Vertexpos163 = ase_vertex3Pos;
float HorizontalStretch217 = lerp(0.0,( (sin( mulTime190 )*_Horizontalstretchamplitude + _Horizontalstretchoffset) * ( _Horizontalstretchpivotpoint + Vertexpos163.x ) ),_Horizontalstretch);
float mulTime111 = _Time.y * _Verticalmovementfreq;
float VerticalMovement210 = lerp(0.0,(sin( mulTime111 )*_Verticalmovementamplitude + _Verticalmovementoffset),_Verticalmovement);
float mulTime91 = _Time.y * _Verticalstretchfreq;
float VerticalStretch215 = lerp(0.0,( (sin( mulTime91 )*_Verticalstretchamplitude + _Verticalstretchoffset) * ( _Verticalstretchpivotpoint + Vertexpos163.y ) ),_Verticalstretch);
float4 appendResult86 = (float4(( HorizontalMovement212 + HorizontalStretch217 ) , ( VerticalMovement210 + VerticalStretch215 ) , 0.0 , 0.0));
v.vertex.xyz += appendResult86.xyz;
}
void surf( Input i , inout SurfaceOutputStandard o )
{
float mulTime99 = _Time.y * _Globalemissionflickerfreq;
float EmissionFlicker228 = lerp(1.0,(pow( sin( mulTime99 ) , 2.0 )*(0.0 + (_Globalemissionflickeramplitude - 0.0) * (0.1 - 0.0) / (1.0 - 0.0)) + _Globalemissionflickeroffset),_Globalemissionflicker);
float mulTime147 = _Time.y * _ScanlinesspeedX;
float clampResult150 = clamp( sin( (i.uv_texcoord.x*_ScanlinesscaleX + mulTime147) ) , 0.0 , 1.0 );
float ScanlinesX220 = lerp(1.0,lerp(clampResult150,ceil( clampResult150 ),_SharpX),_ScanlinesX);
float mulTime26 = _Time.y * _ScanlinesspeedY;
float clampResult175 = clamp( sin( (i.uv_texcoord.y*_ScanlinesscaleY + mulTime26) ) , 0.0 , 1.0 );
float ScanlinesY222 = lerp(1.0,lerp(clampResult175,ceil( clampResult175 ),_SharpY),_ScanlinesY);
float3 ase_vertex3Pos = mul( unity_WorldToObject, float4( i.worldPos , 1 ) );
float mulTime154 = _Time.y * _ScanlinesspeedZ;
float clampResult157 = clamp( sin( (ase_vertex3Pos.z*_ScanlinesscaleZ + mulTime154) ) , 0.0 , 1.0 );
float ScanlinesZ224 = lerp(1.0,lerp(clampResult157,ceil( clampResult157 ),_SharpZ),_ScanlinesZ);
float2 appendResult70 = (float2(_ScrollingspeedX , _ScrollingspeedY));
float2 temp_output_80_0 = (float2( 0,0 ) + (_Offset - float2( 0,0 )) * (float2( 1,1 ) - float2( 0,0 )) / (float2( 360,360 ) - float2( 0,0 )));
float2 uv_TexCoord7 = i.uv_texcoord * _Tiling + temp_output_80_0;
float2 panner4 = ( _Time.y * appendResult70 + uv_TexCoord7);
float2 uv_TexCoord185 = i.uv_texcoord * _Tiling + temp_output_80_0;
float mulTime181 = _Time.y * _RotationSpeed;
float cos179 = cos( mulTime181 );
float sin179 = sin( mulTime181 );
float2 rotator179 = mul( uv_TexCoord185 - ( _Tiling * float2( 0.5,0.5 ) ) , float2x2( cos179 , -sin179 , sin179 , cos179 )) + ( _Tiling * float2( 0.5,0.5 ) );
#if defined(_SCROLLROTATE_SCROLL)
float2 staticSwitch187 = panner4;
#elif defined(_SCROLLROTATE_ROTATE)
float2 staticSwitch187 = rotator179;
#elif defined(_SCROLLROTATE_NONE)
float2 staticSwitch187 = uv_TexCoord7;
#else
float2 staticSwitch187 = panner4;
#endif
float4 PannedRotatedTexture231 = tex2D( _Tex, staticSwitch187 );
float4 CombinedTexture41 = ( EmissionFlicker228 * ScanlinesX220 * ScanlinesY222 * ScanlinesZ224 * PannedRotatedTexture231 );
float3 hsvTorgb125 = RGBToHSV( CombinedTexture41.rgb );
float3 hsvTorgb126 = RGBToHSV( _Color.rgb );
float3 hsvTorgb127 = HSVToRGB( float3(( hsvTorgb125.x + hsvTorgb126.x ),hsvTorgb125.y,hsvTorgb125.z) );
float2 uv_TexCoord238 = i.uv_texcoord * _Masktexturetiling + _Masktextureoffset;
float mulTime247 = _Time.y * _Masktexturerotationspeed;
float cos248 = cos( mulTime247 );
float sin248 = sin( mulTime247 );
float2 rotator248 = mul( uv_TexCoord238 - ( _Masktexturetiling * float2( 0.5,0.5 ) ) , float2x2( cos248 , -sin248 , sin248 , cos248 )) + ( _Masktexturetiling * float2( 0.5,0.5 ) );
float Masktexture241 = tex2D( _Masktexture, rotator248 ).a;
float CombinedTexture_alpha51 = ( CombinedTexture41.a * Masktexture241 );
#if defined(_COLORMODE_ORIGINAL)
float4 staticSwitch40 = CombinedTexture41;
#elif defined(_COLORMODE_HUESHIFT)
float4 staticSwitch40 = float4( hsvTorgb127 , 0.0 );
#elif defined(_COLORMODE_MULTIPLY)
float4 staticSwitch40 = ( CombinedTexture41 * _Color );
#elif defined(_COLORMODE_REPLACE)
float4 staticSwitch40 = ( _Color * CombinedTexture_alpha51 );
#else
float4 staticSwitch40 = ( CombinedTexture41 * _Color );
#endif
float4 FinalEmission234 = staticSwitch40;
o.Emission = FinalEmission234.rgb;
o.Alpha = CombinedTexture_alpha51;
}
ENDCG
}
CustomEditor "TexturePannerEditor"
}
很明显这是一个表面着色器,所以麻烦了,自己本身对表面着色器只有一点点了解,毕竟大部分时间都去学习顶点、片元着色器了,没办法硬着头皮看吧。
#pragma surface surf Standard alpha:fade keepalpha noshadow vertex:vertexDataFunc
- 定义宏:
#pragma shader_feature _COLORMODE_ORIGINAL _COLORMODE_HUESHIFT _COLORMODE_MULTIPLY _COLORMODE_REPLACE
#pragma shader_feature _SCROLLROTATE_SCROLL _SCROLLROTATE_ROTATE _SCROLLROTATE_NONE
- 看一下自定义的两个函数吧:
float3 HSVToRGB( float3 c )
{
float4 K = float4( 1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0 );
float3 p = abs( frac( c.xxx + K.xyz ) * 6.0 - K.www );
return c.z * lerp( K.xxx, saturate( p - K.xxx ), c.y );
}
float3 RGBToHSV(float3 c)
{
float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
float4 p = lerp( float4( c.bg, K.wz ), float4( c.gb, K.xy ), step( c.b, c.g ) );
float4 q = lerp( float4( p.xyw, c.r ), float4( c.r, p.yzx ), step( p.x, c.r ));
float d = q.x - min( q.w, q.y );
float e = 1.0e-10;
return float3( abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
嗯……看不懂,看函数名知道干啥的,内部代码不知道干啥的(要不这篇博客就到这吧)。目测(只是目测),没记错的话,学shader的时候大佬的博客说这段代码好像出自shadertoy,我菜鸟一个也不清楚。
不管了我们接着往下看:
- 顶点函数:
void vertexDataFunc( inout appdata_full v, out Input o )
{
UNITY_INITIALIZE_OUTPUT( Input, o );
float mulTime201 = _Time.y * _Horizontalmovementfreq;
float HorizontalMovement212 = lerp(0.0,(sin( mulTime201 )*_Horizontalmovementamplitude + _Horizontalmovementoffset),_Horizontalmovement);
float mulTime190 = _Time.y * _Horizontalstretchfreq;
float3 ase_vertex3Pos = v.vertex.xyz;
float3 Vertexpos163 = ase_vertex3Pos;
float HorizontalStretch217 = lerp(0.0,( (sin( mulTime190 )*_Horizontalstretchamplitude + _Horizontalstretchoffset) * ( _Horizontalstretchpivotpoint + Vertexpos163.x ) ),_Horizontalstretch);
float mulTime111 = _Time.y * _Verticalmovementfreq;
float VerticalMovement210 = lerp(0.0,(sin( mulTime111 )*_Verticalmovementamplitude + _Verticalmovementoffset),_Verticalmovement);
float mulTime91 = _Time.y * _Verticalstretchfreq;
float VerticalStretch215 = lerp(0.0,( (sin( mulTime91 )*_Verticalstretchamplitude + _Verticalstretchoffset) * ( _Verticalstretchpivotpoint + Vertexpos163.y ) ),_Verticalstretch);
float4 appendResult86 = (float4(( HorizontalMovement212 + HorizontalStretch217 ) , ( VerticalMovement210 + VerticalStretch215 ) , 0.0 , 0.0));
v.vertex.xyz += appendResult86.xyz;
}
- 初始化Input变量
UNITY_INITIALIZE_OUTPUT( Input, o );
中间插一下,讲一下别的东西(一个简单的公式):
y = Asin(ωx + φ) + k
这是一个正弦函数(当然不是标准的),重点不在这里,如果足够细心,你会发现作者通篇应用了这个函数,在这个函数中
振幅: A(Amplitude)
频率:ω / 2π(Frequency)
初相:φ(PrimaryPhase)
偏移:k(Offset)
这也意味着作者的大部分效果是一个具有固定周期的往复运动,通过这些参数让我们更好的调整效果,所以,显而易见:
- 顶点水平位移:
float mulTime201 = _Time.y * _Horizontalmovementfreq;
float HorizontalMovement212 = lerp(0.0,(sin( mulTime201 )*_Horizontalmovementamplitude + _Horizontalmovementoffset),_Horizontalmovement);
- 顶点水平拉伸:
float mulTime190 = _Time.y * _Horizontalstretchfreq;
float HorizontalStretch217 = lerp(0.0,( (sin( mulTime190 )*_Horizontalstretchamplitude + _Horizontalstretchoffset) * ( _Horizontalstretchpivotpoint + Vertexpos163.x ) ),_Horizontalstretch);
其中和顶点水平位移不同的是,在sin函数处理完之后和锚点的偏移参数相乘,达到了顶点拉伸的效果;
- 顶点垂直位移:
float mulTime111 = _Time.y * _Verticalmovementfreq;
float VerticalMovement210 = lerp(0.0,(sin( mulTime111 )*_Verticalmovementamplitude + _Verticalmovementoffset),_Verticalmovement);
- 顶点垂直拉伸(对锚点的处理和水平相同):
float mulTime91 = _Time.y * _Verticalstretchfreq;
float VerticalStretch215 = lerp(0.0,( (sin( mulTime91 )*_Verticalstretchamplitude + _Verticalstretchoffset) * ( _Verticalstretchpivotpoint + Vertexpos163.y ) ),_Verticalstretch);
- 最后合并结果并返回:
float4 appendResult86 = (float4(( HorizontalMovement212 + HorizontalStretch217 ) , ( VerticalMovement210 + VerticalStretch215 ) , 0.0 , 0.0));
v.vertex.xyz += appendResult86.xyz;
在顶点函数中,这两段重复代码:
float3 ase_vertex3Pos = v.vertex.xyz;
float3 Vertexpos163 = ase_vertex3Pos;
作者定义了两个相同的变量,却只有Vertexpos163被使用,我并不认为是作者故意的;在作者的GitHub主页上作者说是通过Amplify Shader Editor实现的,没用过(ASE???类似于shader Graph的可编程插件),猜测是在连连看时为了布局好看(也许),生成了多余的变量。
- 表面函数:
void surf( Input i , inout SurfaceOutputStandard o )
{
float mulTime99 = _Time.y * _Globalemissionflickerfreq;
float EmissionFlicker228 = lerp(1.0,(pow( sin( mulTime99 ) , 2.0 )*(0.0 + (_Globalemissionflickeramplitude - 0.0) * (0.1 - 0.0) / (1.0 - 0.0)) + _Globalemissionflickeroffset),_Globalemissionflicker);
float mulTime147 = _Time.y * _ScanlinesspeedX;
float clampResult150 = clamp( sin( (i.uv_texcoord.x*_ScanlinesscaleX + mulTime147) ) , 0.0 , 1.0 );
float ScanlinesX220 = lerp(1.0,lerp(clampResult150,ceil( clampResult150 ),_SharpX),_ScanlinesX);
float mulTime26 = _Time.y * _ScanlinesspeedY;
float clampResult175 = clamp( sin( (i.uv_texcoord.y*_ScanlinesscaleY + mulTime26) ) , 0.0 , 1.0 );
float ScanlinesY222 = lerp(1.0,lerp(clampResult175,ceil( clampResult175 ),_SharpY),_ScanlinesY);
float3 ase_vertex3Pos = mul( unity_WorldToObject, float4( i.worldPos , 1 ) );
float mulTime154 = _Time.y * _ScanlinesspeedZ;
float clampResult157 = clamp( sin( (ase_vertex3Pos.z*_ScanlinesscaleZ + mulTime154) ) , 0.0 , 1.0 );
float ScanlinesZ224 = lerp(1.0,lerp(clampResult157,ceil( clampResult157 ),_SharpZ),_ScanlinesZ);
float2 appendResult70 = (float2(_ScrollingspeedX , _ScrollingspeedY));
float2 temp_output_80_0 = (float2( 0,0 ) + (_Offset - float2( 0,0 )) * (float2( 1,1 ) - float2( 0,0 )) / (float2( 360,360 ) - float2( 0,0 )));
float2 uv_TexCoord7 = i.uv_texcoord * _Tiling + temp_output_80_0;
float2 panner4 = ( _Time.y * appendResult70 + uv_TexCoord7);
float2 uv_TexCoord185 = i.uv_texcoord * _Tiling + temp_output_80_0;
float mulTime181 = _Time.y * _RotationSpeed;
float cos179 = cos( mulTime181 );
float sin179 = sin( mulTime181 );
float2 rotator179 = mul( uv_TexCoord185 - ( _Tiling * float2( 0.5,0.5 ) ) , float2x2( cos179 , -sin179 , sin179 , cos179 )) + ( _Tiling * float2( 0.5,0.5 ) );
#if defined(_SCROLLROTATE_SCROLL)
float2 staticSwitch187 = panner4;
#elif defined(_SCROLLROTATE_ROTATE)
float2 staticSwitch187 = rotator179;
#elif defined(_SCROLLROTATE_NONE)
float2 staticSwitch187 = uv_TexCoord7;
#else
float2 staticSwitch187 = panner4;
#endif
float4 PannedRotatedTexture231 = tex2D( _Tex, staticSwitch187 );
float4 CombinedTexture41 = ( EmissionFlicker228 * ScanlinesX220 * ScanlinesY222 * ScanlinesZ224 * PannedRotatedTexture231 );
float3 hsvTorgb125 = RGBToHSV( CombinedTexture41.rgb );
float3 hsvTorgb126 = RGBToHSV( _Color.rgb );
float3 hsvTorgb127 = HSVToRGB( float3(( hsvTorgb125.x + hsvTorgb126.x ),hsvTorgb125.y,hsvTorgb125.z) );
float2 uv_TexCoord238 = i.uv_texcoord * _Masktexturetiling + _Masktextureoffset;
float mulTime247 = _Time.y * _Masktexturerotationspeed;
float cos248 = cos( mulTime247 );
float sin248 = sin( mulTime247 );
float2 rotator248 = mul( uv_TexCoord238 - ( _Masktexturetiling * float2( 0.5,0.5 ) ) , float2x2( cos248 , -sin248 , sin248 , cos248 )) + ( _Masktexturetiling * float2( 0.5,0.5 ) );
float Masktexture241 = tex2D( _Masktexture, rotator248 ).a;
float CombinedTexture_alpha51 = ( CombinedTexture41.a * Masktexture241 );
#if defined(_COLORMODE_ORIGINAL)
float4 staticSwitch40 = CombinedTexture41;
#elif defined(_COLORMODE_HUESHIFT)
float4 staticSwitch40 = float4( hsvTorgb127 , 0.0 );
#elif defined(_COLORMODE_MULTIPLY)
float4 staticSwitch40 = ( CombinedTexture41 * _Color );
#elif defined(_COLORMODE_REPLACE)
float4 staticSwitch40 = ( _Color * CombinedTexture_alpha51 );
#else
float4 staticSwitch40 = ( CombinedTexture41 * _Color );
#endif
float4 FinalEmission234 = staticSwitch40;
o.Emission = FinalEmission234.rgb;
o.Alpha = CombinedTexture_alpha51;
}
- 在表面函数里作者先处理的是自发光:
float mulTime99 = _Time.y * _Globalemissionflickerfreq;
float EmissionFlicker228 = lerp(1.0,(pow( sin( mulTime99 ) , 2.0 )*(0.0 + (_Globalemissionflickeramplitude - 0.0) * (0.1 - 0.0) / (1.0 - 0.0)) + _Globalemissionflickeroffset),_Globalemissionflicker);
在这里作者首先对原始sin函数进行了pow(平方),让我不明白的是作者为什么做一些无意义的运算:加0、减0,除以1……如果有知道的朋友拿饭告诉我一声,在此感谢;
- x轴扫描线:
float mulTime147 = _Time.y * _ScanlinesspeedX;
float clampResult150 = clamp( sin( (i.uv_texcoord.x*_ScanlinesscaleX + mulTime147) ) , 0.0 , 1.0 );
float ScanlinesX220 = lerp(1.0,lerp(clampResult150,ceil( clampResult150 ),_SharpX),_ScanlinesX);
在这里作者对sin函数的结果进行了clamp(截断),限制在了0和1之间,由于sin函数的值域为-1到1,所有在sin函数的一个完整周期内会有一半的数据为0,另一半数据为0到1,在图像上表现为一半黑一半渐变为白色,作者在后边的代码中对这个数据相乘来实现在x轴上把画面切割的效果,其他两个轴的是相同的原理;同时在第三行代码中作者通过ceil函数对数据向上取整,来保证数据统一,实际就是通过了_SharpX这个参数控制clampResult150是否从0渐变为1还是全为1,在视觉效果上就是渐变强度或整体统一强度;
- y轴扫描线:
float mulTime26 = _Time.y * _ScanlinesspeedY;
float clampResult175 = clamp( sin( (i.uv_texcoord.y*_ScanlinesscaleY + mulTime26) ) , 0.0 , 1.0 );
float ScanlinesY222 = lerp(1.0,lerp(clampResult175,ceil( clampResult175 ),_SharpY),_ScanlinesY);
- z轴扫描线:
float3 ase_vertex3Pos = mul( unity_WorldToObject, float4( i.worldPos , 1 ) );
float mulTime154 = _Time.y * _ScanlinesspeedZ;
float clampResult157 = clamp( sin( (ase_vertex3Pos.z*_ScanlinesscaleZ + mulTime154) ) , 0.0 , 1.0 );
float ScanlinesZ224 = lerp(1.0,lerp(clampResult157,ceil( clampResult157 ),_SharpZ),_ScanlinesZ);
z轴和x轴和y轴不同,x轴和y轴操作的是uv,z轴操作的是深度,在实际效果上有点诡异(自己试一下就知道了),并没有看到作者使用z轴进行扫描;
- uv滚动:
float2 appendResult70 = (float2(_ScrollingspeedX , _ScrollingspeedY));
float2 temp_output_80_0 = (float2( 0,0 ) + (_Offset - float2( 0,0 )) * (float2( 1,1 ) - float2( 0,0 )) / (float2( 360,360 ) - float2( 0,0 )));
float2 uv_TexCoord7 = i.uv_texcoord * _Tiling + temp_output_80_0;
float2 panner4 = ( _Time.y * appendResult70 + uv_TexCoord7);
float2 uv_TexCoord185 = i.uv_texcoord * _Tiling + temp_output_80_0;
在temp_output_80_0这个变量上,原谅我并没有看懂,尤其是那个360;
- uv旋转:
float mulTime181 = _Time.y * _RotationSpeed;
float cos179 = cos( mulTime181 );
float sin179 = sin( mulTime181 );
float2 rotator179 = mul( uv_TexCoord185 - ( _Tiling * float2( 0.5,0.5 ) ) , float2x2( cos179 , -sin179 , sin179 , cos179 )) + ( _Tiling * float2( 0.5,0.5 ) );
偏移至中心,通过旋转矩阵进行uv旋转;
- 通过宏处理滚动/旋转
#if defined(_SCROLLROTATE_SCROLL)
float2 staticSwitch187 = panner4;
#elif defined(_SCROLLROTATE_ROTATE)
float2 staticSwitch187 = rotator179;
#elif defined(_SCROLLROTATE_NONE)
float2 staticSwitch187 = uv_TexCoord7;
#else
float2 staticSwitch187 = panner4;
#endif
- 合并主贴图计算结果:
float4 PannedRotatedTexture231 = tex2D( _Tex, staticSwitch187 );
float4 CombinedTexture41 = ( EmissionFlicker228 * ScanlinesX220 * ScanlinesY222 * ScanlinesZ224 * PannedRotatedTexture231 );
合并自发光、扫描线;
- 计算Hueshift(Colormode):
float3 hsvTorgb125 = RGBToHSV( CombinedTexture41.rgb );
float3 hsvTorgb126 = RGBToHSV( _Color.rgb );
float3 hsvTorgb127 = HSVToRGB( float3(( hsvTorgb125.x + hsvTorgb126.x ),hsvTorgb125.y,hsvTorgb125.z) );
- 通过宏控制颜色混合模式:
#if defined(_COLORMODE_ORIGINAL)
float4 staticSwitch40 = CombinedTexture41;
#elif defined(_COLORMODE_HUESHIFT)
float4 staticSwitch40 = float4( hsvTorgb127 , 0.0 );
#elif defined(_COLORMODE_MULTIPLY)
float4 staticSwitch40 = ( CombinedTexture41 * _Color );
#elif defined(_COLORMODE_REPLACE)
float4 staticSwitch40 = ( _Color * CombinedTexture_alpha51 );
#else
float4 staticSwitch40 = ( CombinedTexture41 * _Color );
#endif
- 输出最终颜色和Alpha:
float4 FinalEmission234 = staticSwitch40;
o.Emission = FinalEmission234.rgb;
o.Alpha = CombinedTexture_alpha51;
- 最后还有一个自定义面板:
CustomEditor "TexturePannerEditor"
通篇读下来,感觉就是把一堆单独的效果组装到了一起;不过有一点无论某个模块的功能你用还是不用,代码都会运算一遍,感觉做了很多无用功,可能大概还需要优化吧!
- 补充一点toggle的用法:
toggle:0或1
floatx value = lerp(0,计算的值,toggle);
其实,还是想分析一下TexturePannerEditor的,但是在写这篇博客的过程中被打断了3次,搞得一点脾气都没有!好吧,就这样吧!!!