[toc]

曲面细分 在渲染流水线中处在顶点着色器之后 片元着色器之前

其功能主要是通过曲面细分来增加模型的细节,通常曲面细分会配合三张图

  • 颜色图,即主纹理
  • 高度图,即高度映射
  • 法线贴图,即顶点的法线方向

在 ShaderLab 的 SurfaceShader 中,如果想声明一个曲面细分函数,需要在预声明中添加 tessellation: 函数名 该函数只需要返回一个整数即可,即细分级别

常见的流程为:通过高度图处理顶点高度 —> 通过曲面细分对顶点进行细分 -> 通过法线贴图对顶点法线进行修改 -> 通过 Color 贴图对顶点进行着色

采样函数: tex2Dlod () [注意 Lod], 是可以指定等级的,这个等级对应 mipmap 的等级,tex2D 只能在片元着色器中采样,而 tex2Dlod () 可以在任意着色器中采样.

# 效果

仅由一个 Unity 内置的 plane 生成

曲面细分

# 代码

Shader “Custom/Tesselation”
{
Properties
{
_MainTex(“Color”, 2D) = “white” {}
_Tessellation(“Tessellation”,Range(1,32)) = 1
_HeightMap(“Height Map”,2D) = “gray” {}
_Height(“Height”,Range(0,1.0)) = 0

    \_NormalMap("Normal Map",2D) = "bump" {}
    \_Bumpiness("Bumpiness",Range(0,1)) = 0.5
}

SubShader{
    CGPROGRAM
    //声明曲面细分函数和顶点修改函数的编译指令
    #pragma surface surf Lambert tessellate:tessellation vertex:height addshadow

    half \_Tessellation;
        
    //固定数量的曲面细分函数,只需要返回曲面细分等级
    float4 tessellation() {
        return \_Tessellation;
    }

    sampler2D \_HeightMap;
    float4 \_HeightMap\_ST;
    fixed \_Height;

    //顶点修改函数
    void height(inout appdata\_full v) {
        float2 texcoord = TRANSFORM\_TEX(v.texcoord, \_HeightMap);

        //对\_HeightMap采样,然后乘以\_Height
        float h = tex2Dlod(\_HeightMap, float4(texcoord, 0, 0)).r \* \_Height;

        //顶点沿着法线方向偏移h
        v.vertex.xyz += v.normal \* h;
    }

    struct Input {
        float2 uv\_MainTex;
        float2 uv\_NormalMap;
    };

    sampler2D \_MainTex;
    sampler2D \_NormalMap;
    fixed \_Bumpiness;

    void surf(Input IN, inout SurfaceOutput o) {
        half4 c = tex2D(\_MainTex, IN.uv\_MainTex);
        o.Albedo = c.rgb;

        float3 n = UnpackNormal(tex2D(\_NormalMap, IN.uv\_NormalMap));
        n.xy \*= fixed2(\_Bumpiness, \_Bumpiness);
        o.Normal = n;
    }

    ENDCG
}
FallBack "Diffuse"

}

以上是基于数量的曲面细分,还有集中其他的曲面细分方法,但都相差不大。主要是为了性能考虑而提出了,除此之外,还有 phong 曲面细分,这个主要是让模型更光滑.