着色器:ShaderLab 和固定功能着色器

此教程将介绍如何创建自己的着色器,使您的游戏看起来更棒!

Unity 配置了一种强大的着色和材质语言,名为 ShaderLab。其语言风格类似于 CgFX 和 Direct3D Effects (.FX) 语言 – 可描述显示材质 (Material) 所需的一切信息。

着色器的属性描述可在 Unity 材质检视器 (Material Inspector) 中查看,并且多个着色器实现 (子着色器 (SubShaders)) 旨在实现不同的图形硬件功能,每一种都描述了图形硬件渲染状态、固定功能管道设置或要使用的顶点/片段程序。顶点和片段程序都使用高级 Cg/HLSL 编程语言编写。

本教程介绍如何使用固定功能和编程管道编写着色器。我们根据以下前提条件制定此教程:假设读者了解 OpenGL 或 Direct3D 渲染状态、固定功能和编程管道基础知识,并对CgHLSLGLSL 编程语言有一定了解。可在 NVIDIAAMD 开发人员网站找到一些着色器教程和文档。

入门

要新建着色器,请在菜单栏中依次选择资源 (Assets)-> 创建 (Create)-> 着色器 (Shader),或复制并运行现有着色器。在工程视图 (Project View) 中双击新着色器,即可对其进行编辑。

我们先从最基础的着色器开始:

Shader "Tutorial/Basic" {
Properties {
_Color ("Main Color", Color) = (1,0.5,0.5,1)
    }
SubShader {
Pass {
Material {
Diffuse [_Color]
            }
Lighting On
        }
    }
} 

这个简单的着色器函数介绍了一个具备最基本结构的着色器。它定义了名为 "Main Color" 的颜色属性,并分配一个玫瑰色的默认值(红色=100% 绿色=50% 蓝色=50% alpha=100%)。然后通过调用 Pass 渲染该对象,将设置漫反射材质组件传递至属性 _Color,并打开逐顶点照明。要测试此着色器,请新建材质,在下拉菜单(教程 (Tutorial)-> 基本 (Basic))中选择着色器,并将材质 (Material) 分配到某个对象。调节材质检视器 (Material Inspector) 中的颜色并查看其变化。现在我们将讨论更复杂的内容!

基本顶点照明

如果打开现有的复杂着色器,可能难以看明白。首先,我们要仔细分析 Unity 随附的内置顶点光照 (VertexLit) 着色器。此着色器使用固定功能管道执行标准逐顶点照明。

Shader "VertexLit" {
Properties {
_Color ("Main Color", Color) = (1,1,1,0.5)
_SpecColor ("Spec Color", Color) = (1,1,1,1)
_Emission ("Emmisive Color", Color) = (0,0,0,0)
_Shininess ("Shininess", Range (0.01, 1)) = 0.7
_MainTex ("Base (RGB)", 2D) = "white" { }
    }

SubShader {
Pass {
Material {
Diffuse [_Color]
Ambient [_Color]
Shininess [_Shininess]
Specular [_SpecColor]
Emission [_Emission]
            }
Lighting On
SeparateSpecular On
SetTexture [_MainTex] {
constantColor [_Color]
Combine texture * primary DOUBLE, texture * constant
            }
        }
    }
} 

所有着色器都是以关键字 Shader 开头,其后紧跟着表示着色器名称的字符串。检视器 (Inspector) 中将显示此名称。此着色器的所有代码必须位于其名称后面的大括号中:{ }(称为块)。

着色器由属性 (Properties) 块和其后的子着色器 (SubShader) 块构成。下面将介绍这两个块。

属性

在着色器块的起始部分,可以定义设计师可在材质检视器 (Material Inspector) 中编辑的任何属性。以顶点光照 (VertexLit) 为例,其属性示例如下:

属性 (Properties) 块中用隔开的行列出属性。每个属性均以内部名称 (Color, MainTex) 开头。其后的括号列出检视器中显示的名称和属性类型。然后列出了此属性的默认值:

属性组件手册 (Properties Reference) 中列出了可用的类型。默认值取决于属性类型。以颜色为例,其默认值应为四个组件向量。

现已定义好属性,可以正式开始编写着色器了。

着色器结构

继续讲解本部分内容之前,首先要了解着色器文件的基本结构。

不同的图形硬件功能也不同。例如,有些图形卡支持片段程序,但有些图形卡不支持;有些可在一个通道上放置四个纹理,但其他图形卡在一个通道上只能放置两个甚至一个纹理;要充分利用用户拥有的任何硬件,着色器可包含多个子着色器 (SubShaders)。Unity 渲染着色器时,将仔细查看所有子着色器,然后使用硬件支持的一个子着色器。

Shader "Structure Example" {
Properties { /* ...shader properties... }
SubShader {
	// ...subshader that uses vertex/fragment programs...
    }
SubShader {
	// ...subshader that uses four textures per pass...
    }
SubShader {
	// ...subshader that uses two textures per pass...
    }
SubShader {
	// ...subshader that might look ugly but runs on anything :)
    }
} 

此系统允许 Unity 支持所有现有硬件并最大程度地提升其质量。但这也导致有些着色器非常冗长。

在每个子着色器 (SubShader) 块中,可设置所有通道共用的渲染状态;然后自定义渲染通道。有关可用命令的完整清单,请参阅 子着色器组件手册 (SubShader Reference)

通道

每个子着色器是一个通道集合。每个通道的对象几何图像需要渲染,因此必须至少有一个通道。顶点光照 (VertexLit) 着色器只有一个通道:

// ...snip...
Pass {
Material {
Diffuse [_Color]
Ambient [_Color]
Shininess [_Shininess]
Specular [_SpecColor]
Emission [_Emission]
    }
Lighting On
SeparateSpecular On
SetTexture [_MainTex] {
constantColor [_Color]
Combine texture * primary DOUBLE, texture * constant
    }
}
// ...snip... 

在通道中定义的任何命令将图形硬件配置为以特定方式渲染几何图形。

上一示例中,我们使用 Material 块将属性值绑定至固定功能照明材质设置。命令 Lighting On可打开标准顶点照明,SeparateSpecular On 可将单独的颜色用于高亮点。

目前,所有这些命令可直接映射至固定功能 OpenGL/Direct3D 硬件模型。有关更多信息,请参阅 OpenGL 红皮书

下一命令 SetTexture 非常重要。这些命令定义我们需要使用的纹理以及如何在渲染中混合、组合和应用这些纹理。SetTexture 命令后面紧接着我们希望使用的纹理属性名称(此处为 _MainTex),然后是定义如何应用纹理的合成块。合成块中的命令会针对屏幕上渲染的每个像素来执行。

在此块中,我们设置一个颜色常量值,将其称为材质 (Material) 的颜色 (Color) _Color。接下来,我们将使用此颜色常量。

在下一命令中,我们指定如何将纹理与颜色值混合。我们通过 Combine 命令执行此任务,此命令可指定此纹理与其他纹理或颜色混合的方式。常见示例如下: Combine ColorPart, AlphaPart

此处的 ColorPartAlphaPart 分别定义混合颜色 (RGB) 和 alpha (A) 组件的信息。如果忽略 AlphaPart,则其将按上述方法混合 ColorPart

在顶点光照 (VertexLit) 示例中: Combine texture * primary DOUBLE, texture * constant

此处的 texture 是当前纹理的颜色(此处为 _MainTex)。它将与主要顶点颜色相乘(*)。主要颜色是顶点照明颜色,根据上述材质 (Material) 值计算得出。最后,将所得的结果乘以二增加照明亮度 (DOUBLE)。Alpha 值(逗号后面)即纹理常量值(使用上述颜色常量设置)的乘积。另一种常用的合成模式为 previous(本着色器中未使用)。这是由任何先前的 SetTexture 步骤得出的结果,可用于将多个纹理和/或颜色混合起来。

总结

顶点光照 (VertexLit) 着色器配置标准顶点照明并设置纹理合成器,从而将已渲染照明亮度提高一倍。

我们可在着色器中添加并逐个渲染更多通道。现已获得满意的效果,无需执行上述操作。由于无需使用任何高级功能,我们只需使用一个子着色器 (SubShader) – 这个特别的着色器可在 Unity 支持的任何图形卡上运行。

我们认为,顶点光照着色器是最基本的着色器之一。我们没有使用任何硬件的特定操作,也没有使用 ShaderLab 和 Cg 必须具备的任何更特别、更强大的命令。

下一章节,我们将介绍如何使用 Cg 语言编写顶点和片段程序。

Page last updated: 2013-06-26