返回介绍

提供顶点数据给顶点程序

发布于 2021-06-20 00:15:07 字数 6004 浏览 995 评论 0 收藏 0

顶点数据必须以一个结构的形式提交给 Cg/HLSL 顶点程序。几个常用的顶点结构定义在UnityCG.cginc 包含文件,大多数情况下只使用它们就足够了。这些结构是:

  • appdata_base: 顶点由位置、法线和一个纹理坐标构成。
  • appdata_tan: 顶点由位置、切线、法线和一个纹理坐标构成。
  • appdata_full: 顶点由位置、切线、法线、两个纹理坐标以及颜色构成。

例如,该着色器基于网格的法线来着色网格,且只使用 appdata_base 作为顶点程序输入:

Shader "VertexInputSimple" {
  SubShader {
    Pass {
      CGPROGRAM
      #pragma vertex vert
      #pragma fragment frag
      #include "UnityCG.cginc"

      struct v2f {
          float4 pos : SV_POSITION;
          fixed4 color : COLOR;
      };

      v2f vert (appdata_base v)
      {
          v2f o;
          o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
          o.color.xyz = v.normal * 0.5 + 0.5;
          o.color.w = 1.0;
          return o;
      }

      fixed4 frag (v2f i) : COLOR0 { return i.color; }
      ENDCG
    }
  } 
}

如果您想访问不同的顶点数据,您就必须自己声明顶点结构。结构成员必须是下面列出的成员:

  • float4 vertex 是顶点位置
  • float3 normal 是顶点法线
  • float4 texcoord 是第一个 UV 坐标
  • float4 texcoord1 是第二个 UV 坐标
  • float4 tangent 是切线向量(用于法线贴图)
  • float4 color 是逐顶点颜色

示例

可视化 UV

以下着色器示例使用顶点位置和第一个纹理坐标作为顶点着色器输入(定义在结构 appdata 中)。调试网格的 UV 坐标是非常有用的。UV 坐标被可视化为红色和绿色,0..1 范围外的坐标额外应用蓝色色调。

Shader "!Debug/UV 1" {
SubShader {
    Pass {
        Fog { Mode Off }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

// 顶点输入:位置、UV
struct appdata {
    float4 vertex : POSITION;
    float4 texcoord : TEXCOORD0;
};

struct v2f {
    float4 pos : SV_POSITION;
    float4 uv : TEXCOORD0;
};
v2f vert (appdata v) {
    v2f o;
    o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
    o.uv = float4( v.texcoord.xy, 0, 0 );
    return o;
}
half4 frag( v2f i ) : COLOR {
    half4 c = frac( i.uv );
    if (any(saturate(i.uv) - i.uv))
        c.b = 0.5;
    return c;
}
ENDCG
    }
}
}

调试着色器应用于一个环面纽结体模型的 UV1

类似地,这个着色器使模型的第二个 UV 集可视化:

Shader "!Debug/UV 2" {
SubShader {
    Pass {
        Fog { Mode Off }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

// 顶点输入:位置、第二个 UV
struct appdata {
    float4 vertex : POSITION;
    float4 texcoord1 : TEXCOORD1;
};

struct v2f {
    float4 pos : SV_POSITION;
    float4 uv : TEXCOORD0;
};
v2f vert (appdata v) {
    v2f o;
    o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
    o.uv = float4( v.texcoord1.xy, 0, 0 );
    return o;
}
half4 frag( v2f i ) : COLOR {
    half4 c = frac( i.uv );
    if (any(saturate(i.uv) - i.uv))
        c.b = 0.5;
    return c;
}
ENDCG
    }
}
}

可视化顶点颜色

以下着色器使用顶点位置和逐顶点颜色作为顶点着色器输入(定义在结构 appdata 中)。

Shader "!Debug/Vertex color" {
SubShader {
    Pass {
        Fog { Mode Off }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

// 顶点输入:位置、颜色
struct appdata {
    float4 vertex : POSITION;
    fixed4 color : COLOR;
};

struct v2f {
    float4 pos : SV_POSITION;
    fixed4 color : COLOR;
};
v2f vert (appdata v) {
    v2f o;
    o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
    o.color = v.color;
    return o;
}
fixed4 frag (v2f i) : COLOR0 { return i.color; }
ENDCG
    }
}
}

调试着色器应用于一个将照明烘焙成颜色的模型的颜色 (Color)

可视化法线

以下着色器使用顶点位置和法线作为顶点着色器输入(定义在结构 appdata 中)。法线的 X、Y、Z 组件被可视化为 R、G、B 颜色。因为法线组件在 -1..1 范围内,所以我们对其进行缩放和偏移,使得输出颜色在可显示的 0..1 范围内。

Shader "!Debug/Normals" {
SubShader {
    Pass {
        Fog { Mode Off }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

// 顶点输入:位置、法线
struct appdata {
    float4 vertex : POSITION;
    float3 normal : NORMAL;
};

struct v2f {
    float4 pos : SV_POSITION;
    fixed4 color : COLOR;
};
v2f vert (appdata v) {
    v2f o;
    o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
    o.color.xyz = v.normal * 0.5 + 0.5;
    o.color.w = 1.0;
    return o;
}
fixed4 frag (v2f i) : COLOR0 { return i.color; }
ENDCG
    }
}
}

调试着色器应用于一个模型的法线 (Normal)。您可以看见该模型具有硬着色边缘。

可视化切线和副法线

切线和副法线向量用于法线贴图。在 Unity 中,只有切线向量储存在顶点中,副法线衍生自法线和切线。

以下着色器使用顶点位置和切线作为顶点着色器输入(定义在结构 appdata 中)。切线的 X、Y、Z 组件被可视化为 R、G、B 颜色。因为法线组件在 -1..1 范围内,所以我们对其进行缩放和偏移,使得输出颜色在可显示的 0..1 范围内。

Shader "!Debug/Tangents" {
SubShader {
    Pass {
        Fog { Mode Off }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

// 顶点输入:位置、切线
struct appdata {
    float4 vertex : POSITION;
    float4 tangent : TANGENT;
};

struct v2f {
    float4    pos : SV_POSITION;
    fixed4    color : COLOR;
};
v2f vert (appdata v) {
    v2f o;
    o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
    o.color = v.tangent * 0.5 + 0.5;
    return o;
}
fixed4 frag (v2f i) : COLOR0 { return i.color; }
ENDCG
    }
}
}

调试着色器应用于一个模型切线 (Tangent)。

以下着色器使副法线可视化。它使用顶点位置、法线和切线作为顶点输入。副法线是从法线和切线计算出的。就像法线和切线一样,需要将其缩放并偏移到可显示的 0..1 范围内。

Shader "!Debug/Binormals" {
SubShader {
    Pass {
        Fog { Mode Off }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

// 顶点输入:位置、法线、切线
struct appdata {
    float4 vertex : POSITION;
    float3 normal : NORMAL;
    float4 tangent : TANGENT;
};

struct v2f {
    float4    pos : SV_POSITION;
    float4    color : COLOR;
};
v2f vert (appdata v) {
    v2f o;
    o.pos = mul( UNITY_MATRIX_MVP, v.vertex );
    // 计算副法线
    float3 binormal = cross( v.normal, v.tangent.xyz ) * v.tangent.w;
    o.color.xyz = binormal * 0.5 + 0.5;
    o.color.w = 1.0;
    return o;
}
fixed4 frag (v2f i) : COLOR0 { return i.color; }
ENDCG
    }
}
}

调试着色器应用于一个模型的副法线 (Binormal)。漂亮!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文