Unity3D 编写顶点和片元着色器( ShaderLab )

ShaderLab 着色器不仅仅包括“硬件着色器”。这些着色器做很多事情。它们描述在材质检视器 (Material Inspector) 中显示的属性,容纳用于不同图形硬件的多种着色器实现,配置固定函数硬件状态等等。实际可编程着色器 - 如顶点和片元程序 - 只是整个 ShaderLab“着色器”概念的一部分。请查看着色器教程中的基本简介。在这里,我们将调用低级硬件着色器着色器程序

如果您想编写与光照交互的着色器,请查看表面着色器文档。本页剩余部分将假设着色器不与 Unity 光照交互(例如:特殊效果、Image Effects|图像效果等。)

着色器程序的编写采用 Cg/HLSL 语言,是通过在着色器文本中 Pass 命令内的某处嵌入“代码片段”的来实现的。它们通常看起来像这样:

  Pass {
      // ...常用的通道状态设置...

      CGPROGRAM
      // 该代码片段的编译指令,例如:
      #pragma vertex vert
      #pragma fragment frag

      // Cg 代码自身

      ENDCG
      // ...通道设置的剩余部分...
  }

Cg 代码片段

Cg 程序代码片段被编写在 CGPROGRAMENDCG 之间。

在代码片段编译指令的开头,可以使用 #pragma 指令。指示编译哪些着色器函数的编译指令:

  • #pragma vertex 名称 - 将函数名称编译为顶点着色器。
  • #pragma fragment 名称 - 将函数名称编译为片元着色器。
  • #pragma geometry 名称 - 将函数名称编译为 DX10 几何结构着色器。要使这个选项自动打开#pragma target 4.0,请参阅下文。
  • #pragma hull 名称 - 将函数名称编译为 DX11 外壳着色器。要使这个选项自动打开#pragma target 5.0,请参阅下文。
  • #pragma domain 名称 - 将函数名称编译为 DX11 域着色器。要使这个选项自动打开#pragma target 5.0,请参阅下文。

其他编译指令:

  • #pragma target 名称 - 要编译成哪个着色器目标。有关详细信息,请参阅着色器目标。
  • #pragma only_renderers 空格隔开的名称 - 仅为给定渲染器编译着色器。默认情况下,为所有渲染器编译着色器。有关详细信息,请参阅渲染器。
  • #pragma exclude_renderers 空格隔开的名称 - 不仅为给定渲染器编译着色器。默认情况下,为所有渲染器编译着色器。有关详细信息,请参阅渲染器。
  • #pragma glsl - 为桌面 OpenGL 平台编译着色器时,将 Cg/HLSL 转换成 GLSL (而不是默认设置,即 ARB 顶点/片元程序)。使用此指令可启用导数指令 (derivative instruction)、具有明确 LOD 等级的纹理采样等。
  • #pragma glsl_no_auto_normalization - 为移动 GLSL (iOS/Android) 编译着色器时,关闭法线和切线向量的自动规范化性能。默认情况下,法线和切线是在 iOS/Android 平台上的顶点着色器中被规范化的。
  • #pragma fragmentoption 选项 - 添加选项到已编译的 OpenGL 片元程序。有关允许使用的选项的列表,请参阅ARB 片元程序详述。该指令对顶点程序或被编译成非 OpenGL 目标的程序无影响。

每个代码片段都必须包含一个顶点程序或一个片元程序或两者皆包含。因此,要求使用一个 #pragma vertex 指令或一个#pragma fragment 指令或两者都使用。

着色器目标

默认情况下,Unity 将着色器编译为简约 Shader Model 2.0 的相等物。使用 #pragma target 可使着色器被编译成其他能力等级。当前支持以下目标:

  • #pragma target 2.0 (默认) - 简约 Shader Model 2.0
    • Direct3D 9 上的 Shader Model 2.0。
    • 具有 256 位指令限制的ARB_vertex_program、具有 96 位指令限制(32 位纹理 + 64 位算法)的ARB_fragment_program、16 个临时寄存器 (temporary register) 和 4 个纹理间接 (texture indirection)。
  • #pragma target 3.0 - 编译成 Shader Model 3.0:
    • Direct3D 9 上的 Shader Model 3.0。
    • 无指令限制的 ARB_vertex_program、具有 1024 位指令限制(512 位纹理 + 512 位算法)的 ARB_fragment_program、32 个临时寄存器 (temporary register) 和 4 个纹理间接 (texture indirection)。可使用#pragma profileoption 指令覆盖这些限制。例如:#pragma profileoption MaxTexIndirections=256 将纹理间接限制增加到 256 个。请注意,一些 Shader Model 3.0 功能(如导数指令)是不受 ARB_vertex_program/ARB_fragment_program 支持的。您可以使用#pragma glsl 转换成限制较少的 GLSL 来代替。
    当编译成 3.0 或更大目标时,顶点和片元程序都需要被展示。
  • #pragma target 4.0 - 编译成 DX10 Shader Model 4.0。当前只有 DirectX 11 渲染器支持该目标。
  • #pragma target 5.0 - 编译成 DX11 Shader Model 5.0。当前只有 DirectX 11 渲染器支持该目标。

渲染平台

Unity 支持几个渲染 API(例如,Direct3D 9 和 OpenGL),默认情况下,所有着色器程序都编译成受支持的渲染器。使用 #pragma only_renderers #pragma exclude_renderers 指令,您可以指示编译成哪些渲染器。如果您知道您将只把 Mac OS X (无 Direct3D)或 Windows(Unity 默认为 D3D)作为目标,或者如果某个特定着色器只在一个渲染器中可用,而在其他渲染器中不可用,这样是有用的。当前受支持的渲染器名称有:

  • d3d9 - Direct3D 9.
  • d3d11 - Direct3D 11.
  • opengl - OpenGL.
  • gles - OpenGL ES 2.0.
  • xbox360 - Xbox 360.
  • ps3 - PlayStation 3.
  • flash - Flash.

例如,以下这行指令只会将着色器编译为 D3D9 模式:

  #pragma only_renderers d3d9

在着色器程序中,您通常需要访问一些全局状态,例如当前模型*视图*投影矩阵 (model*view*projection matrix)、当前环境颜色等等。无需声明这些内置状态变量,您可以直接在着色器程序中使用它们。

内置矩阵

受支持的矩阵 (float4x4):

UNITY_MATRIX_MVP
当前模型*视图*投影矩阵 (model*view*projection matrix)
UNITY_MATRIX_MV
当前模型*视图矩阵 (model*view matrix)
UNITY_MATRIX_V
当前视图矩阵 (view matrix)。
UNITY_MATRIX_P
当前投影矩阵 (projection matrix)
UNITY_MATRIX_VP
当前视图*投影矩阵 (view*projection matrix)
UNITY_MATRIX_T_MV
模型*视图矩阵 (model*view matrix) 的转置
UNITY_MATRIX_IT_MV
模型*视图矩阵 (model*view matrix) 的逆转置
UNITY_MATRIX_TEXTURE0 to UNITY_MATRIX_TEXTURE3
纹理变换矩阵

内置向量

受支持的向量 (float4):

UNITY_LIGHTMODEL_AMBIENT
当前环境色。
 

ShaderLab 语法:Properties

着色器可以定义一系列的参数,这些参数将由 Unity 材质检视器中的设计师设定。在着色器文件中的属性 (Properties) 块定义参数。

语法

属性 (Properties) { Property [ Property ...] }
定义属性块。括号内,多个属性定义如下。
name (" display name", Range ( min, max)) = number
定义浮点属性,代表检视器中从 最小值 (min)最大值 (max)的滑块。
name (" display name", Color) = ( number, number, number, number)
定义颜色属性。
name (" display name", 2D) = " name" { options }
定义二维纹理属性。
name (" display name", Rect) = " name" { options }
定义矩形(非 2 的幂)纹理属性。
name (" display name", Cube) = " name" { options }
定义立方体贴图纹理属性。
name (" display name", Float) = number
定义浮点属性。
name (" display name", Vector) = ( number, number, number, number)
定义四分量向量属性。

详细信息

着色器内部的每个属性都被名称 (name) 引用(Unity 中,着色器属性名称以下划线开头是很常见的)。在材质检视器中属性会显示为显示名称 (display name)。对每个属性来说,默认值放在等号之后:

  • 对于范围 (Range)浮点 (Float) 属性,默认值只是一个数字。
  • 对于颜色 (Color)向量 (Vector) 属性来说,默认值为圆括号中的四个数字。
  • 对纹理(二维 (2D)矩形 (Rect)立方体 (Cube))来说,默认值可以是一个空字符串或者是以下内置默认纹理中的一种:"白色”、“黑色”、“灰色”或“凹凸贴图”。

随后在着色器中,通过使用方括号内的属性名称访问属性值:[name].

示例

Properties {
    // 水着色器的属性
    _WaveScale ("Wave scale", Range (0.02,0.15)) = 0.07 // 滑块
    _ReflDistort ("Reflection distort", Range (0,1.5)) = 0.5
    _RefrDistort ("Refraction distort", Range (0,1.5)) = 0.4
    _RefrColor ("Refraction color", Color)  = (.34, .85, .92, 1) // 颜色
    _ReflectionTex ("Environment Reflection", 2D) = "" {} // 纹理
    _RefractionTex ("Environment Refraction", 2D) = "" {}
    _Fresnel ("Fresnel (A) ", 2D) = "" {}
    _BumpMap ("Bumpmap (RGB) ", 2D) = "" {}
} 

纹理属性选项

在纹理属性的花括号内的选项 (options) 为可选项。可用选项有:

  • TexGen texgenmode: 该纹理的自动纹理协调生成模式。可以是 ObjectLinearEyeLinearSphereMapCubeReflectCubeNormal 中的一种;这些直接对应 OpenGL texgen 模式。请注意:如果使用自定义顶点程序,则 TexGen 模式将被忽略。
  • LightmapMode 如果启用此模式,该纹理会受到每个渲染器光照贴图参数的影响。也就是说,将使用的纹理可以不在材质中,而是来自渲染器设置,请参见渲染器脚本文档。

示例

// EyeLinear texgen 模式示例
Shader "Texgen/Eye Linear" {
    Properties {
        _MainTex ("Base", 2D) = "white" { TexGen EyeLinear }
    }
    SubShader {
        Pass {
            SetTexture [_MainTex] { combine texture }
        }
    }
} 

ShaderLab 语法:子着色器 (SubShader)

Unity 中的每个着色器都是由一系列的子着色器构成的。当 Unity 必须显示网格时,会找到要使用的着色器,并选择在用户显卡上运行的第一个子着色器。

语法

Subshader { [ Tags] [ CommonState] Passdef [ Passdef ...] }
定义子着色器为可选的标记、普通状态和一系列通道定义。

详细信息

子着色器定义一系列的渲染通道并视情况对所有通道设置成普通状态。此外,可以设置子着色器特定的标记。

当 Unity 选择使用哪个子着色器进行渲染时,它对每个定义的通道渲染对象一次(因为光交互也可能渲染多次)。由于每次渲染对象都是一次昂贵的操作,所以要使用尽可能最少的通道定义着色器。当然,有时在一些图形硬件上,使用一个通道不能达到需要的效果;那么您别无选择,只能使用多通道。

每个通道定义可以是一个常规通道、一个使用通道或一个捕获通道。

通道定义中允许的任何声明也可以出现在子着色器块中。这将使所有通道使用这种“共享”状态。

Example

// ...
SubShader {
    Pass {
        Lighting Off
        SetTexture [_MainTex] {}
    }
}
// ...

该子着色器定义了一个单通道,其关闭了所有光照并只显示纹理名称为 _MainTex 的网格。

ShaderLab 语法:Pass

通道 (Pass) 块使对象的几何结构被渲染一次。

语法

Pass { [Name and Tags] [RenderSetup] [TextureSetup] }
基本通道命令包含了渲染设置命令的可选列表,后面可跟随一系列纹理以供使用。

名称和标记

通道 (Pass) 可以定义其名称和任意数量的标记 - 名称/值字符串告知渲染引擎“通道”(Pass) 的目的。

渲染设置

通道可设置图形硬件的各种状态,例如,是否应打开 alpha 混合,是否使用雾化等。其命令如下:

Material { Material Block }
定义在顶点光照管线中使用的材质。有关详细信息,请参阅 材质页面
Lighting On | Off
开启或关闭顶点光照。有关详细信息,请参阅 材质页面
Cull Back | Front | Off
设置多边形剔除模式。
ZTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always)
设置深度测试模式。
ZWrite On | Off
设置深度编写模式。
Fog { Fog Block }
设置雾化参数。
AlphaTest (Less | Greater | LEqual | GEqual | Equal | NotEqual | Always) CutoffValue
开启 alpha 测试。
Blend SourceBlendMode DestBlendMode
设置 alpha 混合模式。
Color Color value
如果顶点光照是关闭的,则设置使用的颜色。
ColorMask RGB | A | 0 | any combination of R, G, B, A
设置颜色编写遮蔽图。编写 ColorMask 0 可关闭所有颜色通道的渲染。
Offset OffsetFactor , OffsetUnits
设置深度偏移。请注意,从 Unity 3.0 版本起,该命令只接受常量(即:非着色器参数)。
SeparateSpecular On | Off
打开或关闭顶点光照单独的高光颜色。有关详细信息,请参阅 材质页面
ColorMaterial AmbientAndDiffuse | Emission
计算顶点光照时使用逐顶点颜色。有关详细信息,请参阅 材质页面

纹理设置

渲染状态设置后,您可以应用 SetTexture 命令指定要应用的多种纹理及其组合模式:

SetTexture texture property { [Combine options] }

纹理设置可配置固定功能多层材质管线,并且如果使用自定义片段着色器,则纹理设置将被忽视。

详细信息

逐像素光照

逐像素光照管线通过在多通道中渲染对象作用。Unity 渲染对象一次以获得环境光照和所有顶点光照。然后渲染每个影响独立附加通道内的对象的像素光照。有关详细信息,请参阅渲染器管线。

逐顶点光照

逐顶点光照是对每个顶点都进行了计算的标准的 Direct3D/OpenGL 光照模式。Lighting on 可打开光照。光照受Material 块、ColorMaterialSeparateSpecular 令影响。有关详细信息,请参阅材质页面。


ShaderLab 内置值

Unity 为着色器提供 少量内置值:当前对象变换矩阵、时间等类似值。

使用 ShaderLab 中的内置值就像使用其他任何属性一样,唯一的区别在于您不必在某处进行声明 - 它们都是“内置的”。

在可编程着色器中使用它们需要包含UnityCG.cginc文档。

变换

float4x4 UNITY_MATRIX_MVP
当前模型*视图*投影矩阵 (model*view*projection matrix)
float4x4 UNITY_MATRIX_MV
当前模型*视图矩阵 (model*view matrix)
float4x4 UNITY_MATRIX_V
当前视图矩阵 (view matrix)。
float4x4 UNITY_MATRIX_P
当前投影矩阵 (projection matrix)
float4x4 UNITY_MATRIX_VP
当前视图*投影矩阵 (view*projection matrix)
float4x4 UNITY_MATRIX_T_MV
模型*视图矩阵 (model*view matrix) 的转置
float4x4 UNITY_MATRIX_IT_MV
模型*视图矩阵 (model*view matrix) 的逆转置
float4x4 UNITY_MATRIX_TEXTURE0 UNITY_MATRIX_TEXTURE3
纹理变换矩阵
float4x4 _Object2World
当前模型矩阵
float4x4 _World2Object
当前世界坐标矩阵的逆转置
float3 _WorldSpaceCameraPos
相机的世界坐标空间位置
float4 unity_Scale
xyz 组件未使用;.w 包含等比缩放对象的缩放。

光照

在普通的 ShaderLab 中,通过结尾追加零访问以下属性:例如光源的模型*光颜色是 _ModelLightColor0。在 Cg 着色器中,它们显示为单元素阵列,所以 Cg 中相同的是 _ModelLightColor[0]

名称 类型
_ModelLightColor float4 材质的主要*光色
_SpecularLightColor float4 材质的高光*光色
_ObjectSpaceLightPos float4 光源在对象空间中的位置。w 组件针对方向灯是 0,针对其他灯是 1
_Light2World float4x4 光到世界坐标 (World) 空间矩阵
_World2Light float4x4 世界坐标到光 (Light) 空间矩阵
_Object2Light float4x4 对象到光 (Light) 空间矩阵

种类

  • float4 _Time : 时间 (t/20, t, t*2, t*3),用于对着色器内的对象进行动画处理
  • float4 _SinTime : 时间正弦:(t/8, t/4, t/2, t)
  • float4 _CosTime : 时间余弦:(t/8, t/4, t/2, t)
  • float4 unity_DeltaTime : 差量时间:(dt, 1/dt, smoothDt, 1/smoothDt)
  • float4 _ProjectionParams :
    x 是 1.0 或 -1.0,如果当前用翻转投影矩阵渲染,则为负数
    y 是相机的近平面
    z 是相机的远平面
    w 是 1/FarPlane。
  • float4 _ScreenParams :
    x 是以像素为单位的当前渲染目标宽度
    y 是以像素为单位的当前渲染目标高度
    z 是 1.0 + 1.0/宽度
    w 是 1.0 + 1.0/高度


你可能感兴趣的:(unity3d,3D,shaderlab,着色)