Unity Surface Shader——自定义顶点修改函数

唐福幸 发表于    2021年10月12日 13:56
4121
1
13

拿一个飞毯效果作为讲解案例,开始之前先展示最终效果:


录制_2021_10_12_15_58_22_697(1).gif

最终效果


准备工作

1.在新场景里创建两个Plane,一个名为Ground,一个名为Carpet,缩放到适合的大小


2.创建两个材质,跟两个Plane的名字保持一致,并赋予给上一步创建的Plane


3.自己找适合的地面贴图贴在Ground材质上即可


4.新建SurfaceShader,拖给Carpet材质,然后开始编写shader

定义Inspector属性

    Properties
   {
       _MainTex ("Albedo (RGBA)", 2D) = "white" {}
       _AlphaTest("AlphaTest", Range(0, 1)) = 0

       _MetallicTex("Metallic", 2D) = "white"{}
       _Metallic ("Intensity", Range(0,1)) = 0.0
       _SmoothnessTex("Smoothness", 2D) = "white"{}
       _Smoothness ("Intensity", Range(0,1)) = 0

       _NormalTex("Normal", 2D) = "bump"
       _Normal("Intensity", float) = 1

       _Speed("Speed", float) = 1
       _Frequency("Frequency", float) = 1
       _Amplitude("Amplitude", float) = 1
   }


1.定义了物理材质常用的Albedo、Metallic、Smoothness、Normal


2.然后又定义了飞毯的飞行速度,波浪出现的频率和波浪起伏的高度


3._AlphaTest属性是为了接下来传给alphatest,用于像素裁切

渲染类型、顺序、光照模型等一系列设置

        Tags 
       {
           "RenderType" = "Opaque"
           "Queue" = "AlphaTest"
       }
       LOD 200
       CULL Off

       CGPROGRAM
       #pragma surface surf Standard fullforwardshadows vertex:vert addshadow alphatest:_AlphaTest

       #pragma target 3.0


1.渲染类型为不透明


2.渲染顺序为透明度测试


3.CULL off:关闭模型面的剔除,这样模型的背面也会被渲染


4.使用默认的Standard光照模型


5.我们使用自定义的顶点函,命名为vert


6.修改了顶点函数之后,投影会出现跟模型不一致的现象,所以使用addshadow指令重新计算正确投影


7.透明类型为alphatest,然后把一开始定义的_AlphaTest属性传递过来,小于这个数值的像素会被裁切,大于这个数值的像素会被保留

定义属性和结构体

sampler2D _MainTex;
       sampler2D _MetallicTex;
       sampler2D _SmoothnessTex;
       sampler2D _NormalTex;

       struct Input
       {
           float2 uv_MainTex;
       };

       half _Smoothness;
       half _Metallic;
       float _Normal;

       half _Speed;
       half _Frequency;
       half _Amplitude;


1.在CG里重新定义之前的属性


2.定义Input结构体存储贴图坐标。


这里只是存储了Albedo贴图的坐标,接下来对所有贴图的采样都会使用Albedo的坐标,这么做有两大好处:

1.减少插值寄存器的数量,节省性能消耗


2.在材质的Inspector上只需要修改Albedo即可调整所有贴图的UV坐标

定义顶点函数

void vert(inout appdata_full v)
       {
           float time = _Time.y * _Speed;
           float offset = (sin(time + v.vertex.z * _Frequency)) * _Amplitude;

           v.vertex.y += offset;
       }


1.这里使用了CG里提供的时间变量Time的y分量乘以_Speed属性,得到新的时间变量,以后我们就可以在材质的Inspector通过调节Speed属性控制飞毯的速度了


2.顶点z轴的坐标与_Frequency相乘,相当于对z轴进行了一个范围的缩放。然后跟time变量相加,是为了把顶点Z轴方向与时间结合在一起变为动态变量。经过sin处理之后,可以得出一个随时间推迟而循环浮动的偏移值。最后乘以_Amplitude属性可以控制偏移的大小


3.顶点的y方向加上这个偏移值,实现垂直方向上的上下浮动效果

定义表面函数

void surf (Input IN, inout SurfaceOutputStandard o)
       {
           fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
           o.Albedo = c.rgb;
           o.Alpha = c.a;
           o.Metallic = tex2D(_MetallicTex, IN.uv_MainTex) * _Metallic;
           o.Smoothness = tex2D(_SmoothnessTex, IN.uv_MainTex) *  _Smoothness;

           fixed3 n = UnpackNormal(tex2D(_NormalTex, IN.uv_MainTex)).rgb;
           n.x *= _Normal;
           n.y *= _Normal;
           o.Normal = n;
       }
       ENDCG


1.使用Albedo贴图的坐标对所有的贴图进行采样,得出表面函数最终的输出变量


2.法线的x和y分量分别乘以_Normal属性,可以控制法线强度,最终输出到表面函数的法线变量

贴图

本次案例使用的是一张带有Alpha通道的贴图,Alpha通道用于透明测试。


RGB通道


A通道

Inspector参数设置

最后再展示一遍最终的效果:

录制_2021_10_12_15_58_22_697(1).gif


从动图可以看出,地面上接受到了飞毯的动态投影,并且灯光也穿过了破洞,射在了地面上。

可以说投影计算的非常完美。



发表于    2021年10月12日 13:56
关于作者
唐福幸
回答
0
文章
0
粉丝
194

相关文章

URL已复制到剪贴板!