14.表面着色器顶点膨胀

14.表面着色器-实例分析-顶点膨胀


14.1 知识点

表面着色器中如何处理顶点

在表面着色器的编译指令中,可以通过可选额外参数添加顶点处理函数,用于对顶点进行预处理。
例如,在编译指令中添加 vertex:自定义函数名,要求自定义的顶点函数格式为:

void 自定义函数名(inout appdata_full v)

实现顶点膨胀效果

主要步骤

  • 在Lesson13已有法线贴图代码的基础上进行修改
  • 加入顶点碰撞控制参数
  • 在编译指令中添加顶点处理函数
  • 自定义顶点处理函数,在该函数中对顶点进行偏移

加入顶点碰撞控制参数 _Expansion 并进行映射

在材质属性中定义扩展参数:

Properties
{
    // …
    _Expansion("Expansion", Float) = 0   // 顶点沿法线方向的偏移量(扩展效果)
}

并声明对应变量:

float _Expansion;  // 控制顶点扩展效果

在编译指令中加入顶点处理函数

使用物理基础的标准光照模型,启用全前向阴影,并指定自定义顶点函数:

#pragma surface surf Standard fullforwardshadows vertex:vertexFunc

自定义顶点处理函数

在顶点着色阶段对顶点进行偏移,实现几何体“膨胀”效果:

// 自定义顶点函数:在顶点着色阶段对顶点进行偏移
void vertexFunc(inout appdata_full v)
{
    // 顶点坐标沿法线方向偏移,实现几何体“膨胀”效果
    v.vertex.xyz += v.normal * _Expansion;
}

修改参数查看效果

调整 _Expansion 参数,可直观观察几何体顶点沿法线方向的膨胀效果。

感受最终颜色处理函数

主要步骤

在可选额外参数中添加颜色处理函数 finalcolor,自定义的颜色函数格式为:

void 自定义函数名(Input IN, SurfaceOutput... o, inout fixed4 color)

在编译指令中指定颜色函数

使用物理基础的标准光照模型,启用全前向阴影,并同时指定自定义顶点和颜色处理函数:

#pragma surface surf Standard fullforwardshadows vertex:vertexFunc finalcolor:colorFunc

表面函数中漫反射阶段不叠加基础颜色

表面函数负责计算每个像素的材质属性,修改Albedo赋值,o.Albedo = texColor.rgb代表先不叠加颜色。Lesson13是直接o.Albedo = texColor.rgb * _Color.rgb;叠加颜色的。

void surf (Input IN, inout SurfaceOutputStandard o)
{
    fixed4 texColor = tex2D(_MainTex, IN.uv_MainTex);
    o.Albedo = texColor.rgb;                   // 漫反射颜色直接使用基础纹理的颜色
    o.Alpha = texColor.a * _Color.a;             // 透明度受基础颜色的 alpha 影响
    o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));  // 通过法线贴图解包得到切线空间法线

    // o.Emission = _Emission.rgb;               // 发光效果(暂未启用)
    o.Metallic = _Metallic;
    o.Smoothness = _Smoothness;
}

在自定义颜色函数中叠加基础颜色

自定义颜色函数在片元着色阶段调整最终输出颜色,在计算完成后将基础颜色叠加到结果上:

void colorFunc(Input IN, SurfaceOutputStandard o, inout fixed4 color)
{
    // 最终输出颜色乘以基础颜色,实现颜色调节
    color *= _Color;
}

查看效果

通过调整相关参数和观察 Shader 在场景中的表现,查看顶点膨胀与颜色叠加效果。


14.2 知识点代码

Lesson14.shader

Shader "Custom/Lesson14"
{
    Properties
    {
        _Color ("Color", Color) = (1,1,1,1)            // 材质基础颜色
        _MainTex ("Albedo (RGB)", 2D) = "white" {}       // 基础纹理
        _BumpMap("BumpMap", 2D) = ""{}                  // 法线贴图

        //_Emission("Emission", Color) = (1,1,1,1)       // 发光属性(暂未启用)
        _Metallic("Metallic", Range(0,1)) = 0            // 金属度
        _Smoothness("Smoothness", Range(0,1)) = 0        // 平滑度

        _Expansion("Expansion", Float) = 0              // 顶点沿法线方向的偏移量(扩展效果)
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }  // 标记为不透明材质

        CGPROGRAM
        // 使用物理基础的标准光照模型,启用全前向阴影,并指定自定义顶点和颜色函数
        #pragma surface surf Standard fullforwardshadows vertex:vertexFunc finalcolor:colorFunc
        #pragma target 3.0  // 指定Shader Model 3.0

        fixed4 _Color;
        sampler2D _MainTex;
        sampler2D _BumpMap;
        //fixed4 _Emission;
        fixed _Metallic;
        fixed _Smoothness;
        float _Expansion;  // 控制顶点扩展效果

        // 输入结构体:包含用于采样纹理的UV坐标
        struct Input
        {
            float2 uv_MainTex;
            float2 uv_BumpMap;
        };

        // 表面函数:计算每个像素的材质属性
        void surf (Input IN, inout SurfaceOutputStandard o)
        {
            fixed4 texColor = tex2D(_MainTex, IN.uv_MainTex);
            o.Albedo = texColor.rgb;                   // 漫反射颜色直接使用基础纹理的颜色
            o.Alpha = texColor.a * _Color.a;             // 透明度受基础颜色的alpha影响
            o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_BumpMap));  // 通过法线贴图解包得到切线空间法线

            //o.Emission = _Emission.rgb;               // 发光效果(暂未启用)
            o.Metallic = _Metallic;
            o.Smoothness = _Smoothness;
        }

        // 自定义顶点函数:在顶点着色阶段对顶点进行偏移
        void vertexFunc(inout appdata_full v)
        {
            // 顶点坐标沿法线方向偏移,实现几何体“膨胀”效果
            v.vertex.xyz += v.normal * _Expansion;
        }

        // 自定义颜色函数:在片元着色阶段调整最终输出颜色
        void colorFunc(Input IN, SurfaceOutputStandard o, inout fixed4 color)
        {
            // 最终输出颜色乘以基础颜色,实现颜色调节
            color *= _Color;
        }

        ENDCG
    }
    FallBack "Diffuse"  // 当当前Shader不可用时使用Diffuse Shader作为后备
}

Lesson14_表面着色器_实例分析_顶点膨胀.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson14_表面着色器_实例分析_顶点膨胀 : MonoBehaviour
{
    void Start()
    {
        #region 知识回顾 表面着色器中如何处理顶点?

        //在编译指令中
        //#pragma surface 表面函数名 光照模型 可选额外参数
        //可选额外参数中添加
        //vertex:自定义函数名
        //函数格式:
        //void 自定义函数名(inout appdata_full v)

        #endregion

        #region 知识点一 实现顶点膨胀效果

        //直接在Lesson13实现法线贴图的代码中进行修改即可
        //1.加入顶点碰撞控制参数
        //2.在编译指令中加入顶点处理函数
        //3.自定义顶点处理函数
        //4.在该函数中对顶点进行偏移

        #endregion

        #region 知识点二 感受最终颜色处理函数

        //可选额外参数中添加
        //finalcolor:自定义函数名
        //函数格式:
        //void 自定义函数名(Input IN, SurfaceOutput... o, inout fixed4 color)

        #endregion
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏