本教程将通过一个简单的纹理渲染着色器,介绍 ShaderLab 的基础语法结构,通过这个基础示例,你将学会:
ShaderLab 采用三层嵌套结构:Shader → SubShader → Pass
Shader "Tutorial/01-BasicShader" {
  SubShader "Default" {
    Pass "Forward" {
      // 着色器代码写在这里
    }
  }
}在 Pass 中,我们需要声明着色器使用的变量:
// 引擎内置变量:MVP 变换矩阵
mat4 renderer_MVPMat;
 
// 自定义材质属性
vec4 material_BaseColor;      // 基础颜色
sampler2D material_BaseTexture; // 纹理采样器使用结构体定义顶点数据和传递数据:
// 顶点着色器输入(从网格获取)
struct Attributes {
  vec4 POSITION;    // 顶点位置
  vec2 TEXCOORD_0;  // UV 坐标
};
 
// 顶点着色器输出 / 片元着色器输入
struct Varyings {
  vec2 uv;          // 传递给片元着色器的 UV 坐标
};内置顶点属性:
POSITION:顶点位置TEXCOORD_0:第一套UV坐标NORMAL:顶点法线COLOR_0:顶点颜色指定顶点着色器和片元着色器的入口函数:
VertexShader = vert;    // 顶点着色器入口
FragmentShader = frag;  // 片元着色器入口顶点着色器负责处理每个顶点的变换:
Varyings vert(Attributes attr) {
  Varyings output;
  
  // MVP 变换:将顶点从模型空间变换到裁剪空间
  gl_Position = renderer_MVPMat * attr.POSITION;
  
  // 传递 UV 坐标给片元着色器
  output.uv = attr.TEXCOORD_0;
  
  return output;
}关键点:
gl_Position 是内置输出变量,必须赋值片元着色器负责计算每个像素的颜色:
void frag(Varyings varying) {
  // 从纹理中采样颜色
  vec4 texColor = texture2D(material_BaseTexture, varying.uv);
  
  // 与材质基础颜色相乘
  vec4 finalColor = texColor * material_BaseColor;
  
  // 输出最终颜色
  gl_FragColor = finalColor;
}关键点:
texture2D() 函数用于纹理采样gl_FragColor 是内置输出变量,表示像素最终颜色纹理采样是着色器中的常见操作:
// 声明纹理采样器
sampler2D material_BaseTexture;
 
// 在片元着色器中采样
vec4 texColor = texture2D(material_BaseTexture, uv);采样参数:
让我们分析完整的着色器代码:
Shader "Tutorial/01-BasicShader" {
  SubShader "Default" {
    // Pass 是渲染通道,定义具体的渲染逻辑
    Pass "Forward" {
      // 引擎内置的 MVP 矩阵,用于顶点变换
      mat4 renderer_MVPMat;
      
      // 自定义的材质属性
      vec4 material_BaseColor;
      sampler2D material_BaseTexture;
      
      // 顶点着色器输入结构体 (Attributes)
      struct Attributes {
        vec4 POSITION;    // 顶点位置
        vec2 TEXCOORD_0;  // UV 坐标
      };
      
      // 顶点着色器输出 / 片元着色器输入结构体 (Varyings)
      struct Varyings {
        vec2 uv;          // 传递给片元着色器的 UV 坐标
      };
      
      // 指定着色器入口函数
      VertexShader = vert;
      FragmentShader = frag;
      
      // 顶点着色器:处理顶点变换和数据传递
      Varyings vert(Attributes attr) {
        Varyings output;
        
        // 将顶点从模型空间变换到裁剪空间
        gl_Position = renderer_MVPMat * attr.POSITION;
        
        // 传递 UV 坐标给片元着色器
        output.uv = attr.TEXCOORD_0;
        
        return output;
      }
      
      // 片元着色器:计算每个像素的最终颜色
      void frag(Varyings varying) {
        // 从纹理中采样颜色
        vec4 texColor = texture2D(material_BaseTexture, varying.uv);
        
        // 与材质基础颜色相乘
        vec4 finalColor = texColor * material_BaseColor;
        
        // 输出最终颜色
        gl_FragColor = finalColor;
      }
    }
  }
}这个着色器会:
前往 游乐场