本文档主要是对Unity官方手册的个人理解与总结(其实以翻译记录为主:>)
仅作为个人学习使用,不得作为商业用途,欢迎转载,并请注明出处。
文章中涉及到的操作都是基于Unity2018.2版本
参考链接:https://docs.unity3d.com/Manual/SL-PropertiesInPrograms.html
https://docs.unity3d.com/Manual/SL-VertexProgramInputs.html
Shader declares Material properties in a Properties block. If you want to access some of those properties in a shader program, you need to declare a Cg/HLSL variable with the same name and a matching type. An example is provided in Shader Tutorial: Vertex and Fragment Programs.
着色器在属性块中声明了材质属性。如果你想要访问着色程序中的一些属性,你需要声明一个Cg/HLSL变量,具有相同的名称和匹配的类型。在Shader教程中提供了一个例子:顶点和片段程序。
For example these shader properties:
_MyColor ("Some Color", Color) = (1,1,1,1)
_MyVector ("Some Vector", Vector) = (0,0,0,0)
_MyFloat ("My float", Float) = 0.5
_MyTexture ("Texture", 2D) = "white" {}
_MyCubemap ("Cubemap", CUBE) = "" {}
would be declared for access in Cg/HLSL code as:
将在Cg/HLSL代码中声明为:
fixed4 _MyColor; // low precision type is usually enough for colors
float4 _MyVector;
float _MyFloat;
sampler2D _MyTexture;
samplerCUBE _MyCubemap;
Cg/HLSL can also accept uniform keyword, but it is not necessary:
Cg/HLSL也可以接受uniform关键字,但不需要:
uniform float4 _MyColor;
Property types in ShaderLab map to Cg/HLSL variable types this way:
属性类型在ShaderLab映射到Cg/HLSL变量类型如下:
How property values are provided to shaders 属性值是如何提供给着色器的
Shader property values are found and provided to shaders from these places:
着色器属性值从如下找到并提供给着色器:
The order of precedence is like above: per-instance data overrides everything; then Material data is used; and finally if shader property does not exist in these two places then global property value is used. Finally, if there’s no shader property value defined anywhere, then “default” (zero for floats, black for colors, empty white texture for textures) value will be provided.
优先级顺序与上面类似:每个实例的数据覆盖所有内容;然后使用材质数据;最后,如果着色器属性不存在于这两个地方,则使用全局属性值。最后,如果在任何地方没有定义着色器属性值,那么将提供“默认”值(浮点值为0,颜色为黑色,纹理为纯白色)。
Serialized and Runtime Material properties 序列化和运行时材质属性
Materials can contain both serialized and runtime-set property values.
材质可以包含序列化的和运行时设置的属性值。
Serialized data is all the properties defined in shader’s Properties block. Typically these are values that need to be stored in the material, and are tweakable by the user in Material Inspector.
序列化数据是着色器属性块中定义的所有属性。通常,这些值需要存储在材质中,并由用户在材料检视器中进行调整。
A material can also have some properties that are used by the shader, but not declared in shader’s Properties block. Typically this is for properties that are set from script code at runtime, e.g. via Material.SetColor. Note that matrices and arrays can only exist as non-serialized runtime properties (since there’s no way to define them in Properties block).
材质也有一些被shader使用的属性,但未在shader属性块中声明过。通常这是用于在运行时从脚本代码中设置的属性,例如通过Material.SetColor。注意,矩阵和数组只能以非序列化的运行时属性的形式存在(因为无法在属性块中定义它们)。
Special Texture properties 特殊的贴图属性
For each texture that is setup as a shader/material property, Unity also sets up some extra information in additional vector properties.
对于每个着色器/材质属性的纹理,Unity还在额外的向量属性中设置了一些额外的信息。
Texture tiling & offset
Materials often have Tiling and Offset fields for their texture properties. This information is passed into shaders in a float4 {TextureName}_ST property:
材质的纹理属性通常有平铺和偏移字段。这个信息在 float4 {TextureName}_ST 属性中传递给着色器:
For example, if a shader contains texture named _MainTex, the tiling information will be in a _MainTex_ST vector.
例如,如果着色器包含一个名为_MainTex的纹理,那么平铺信息将定义为_MainTex_ST向量。
Texture size
{TextureName}_TexelSize - a float4 property contains texture size information:
{TextureName}_TexelSize - 一个float4属性包含纹理大小信息:
Texture HDR parameters
{TextureName}_HDR - a float4 property with information on how to decode a potentially HDR (e.g. RGBM-encoded) texture depending on the color space used. See DecodeHDR function in UnityCG.cginc shader include file.
{TextureName}_HDR -一个float4属性,根据使用的颜色空间,决定如何解码潜在的HDR(例如rgbm编码)纹理的信息。参见UnityCG中的DecodeHDR函数在UnityCG.cginc文件中。
Color spaces and color/vector shader data 颜色空间与颜色/向量 着色器数据
When using Linear color space, all material color properties are supplied as sRGB colors, but are converted into linear values when passed into shaders.
当使用线性颜色空间时,所有材质颜色属性都以sRGB颜色提供,但在传递到着色器时转换为线性值。
For example, if your Properties shader block contains a Color property called “MyColor“, then the corresponding ”MyColor” HLSL variable will get the linear color value.
例如,如果您的属性着色器块包含一个名为“MyColor”的颜色属性,那么相应的“MyColor”HLSL变量将获得线性空间的颜色值。
For properties that are marked as Float or Vector type, no color space conversions are done by default; it is assumed that they contain non-color data. It is possible to add [Gamma] attribute for float/vector properties to indicate that they are specified in sRGB space, just like colors (see Properties).
对于标记为浮点类型或向量类型的属性,默认情况下不进行颜色空间转换;因为被假设它们包含非颜色数据。可以为float/vector属性添加[Gamma]属性,以指示它们在sRGB空间中指定,就像颜色一样。
Providing vertex data to vertex programs 为顶点程序提供顶点数据
For Cg/HLSL vertex programs, the Mesh vertex data is passed as inputs to the vertex shader function. Each input needs to have semantic speficied for it: for example, POSITION input is the vertex position, and NORMAL is the vertex normal.
对于Cg/HLSL顶点程序,网格顶点数据作为顶点着色函数的输入被传递。每个输入都需要对其进行语义解析:例如,位置输入是顶点位置,而NORMAL是顶点法线。
Often, vertex data inputs are declared in a structure, instead of listing them one by one. Several commonly used vertex structures are defined in UnityCG.cginc include file, and in most cases it’s enough just to use those. The structures are:
通常,顶点数据输入是在结构中声明的,而不是逐个列出它们。UnityCG.cginc中定义了几种常用的顶点结构。cginc包含文件,在大多数情况下,只使用这些文件就足够了。结构体是:
Example: This shader colors the mesh based on its normals, and uses appdata_base as vertex program input:
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 = UnityObjectToClipPos(v.vertex);
o.color.xyz = v.normal * 0.5 + 0.5;
o.color.w = 1.0;
return o;
}
fixed4 frag (v2f i) : SV_Target { return i.color; }
ENDCG
}
}
}
To access different vertex data, you need to declare the vertex structure yourself, or add input parameters to the vertex shader. Vertex data is identified by Cg/HLSL semantics, and must be from the following list:
要访问不同的顶点数据,您需要自己声明顶点结构,或者向顶点着色器添加输入参数。顶点数据由Cg/HLSL语义标识,必须来自以下列表:
When the mesh data contains fewer components than are needed by the vertex shader input, the rest are filled with zeroes, except for the .w component which defaults to 1. For example, mesh texture coordinates are often 2D vectors with just x and y components. If a vertex shader declares a float4 input with TEXCOORD0 semantic, the value received by the vertex shader will contain (x,y,0,1).
当网格数据包含的组件比顶点着色器输入所需的要少时,其余的都是0,除了vector的w值默认为1。例如,网格纹理坐标通常是二维向量,只有x和y分量。如果顶点着色器声明一个带有TEXCOORD0语义的float4输入,顶点着色器接收的值将包含(x,y,0,1)。
Examples
Visualizing UVs
The following shader example uses the vertex position and the first texture coordinate as the vertex shader inputs (defined in the structure appdata). This shader is very useful for debugging the UV coordinates of the mesh.
下面的着色器示例使用顶点位置和第一个纹理坐标作为顶点着色器输入(在结构体appdata中定义)。这个着色器对于调试网格的UV坐标非常有用。
Shader "Debug/UV 1" {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// vertex input: position, 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 = UnityObjectToClipPos(v.vertex );
o.uv = float4( v.texcoord.xy, 0, 0 );
return o;
}
half4 frag( v2f i ) : SV_Target {
half4 c = frac( i.uv );
if (any(saturate(i.uv) - i.uv))
c.b = 0.5;
return c;
}
ENDCG
}
}
}
Here, UV coordinates are visualized as red and green colors, while an additional blue tint has been applied to coordinates outside of the 0 to 1 range:
在这里,UV坐标显示为红色和绿色,而在0到1范围之外的坐标应用了额外的蓝色色调:
Similarly, this shader vizualizes the second UV set of the model:
类似地,这个着色器使模型的UV2集合可视化:
Shader "Debug/UV 2" {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// vertex input: position, second 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 = UnityObjectToClipPos(v.vertex );
o.uv = float4( v.texcoord1.xy, 0, 0 );
return o;
}
half4 frag( v2f i ) : SV_Target {
half4 c = frac( i.uv );
if (any(saturate(i.uv) - i.uv))
c.b = 0.5;
return c;
}
ENDCG
}
}
}
Visualizing vertex colors
The following shader uses the vertex position and the per-vertex colors as the vertex shader inputs (defined in structure appdata).
下面的着色器使用顶点位置和每个顶点的颜色作为顶点着色器输入(在结构appdata中定义)。
Shader "Debug/Vertex color" {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// vertex input: position, color
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 = UnityObjectToClipPos(v.vertex );
o.color = v.color;
return o;
}
fixed4 frag (v2f i) : SV_Target { return i.color; }
ENDCG
}
}
}
Visualizing normals
The following shader uses the vertex position and the normal as the vertex shader inputs (defined in the structure appdata). The normal’s X,Y & Z components are visualized as RGB colors. Because the normal components are in the –1 to 1 range, we scale and bias them so that the output colors are displayable in the 0 to 1 range.
下面的着色器使用顶点位置和法线作为顶点着色器输入(在结构appdata中定义)。法线的X、Y和Z分量显示为RGB颜色。因为法线组件在-1到1的范围内,我们对它们进行缩放和偏置,以便输出的颜色在0到1的范围内可以显示。
Shader "Debug/Normals" {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// vertex input: position, normal
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 = UnityObjectToClipPos(v.vertex );
o.color.xyz = v.normal * 0.5 + 0.5;
o.color.w = 1.0;
return o;
}
fixed4 frag (v2f i) : SV_Target { return i.color; }
ENDCG
}
}
}
Visualizing tangents and binormals
Tangent and binormal vectors are used for normal mapping. In Unity only the tangent vector is stored in vertices, and the binormal is derived from the normal and tangent values.
法线映射使用切线向量和副法线向量。在Unity中,只有切线向量存储在顶点数据中,副法线是从法向量和切线向量中计算出的。
The following shader uses the vertex position and the tangent as vertex shader inputs (defined in structure appdata). Tangent’s x,y and z components are visualized as RGB colors. Because the normal components are in the –1 to 1 range, we scale and bias them so that the output colors are in a displayable 0 to 1 range.
下面的着色器使用顶点位置和切线作为顶点着色器输入(在结构appdata中定义)。切线的x、y和z分量被可视化为RGB颜色。因为法线的分量在-1到1的范围内,我们对它们进行缩放和偏置,使输出的颜色在可显示的0到1的范围内。
Shader "Debug/Tangents" {
SubShader {
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// vertex input: position, tangent
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 = UnityObjectToClipPos(v.vertex );
o.color = v.tangent * 0.5 + 0.5;
return o;
}
fixed4 frag (v2f i) : SV_Target { return i.color; }
ENDCG
}
}
}
The following shader visualizes bitangents. It uses the vertex position, normal and tangent values as vertex inputs. The bitangent (sometimes called binormal) is calculated from the normal and tangent values. It needs to be scaled and biased into a displayable 0 to 1 range.
下面的着色器可视化副切线。它使用顶点位置、法线和切线值作为顶点输入。副切线(有时称为副法线)是由法线值和切线值计算出来的。它需要缩放和偏置到可显示的0到1范围。
Shader "Debug/Bitangents" {
SubShader {
Pass {
Fog { Mode Off }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// vertex input: position, normal, tangent
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 = UnityObjectToClipPos(v.vertex );
// calculate bitangent
float3 bitangent = cross( v.normal, v.tangent.xyz ) * v.tangent.w;
o.color.xyz = bitangent * 0.5 + 0.5;
o.color.w = 1.0;
return o;
}
fixed4 frag (v2f i) : SV_Target { return i.color; }
ENDCG
}
}
}