Skip to content

Commit

Permalink
对表面着色器中的顶点使用动画
Browse files Browse the repository at this point in the history
  • Loading branch information
linkliu committed Jul 9, 2022
1 parent 0eeaca6 commit 61ce891
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
---
category: shader
tags: [U3D, Shader,Cookbook,中文版]

---

## 对表面着色器中的顶点使用动画

我们现在知道了如何访问每个顶点数据的一些基础知识,这次让我们更进一步的了解一些其他类型的数据和顶点的位置。

使用顶点函数,我们可以访问网格中每个顶点位置。具体来说就是可以在着色器处理渲染的过程中,这些函数可以让我们单独对每一个顶点进行修改。

这个知识点当中,我们会创建一个着色器,并且用三角函数的正弦函数(**sine wave**)来修改网格当中的每一个顶点。该技术可以用来创建旗子飘动或者海浪等物体动画。

***

- **始前准备**
我们把资源都放一块儿,这样方便我们为顶点着色器( **Vertex Shader** )编写代码:
- 1.创建一个新的场景,并且创建一个平面网格( **plane mesh** ),把它放在场景正中央,位置归零。
- 2.然后创建一个新的材质和着色器。
- 3.最后,把着色器挂到材质上,在把材质挂到平面网格上。

最终,你的场景看起来应该跟下图一样:
![diagram](https://linkliu.github.io/game-tech-post/assets/img/shader_book/diagram60.png){: .shadow width = "90%" }

***
- **操作步骤**
场景创建好后,鼠标双击打开刚刚我们创建的着色器:
- 1.让我们给着色器的属性块下面的预设值:
``` C#
Properties
{
_MainTex ("Base (RGB)", 2D) = "white" {}
_tintAmount ("Tint Amount", Range(0,1)) = 0.5
_ColorA ("Color A", Color) = (1,1,1,1)
_ColorB ("Color B", Color) = (1,1,1,1)
_Speed ("Wave Speed", Range(0.1, 80)) = 5
_Frequency ("Wave Frequency", Range(0, 5)) = 2
_Amplitude ("Wave Amplitude", Range(-1, 1)) = 1
}
```
- 2.接下来我们通过下面的声明告诉Unity,我们需要使用顶点函数了,添加声明的位置在: **#pragma statement**
``` C#
CGPROGRAM
#pragma surface surf Lambert vertex:vert
```
- 3.为了访问属性块中的值,我们还要在 **CGPROGRAM** 块中声明与之对应的变量:
``` C#
sampler2D _MainTex;
float4 _ColorA;
float4 _ColorB;
float _tintAmount;
float _Speed;
float _Frequency;
float _Amplitude;
float _OffsetVal;
```
- 4.我们也将使用顶点位置的变化作为 **vert** 颜色。因为这样我们可以顺便修改物体的颜色了:
``` c#
struct Input
{
float2 uv_MainTex;
float3 vertColor;
}
```
- 5.此时,我们要修改顶点的表现了,我们要使用到下面的正选函数和顶点函数,在我们的 **Input Struct** 后面添加如下代码:
``` c#
void vert(inout appdata_full v, out 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 = float3(waveValueA,waveValueA,waveValueA);
}
```
- 6.最后,我们要使用一个 **lerp()** 函数对两个颜色进行一个插值,这样我们就可以对新网格的波峰和波谷应用不同的颜色,为了获得这种表现,添加下面的代码让顶点函数起作用:
``` c#
void surf (Input IN, inout SurfaceOutput o)
{
half4 c = tex2D (_MainTex, IN.uv_MainTex);
float3 tintColor = lerp(_ColorA, _ColorB, IN.vertColor).rgb;
o.Albedo = c.rgb * (tintColor * _tintAmount);
o.Alpha = c.a;
}
```


当你完成了着色器的编写后,回到Unity并且等待着色器编译完成。当编译完成后,你就会看到如下图所示的情形:

![diagram](https://linkliu.github.io/game-tech-post/assets/img/shader_book/diagram61.png){: .shadow width = "90%" }
***

- **原理介绍**
这个特定的着色器使用了我们上个知识点的一些概念,但不同的是,我们这里改变的是网格上那些顶点的位置。有时候你不想用骨骼结构( **skeleton structure** )或者是节点结构( **hierarchy of transforms** )来扣动画,
然后在简单的拼接它们,比如旗帜,在旗子上做动画然后跟旗杆组合拼接成旗帜。这个时候你使用这个着色器就特别有用了。

我们简单的使用了正弦函数 **sin()** 来创建正弦波,这个函数式Cg语言内建的。当计算好正弦值后,我们把这个值赋值给了每个顶点位置的 **y**,然后就产生了波动的效果。

当然我们还顺便稍微修改了网格上面的法线,让它针对正弦波有更真实的着色。

从这里你也可以知道,通过利用表面着色器内建的顶点参数,来获得一些比较复杂的顶点效果,还是比较容易的。


Binary file added assets/img/shader_book/diagram60.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/img/shader_book/diagram61.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 61ce891

Please sign in to comment.