> Shader Vertex 的初步使用。
Basic
Example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| Shader "Custom/vertexShader" { Properties { _Color ("Color", Color) = (1,1,1,1) } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM #pragma surface surf Lambert vertex : vert #pragma target 2.0
struct Input { float2 uv_MainTex; float4 vertColor; };
fixed4 _Color;
void vert (inout appdata_full v,out Input o) { o.vertColor = v.color; }
void surf (Input IN, inout SurfaceOutput o) { o.Albedo = IN.vertColor.rgb * _Color.rgb; } ENDCG } FallBack "Diffuse" }
|
参数详情
- appdata_full 位于UnityCG.cginc . 顾名思义保存了顶点的绝大部分可用于计算的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| struct appdata_full { float4 vertex : POSITION; float4 tangent : TANGENT; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; float4 texcoord1 : TEXCOORD1; float4 texcoord2 : TEXCOORD2; float4 texcoord3 : TEXCOORD3; #if defined(SHADER_API_XBOX360) half4 texcoord4 : TEXCOORD4; half4 texcoord5 : TEXCOORD5; #endif fixed4 color : COLOR; };
|
这里还包含两个appdata_full的简化版,其实都一样 什么时候要用简化版?当然是越简化越省性能。
1 2 3 4 5 6 7 8 9 10 11 12
| struct appdata_base { float4 vertex : POSITION; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; };
struct appdata_tan { float4 vertex : POSITION; float4 tangent : TANGENT; float3 normal : NORMAL; float4 texcoord : TEXCOORD0; };
|
2. SurfaceOutput 位于Lighting.cginc . 这可以说是最常见的一个结构体了但还是稍微写下吧。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| struct SurfaceOutput { fixed3 Albedo; fixed3 Normal; fixed3 Emission; half Specular; fixed Gloss; fixed Alpha; };
|
Effect
效果展示
效果就是文章首页放的图了。下面的算法我就不解释了,毕竟这数学也不是靠别人能说清楚的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| Shader "test/vertexAnimation" { Properties { _ColorA ("Color", Color) = (1,1,1,1) _ColorB ("Color", Color) = (1,1,1,1) _MainTex ("Albedo (RGB)", 2D) = "white" {} _TintAmount("TintAmount",Range(0,1)) = 0.5 _Speed("Wave Speed",Range(0.1,80)) = 1 _Frequency("Wave Frequency",Range(0,5)) = 2 _Amplitude("Wave Amplitude",Range(-1,1)) = 1 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM #pragma surface surf Lambert vertex:vert
#pragma target 2.0
sampler2D _MainTex; fixed4 _ColorA; fixed4 _ColorB; float _TintAmount; float _Speed; float _Frequency; float _Amplitude;
struct Input{ float2 uv_MainTex; float4 vertColor; };
void vert (inout appdata_full v,out Input o) { UNITY_INITIALIZE_OUTPUT(Input,o); float time = _Time * _Speed; float waveValueA = sin(time + v.vertex.x * _Frequency) * _Amplitude;
v.vertex.xyz = float3(v.vertex.x , v.vertex.y + waveValueA , v.vertex.z); v.normal = normalize(float3(v.normal.x + waveValueA,v.normal.y,v.normal.z)); o.vertColor = float4(waveValueA,waveValueA,waveValueA,255); }
void surf (Input IN, inout SurfaceOutput o) { // Albedo comes from a texture tinted by color fixed4 c = tex2D (_MainTex, IN.uv_MainTex); float3 tintColor = lerp(_ColorA,_ColorB,IN.vertColor).rgb; o.Albedo = c.rgb * (tintColor * _TintAmount); o.Alpha = c.a; } ENDCG } FallBack "Diffuse" }
|
WARNING
#pragma声明函数
在 #pragma 声明函数的时候,不要重名否则会报错。这是常识,引擎编译的时候会自动搜索所有编译期文件是否包含此函数。
in out inout
in out inout 是cg语言提供的输入输出关键字,用来表示图形硬件上的不同寄存器。
引用《GPU 编程与CG 语言之阳春白雪下里巴人》的一段话来概括:
1 2 3 4 5 6 7 8
| 1. in: 修辞一个形参只是用于输入,进入函数体时被初始化,且该形参值 的改变不会影响实参值,这是典型的值传递方式。 2. out: 修辞一个形参只是用于输出的,进入函数体时并没有被初始化,这 种类型的形参一般是一个函数的运行结果; 3. inout: 修辞一个形参既用于输入也用于输出,这是典型的引用传递。 举例如下: void myFunction(out float x); void myFunction(inout float x); void myFunction(in float x); void myFunction(float x); /等价与 in float x,这种用法和 C\C++完全一致 也可以使用 return 语句来代替 out 修辞符的使用。输入\输出修辞符通常和语 义词一起使用,表示顶点着色程序和片段着色程序的输入输出。
|
使用Lambert的vertex
使用Lambert的vertex自定义函数的时候编辑器默认会报错,这个时候加入下面代码。这些代码可以看作是对Direcxtx11的hack。
1
| UNITY_INITIALIZE_OUTPUT(Input,o);
|
使用_Time
如果直接使用_Time * Float 那么默认使用_Time.x
1
| float4 _Time : Time (t/20, t, t*2, t*3), use to animate things inside the shaders
|
本文标题:Shder顶点动画
文章作者:Keyle
发布时间:2016-04-21
最后更新:2024-08-20
原始链接:https://vrast.cn/posts/cc147fdd/
版权声明:©Keyle's Blog. 本站采用署名-非商业性使用-相同方式共享 4.0 国际进行许可