Writing shaders that interact with lighting is complex. There are different light types, different shadow options, different rendering paths (forward and deferred rendering),
编写与光线交互的着色器是很复杂的。有不同的灯光类型,不同的阴影选项,不同的渲染路径(前向渲染和延迟渲染),
and the shader should somehow handle all that complexity.
着色器应该以某种方式处理所有的复杂性。
Surface Shaders in Unity is a code generation approach that makes it much easier to write lit shaders than using low level vertex/pixel shader programs.
Unity中的表面着色器是一种代码生成方法,它使得编写光照着色器比使用低级顶点/像素着色器程序更容易。
Note that there are no custom languages, magic or ninjas involved in Surface Shaders;
注意,在表面着色器中不涉及自定义语言,魔术或忍者(暂时不懂是啥意思);
it just generates all the repetitive code that would have to be written by hand. You still write shader code in HLSL.
它只生成所有必须手工编写的重复代码。你仍然用HLSL写着色代码。
For some examples, take a look at Surface Shader Examples and Surface Shader Custom Lighting Examples.
对于一些例子,看看表面着色器例子和表面着色器自定义照明例子。
How it works:它是如何工作的
You define a “surface function” that takes any UVs or data you need as input, and fills in output structure SurfaceOutput
.
您可以定义一个“表面函数”,它接受您需要的任何uv或数据作为输入,并填充输出结构SurfaceOutput。
SurfaceOutput basically describes properties of the surface (it’s albedo color, normal, emission, specularity etc.). You write this code in HLSL.
SurfaceOutput基本上描述了表面的属性(它的反照率颜色,法线,发射,反射等)。你用HLSL写这段代码。
Surface Shader compiler then figures out what inputs are needed, what outputs are filled and so on, and generates actual vertex&pixel shaders, as well as rendering passes to handle forward and deferred rendering.
然后,Surface Shader编译器会找出需要什么输入,填充什么输出等等,并生成实际的vertex&pixel shaders,以及处理前进和延迟的渲染。
Standard output structure of surface shaders is this:
表面着色器的标准输出结构是:
struct SurfaceOutput { fixed3 Albedo;反光率 // diffuse color:漫反射颜色 fixed3 Normal; 法线// tangent space normal, if written:切线空间法向量,如果写了的话 fixed3 Emission;自发光 half Specular;镜面(高光)反射 // specular power in 0..1 range:高光功率,在0到1范围内 fixed Gloss;光泽,值越高光泽度越高,1为极值,物极必反 // specular intensity:高光强度 fixed Alpha;透明度 // alpha for transparencies:透明度 }; |
In Unity 5, surface shaders can also use physically based lighting models.
在Unity 5中,表面着色器也可以使用基于物理的光照模型。
Built-in Standard and StandardSpecular lighting models (see below) use these output structures respectively:
内置标准和标准镜面照明模型(见下文)分别使用这些输出结构:
struct SurfaceOutputStandard { fixed3 Albedo; // base (diffuse or specular) color 基础颜色(漫反射或者高光) fixed3 Normal; // tangent space normal, if written 切线空间法线,如果写了的话 half3 Emission; 自发光 half Metallic; // 0=non-metal, 1=metal 0=无金属 1=有金属 half Smoothness; // 0=rough, 1=smooth 0=粗糙,1=光滑 half Occlusion; // occlusion (default 1) 贴图吸收(默认为1) fixed Alpha; // alpha for transparencies 透明度 }; struct SurfaceOutputStandardSpecular { fixed3 Albedo; // diffuse color fixed3 Specular; // specular color fixed3 Normal; // tangent space normal, if written half3 Emission; half Smoothness; // 0=rough, 1=smooth half Occlusion; // occlusion (default 1) fixed Alpha; // alpha for transparencies }; |
Samples:示例
See Surface Shader Examples, Surface Shader Custom Lighting Examples and Surface Shader Tessellation pages.
见表面着色器例子,表面着色器自定义照明例子和表面着色器镶嵌页。
Surface Shader compile directives:表面着色器编译指令
Surface shader is placed inside CGPROGRAM..ENDCG
block, just like any other shader. The differences are:
表面着色器被放置在CGPROGRAM..ENDCG块,就像任何其他着色器。差异是:
- It must be placed inside SubShader block, not inside Pass. Surface shader will compile into multiple passes itself.
它必须放在SubShader block里面,而不是Pass里面。表面着色器将编译成多个通道本身。 - It uses
#pragma surface ...
directive to indicate it’s a surface shader.
它使用#pragma surface…指令,来表明它是一个表面着色器。
The #pragma surface
directive is:#pragma表面着色器指令是:
#pragma surface surfaceFunction lightModel [optionalparams] |
Required parameters:必需的参数
surfaceFunction
- 表面着色器方法
which Cg function has surface shader code. Cg函数有表面着色代码。
The function should have the form ofvoid surf (Input IN, inout SurfaceOutput o)
, where Input is a structure you have defined.
函数的形式应该是void surf (Input IN, inout SurfaceOutput o),其中输入是您定义的结构。
Input should contain any texture coordinates and extra automatic variables needed by surface function.
输入应该包含任何纹理坐标和表面函数所需的额外自动变量。lightModel
- 光照模型
lighting model to use. 给光照模型使用
Built-in ones are physically basedStandard
andStandardSpecular
,
内置的光照模型是基于物理的Standard
和SurfaceOutputStandard
输出结构,
as well as simple non-physically basedLambert
(diffuse) andBlinnPhong
(specular).
以及简单的非物理基础Lambert(漫反射)和BlinnPhong(高光)。
See Custom Lighting Models page for how to write your own.
请参阅自定义照明模型页面,了解如何编写自己的模型。Standard
lighting model usesSurfaceOutputStandard
output struct, and matches the Standard (metallic workflow) shader in Unity.
标准光照模型使用SurfaceOutputStandard输出结构,并在Unity中匹配标准(金属工作流)着色器。StandardSpecular
lighting model usesSurfaceOutputStandardSpecular
output struct, and matches the Standard (specular setup) shader in Unity.
标准镜面光照模型使用SurfaceOutputStandardSpecular输出结构,并在Unity中匹配标准(镜面设置)着色器。Lambert
andBlinnPhong
lighting models are not physically based (coming from Unity 4.x), but the shaders using them can be faster to render on low-end hardware.
Lambert和BlinnPhong灯光模型不是基于物理的(来自Unity 4.x),但是使用它们的着色器可以更快地在低端硬件上渲染。
Optional parameters:可选参数
Transparency and alpha testing is controlled by alpha
and alphatest
directives.
透明和alpha测试由alpha和alphatest指令控制。
Transparency can typically be of two kinds: traditional alpha blending (used for fading objects out) or more physically plausible “premultiplied blending” (which allows semitransparent surfaces to retain proper specular reflections).
透明度通常有两种:传统的alpha混合(用于淡出物体)或更物理上合理的“预乘混合”(允许半透明表面保留适当的镜面反射)。
Enabling semitransparency makes the generated surface shader code contain blending commands;
启用半透明使生成的表面着色器代码包含混合命令;
whereas enabling alpha cutout will do a fragment discard in the generated pixel shader, based on the given variable.
而启用alpha cutout则会在生成的像素中删除一个片段着色器,基于给定的变量。
alpha
oralpha:auto
-
Will pick fade-transparency (same asalpha:fade
) for simple lighting functions,
对于简单的灯光函数,会选择渐淡透明(和alpha:fade一样),
and premultiplied transparency (same asalpha:premul
) for physically based lighting functions.
而对于物理效果,会选择预乘透明(和alpha:premul一样)alpha:blend
-
Enable alpha blending.
开启alpha blendingalpha:fade
-
Enable traditional fade-transparency.
开启传统的渐淡透明traditional fade-transparency.alpha:premul
-
Enable premultiplied alpha transparency.
开启预乘透明premultiplied alpha transparencyalphatest:VariableName
-
Enable alpha cutout transparency.
开启alpha cutout transparency
Cutoff value is in a float variable with VariableName.
截止值在一个名为VariableName的浮点变量中。
You’ll likely also want to useaddshadow
directive to generate proper shadow caster pass.
你也可能想要使用addshadow指令来生成正确的阴影渲染通道。keepalpha
-
By default opaque surface shaders write 1.0 (white) into alpha channel, no matter what’s output in the Alpha of output struct or what’s returned by the lighting function.
默认情况下,不管输出结构的alpha中有什么输出,或者灯光函数返回了什么,不透明的表面着色器将1.0(白色)写入alpha通道。
Using this option allows keeping lighting function’s alpha value even for opaque surface shaders.
使用这个选项允许保持照明功能的alpha值,即使对于不透明的表面着色。decal:add
-
Additive decal shader (e.g. terrain AddPass).
添加贴花着色器(如地形添加通道)。
This is meant for objects that lie atop of other surfaces, and use additive blending. See Surface Shader Examples。
这是指位于其他表面之上的对象,并使用添加混合。见表面着色的例子decal:blend
-
Semitransparent decal shader. 半透明的贴花纸材质。
This is meant for objects that lie atop of other surfaces, and use alpha blending. See Surface Shader Examples。
这是用于位于其他表面之上的对象,并使用alpha混合。见表面着色器的例子
Custom modifier functions can be used to alter or compute incoming vertex data, or to alter final computed fragment color.
自定义修饰符函数可用于更改或计算传入顶点数据,或更改最终计算片段颜色。
vertex:VertexFunction
-
Custom vertex modification function.自定义顶点修改功能。
This function is invoked at start of generated vertex shader, and can modify or compute per-vertex data.
这个函数是在生成顶点着色器开始时调用的,可以修改或计算每个顶点的数据。
See Surface Shader Examples.见表面着色器的例子
finalcolor:ColorFunction
-
Custom final color modification function.自定义最终颜色修改功能。
See Surface Shader Examples.见表面着色器的例子finalgbuffer:ColorFunction
-
Custom deferred path for altering gbuffer content.修改gbuffer内容的自定义延迟路径。finalprepass:ColorFunction
-
Custom prepass base path.
自定义prepass 基本路径
addshadow
-
Generate a shadow caster pass. 生成一个阴影渲染通道。
Commonly used with custom vertex modification, so that shadow casting also gets any procedural vertex animation.
通常与自定义顶点修改一起使用,这样阴影投射也可以获得任何过程顶点动画。
Often shaders don’t need any special shadows handling, as they can just use shadow caster pass from their fallback.
通常着色器不需要任何特殊的阴影处理,因为他们可以从fallback中使用阴影渲染通道。
fullforwardshadows
-
Support all light shadow types in Forward rendering path.
在Forward渲染通道中支持所有的光影类型。
By default shaders only support shadows from one directional light in forward rendering(to save on internal shader variant count).
默认情况下,在正向渲染中,着色器只支持来自一个方向光的阴影(用于保存内部着色器变量计数)。
If you need point or spot light shadows in forward rendering, use this directive。
如果你在正向渲染中需要点或聚光灯光源阴影,使用这个指令。
tessellate:TessFunction
-
use DX11 GPU tessellation; 使用DX11 GPU镶嵌
the function computes tessellation factors. 这个函数计算镶嵌因子。
See Surface Shader Tessellation for details.
Code generation options - 代码生成选项
by default generated surface shader code tries to handle all possible lighting/shadowing/lightmap scenarios.
默认情况下,生成的表面着色器代码试图处理所有可能的光照/阴影/光照贴图场景。
However in some cases you know you won’t need some of them, and it is possible to adjust generated code to skip them.
然而,在某些情况下,您知道您不需要其中的一些,并且可以调整生成的代码以跳过它们。
This can result in smaller shaders that are faster to load.
这会使着色器更小,加载速度更快。
exclude_path:deferred
,exclude_path:forward
,exclude_path:prepass
-
Do not generate passes for given rendering path (Deferred Shading, Forward and Legacy Deferred respectively).
不生成给定渲染路径的通道。noshadow
-
Disables all shadow receiving support in this shader.
在这个着色器中禁用所有接受支持的阴影。noambient
-
Do not apply any ambient lighting or light probes
不应用任何环境照明或光探头novertexlights
-
Do not apply any light probes or per-vertex lights in Forward rendering.
不要在正向渲染中应用任何光探针或每个顶点的光。nolightmap
-
Disables all lightmapping support in this shader.
禁用此着色器中的所有光映射支持。nodynlightmap
-
Disables runtime dynamic global illumination support in this shader.
在这个着色器中禁用运行时动态全局光照支持。nodirlightmap
-
Disables directional lightmaps support in this shader.
在这个着色器中禁用定向方向光映射。nofog
-
Disables all built-in Fog support.
禁用所有内置雾支持。nometa
-
Does not generate a “meta” pass (that’s used by lightmapping & dynamic global illumination to extract surface information).
不生成“meta”通道(被光映射和动态全局光照用于提取表面信息)。noforwardadd
-
Disables Forward rendering additive pass. 禁用正向渲染添加通道。
This makes the shader support one full directional light, with all other lights computed per-vertex/SH. Makes shaders smaller as well.
这使得着色器支持一个完整的方向光和所有光照的per-vertex/SH计算。使着色器也更小。nolppv
-
Disables Light Probe Proxy Volume support in this shader.
在这个着色器中禁用光照探测代理。noshadowmask
-
Disables Shadowmask support for this shader (both Shadowmask and Distance Shadowmask).
禁用这个着色器的暗影面具(包括暗影面具和距离暗影面具)。
Miscellaneous options
softvegetation
- 软植被
Makes the surface shader only be rendered when Soft Vegetation is on.
使表面着色器只有当Soft Vegetation开启时才渲染。interpolateview
- 插值视图
Compute view direction in the vertex shader and interpolate it; instead of computing it in the pixel shader.
在顶点着色器中计算视图方向并插值;而不是在像素着色器中计算它。
This can make the pixel shader faster, but uses up one more texture interpolator.
这可以使像素着色器更快,但使用更多的纹理插值器。halfasview
-
Pass half-direction vector into the lighting function instead of view-direction.
将半方向向量传递到光照函数,而不是视图方向。
Half-direction will be computed and normalized per vertex. This is faster, but not entirely correct.
半方向向量将被逐顶点计算并单位化。这更快,但并不完全正确。approxview
-
Removed in Unity 5.0. Useinterpolateview
instead.
在Unity 5.0中删除。使用interpolateview代替。dualforward
-
Use dual lightmaps in forward rendering path.
在前向渲染路径中使用双光映射。dithercrossfade
-
Makes the surface shader support dithering effects.
使表面着色器支持抖动效果。
You can then apply this shader to GameObjects that use an LOD Group component configured for cross-fade transition mode.
然后,您可以将这个着色器应用到使用LOD组组件配置为交叉淡出转换模式的游戏对象上。
To see what exactly is different from using different options above, it can be helpful to use “Show Generated Code” button in the Shader Inspector.
要查看与上面使用不同选项的区别,在着色器检查器中使用“显示生成的代码”按钮是有帮助的。
Surface Shader input structure:表面着色器输入结构
The input structure Input
generally has any texture coordinates needed by the shader.
输入结构体Input通常有着色器需要的任何纹理坐标。
Texture coordinates must be named “uv
” followed by texture name (or start it with “uv2
” to use second texture coordinate set).
纹理坐标必须命名为“uv”,后跟纹理名称(或者以“uv2”开始使用第二个纹理坐标集)。
Additional values that can be put into Input structure:
float3 viewDir
-
contains view direction, for computing Parallax effects, rim lighting etc.
包含视图方向,用于计算视差效果,边缘照明等
float4
withCOLOR
semantic - 带COLOR的语义
contains interpolated per-vertex color.包含每个顶点的插值颜色。float4 screenPos
-
contains screen space position for reflection or screenspace effects.
包含屏幕空间位置的反射或屏幕空间效果。
Note that this is not suitable for GrabPass; you need to compute custom UV yourself usingComputeGrabScreenPos
function.
注意,这并不适合GrabPass;您需要使用ComputeGrabScreenPos函数自己计算自定义UV。float3 worldPos
-
contains world space position.包含世界空间位置。float3 worldRefl
-
contains world reflection vector if surface shader does not write to o.Normal.
如果表面着色器不写o.Normal,包含世界反射向量
See Reflect-Diffuse shader for example.
详情参见Reflect-Diffuse shaderfloat3 worldNormal
-
contains world normal vector if surface shader does not write to o.Normal.
如果表面着色器不写o.Normal,包含世界法线向量float3 worldRefl; INTERNAL_DATA
-
contains world reflection vector if surface shader writes to o.Normal.
如果表面着色器不写o.Normal,包含世界反射向量
To get the reflection vector based on per-pixel normal map, useWorldReflectionVector (IN, o.Normal)
.
得到基于逐像素法线映射的反射向量,使用WorldReflectionVector (IN, o.Normal)
.
See Reflect-Bumped shader for example.
详情参见Reflect-Bumped shaderfloat3 worldNormal; INTERNAL_DATA
-
contains world normal vector if surface shader writes to o.Normal.
如果表面着色器不写o.Normal,包含世界法线向量
To get the normal vector based on per-pixel normal map, useWorldNormalVector (IN, o.Normal)
.
得到基于逐像素法线映射的法线向量,使用 WorldNormalVector(IN, o.Normal)
.
Surface Shaders and DirectX 11 HLSL syntax:表面着色器和directx11 HLSL语法
Currently some parts of surface shader compilation pipeline do not understand DirectX 11-specific HLSL syntax,
目前,部分表面着色器编译管道不支持DirectX 11-specific HLSL语法,
so if you’re using HLSL features like StructuredBuffers, RWTextures and other non-DX9 syntax, you have to wrap it into a DX11-only preprocessor macro.
所以如果您使用的是诸如StructuredBuffers、RWTextures 和其他非dx9语法的HLSL特性,那么您必须将它封装到一个DX11-only预处理器宏中。