Unity Shader基础-HLSL基本语法

Unity Shader基础-HLSL基本语法


下面对微软所给的HLSL官方文档进行简单梳理,将其基本语法总结如下。

1 数据类型


1.1 缓存(Buffer)


  • 用法:Buffer Name

  • 示例:Buffer g_Buffer;

  • 说明:Type可以为标量、向量或一些矩阵类型


1.2 标量


  • bool:布尔值,true或false。

  • int: 32位有符号整型。

  • uint: 32位无符号整型。

  • dword: 32位无符号整型。

  • half: 16位浮点型。该类型只是为了保持语言兼容性,Direct3D 10将所有half都映射为float型,该类型不能用作标准全局变量。

  • float:32位浮点型。

  • fixed: 11位低精度浮点数。
  • double: 64位浮点型。

1.3 向量类型


  • 用法:TypeNumber Name 或 vector <Type, Number> VariableName

  • 示例:

bool    bVector;   // scalar containing 1 Boolean
int1    iVector = 1;
float3  fVector = { 0.2f, 0.3f, 0.4f };
vector <int,    1> iVector = 1;
vector <double, 4> dVector = { 0.2, 0.3, 0.4, 0.5 };
  • 说明:Type为标量类型

1.4 矩阵类型


  • 用法:TypeNumberxNumber Name 或 matrix <Type, Number> VariableName

  • 示例:

int1x1    iMatrix;   // integer matrix with 1 row,  1 column
int4x1    iMatrix;   // integer matrix with 4 rows, 1 column
int1x4    iMatrix;   // integer matrix with 1 row, 4 columns
double3x3 dMatrix;   // double matrix with 3 rows, 3 columns

float2x2 fMatrix = { 0.0f, 0.1, // row 1
					2.1f, 2.2f // row 2
				}; 

matrix <float, 2, 2> fMatrix = { 0.0f, 0.1, // row 1
								2.1f, 2.2f // row 2
							};
  • 说明:Type为标量类型

1.5 采样器类型(Sampler)


  • 用法:
Direct3D 9

sampler Name = SamplerType{   Texture = <texture_variable>;   [state_name = state_value;]   ... }; 
	

Direct3D 10之后:

SamplerType Name[Index]{   [state_name = state_value;]   ... };
  • 示例:
Direct3D 9

sampler MeshTextureSampler = 
sampler_state
{
	Texture = <g_MeshTexture>;
	MipFilter = LINEAR;
	MinFilter = LINEAR;
	MagFilter = LINEAR;
};

Direct3D 10之后:

SamplerState MeshTextureSampler
{
	Filter = MIN_MAG_MIP_LINEAR;
	AddressU = Wrap;
	AddressV = Wrap;
};
  • 说明: sampler:只有Direct3D 9需要。

    Name:采样器名称

    [Index]:Direct3D 10后需要,定义数据长度

    SamplerType:采样器类型,可为: sampler, sampler1D, sampler2D, sampler3D, samplerCUBE, sampler_state, SamplerState,SamplerComparisonState(仅Direct3D 10之后支持)。

    Texture = :纹理变量。

    state_name = state_value:可选状态设置,所有状态赋值必须出现在状态块中(大括号中),由分号分隔。


1.6 着色器类型(Shader)


  • 用法:

    Direct3D 10之后: SetXXXShader Compile( ShaderTarget, ShaderFunction );

    Direct3D 9之前: XXXShader = compile ShaderTarget ShaderFunction(…);

  • 示例:

// Direct3D 10
technique10 Render
{
	pass P0
	{
		SetVertexShader( CompileShader( vs_4_0, VS() ) );
		SetGeometryShader( NULL );
		SetPixelShader( CompileShader( ps_4_0, PS() ) );
	}
}

// Direct3D 9
technique RenderSceneWithTexture1Light
{
	pass P0
	{          
		VertexShader = compile vs_2_0 RenderSceneVS( 1, true, true );
		PixelShader  = compile ps_2_0 RenderScenePS( true );
	}
}
  • 说明: SetXXXShader: Direct3Dy调用底层API创建Shader对象,可为SetPixelShader、SetGeometryShader 或SetVertexShader。(Direct3D 9中XXXShader可为SetPixelShader或SetVertexShader)

    ShaderTarget: 用于编译的shader模型:vs_4_0, gs_4_0或ps_4_0

    ShaderFunction(…):Shader名称,包含着色器入口点函数名,当Shader被调用时,该函数会被执行;(…)表示函数参数,这些参数同样会被传递给创建Shader对象的API函数:SetPixelShader或SetVertexShader


1.7 纹理类型(Texture)


  • 用法:Type Name;

  • 示例:Texture2D g_MeshTexture;

  • 说明:Type可以为texture,Texture1D, Texture1DArray, Texture2D, Texture2DArray, Texture3D, TextureCube。

  • 备注:调用Texture在Direct3D 9和10中有比较大的差异

//9
Output.RGBColor = tex2D(MeshTextureSampler, In.TextureUV) * In.Diffuse;
//10
Output.RGBColor = g_MeshTexture.Sample(MeshTextureSampler, In.TextureUV) * In.Diffuse;

1.8 结构体


用法:

		struct struct2
		{
		  int    a;
		  float  b;
		  int4x4 iMatrix;
		}

访问方式与C语言类似,通过.来访问。


1.9 自定义类型


  • 用法:typedef [const] Type Name[Index];

  • 示例:

typedef int DWORD;
typedef float FLOAT; 
typedef vector <float, 4> VECTOR;
typedef matrix <float, 4, 4> MATRIX;
typedef string STRING;
typedef texture TEXTURE;
typedef pixelshader PIXELSHADER;
typedef vertexshader VERTEXSHADER;
  • 说明:Type可以为HLSL定义的固定类型。

2 HLSL语义


2.1 顶点着色器(Vertex Shader)语义


输入 描述 类型
BINORMAL[n] 次法线 float4
BLENDINDICES[n] 混合指数 uint
BLENDWEIGHT[n] 混合权重 float
COLOR[n] 固有色与高光色 float4
NORMAL[n] 法向量 float4
POSITION[n] 模型空间中顶点坐标 float4
POSITIONT 顶点坐标转置 float4
PSIZE[n] 点大小 float
TANGENT[n] 切线 float4
TEXCOORD[n] 纹理坐标 float4

输出 描述 类型
COLOR[n] 固有色与高光色 float4
FOG 顶点雾化值 float
POSITION[n] 齐次空间顶点坐标,将(x,y,z)除以w即可得到屏幕坐标空间,每个顶点Shader必须有该语义输出。 float4
PSIZE 点大小 float
TESSFACTOR[n] 曲面细分因子 float
TEXCOORD[n] 纹理坐标 float4

2.2 像素着色器(Pixel Shader)语义


输入 描述 类型
COLOR[n] 固有色与高光色 float4
TEXCOORD[n] 纹理坐标 float4
VFACE 用于标记一个背面图元的浮点标量值,负值表示面向背面,正值表示面向相机,该语义仅在Direct3D 9的Shader Model 3.0中可用,Direct3D 10以后使用SV_IsFrontFace替代 float
VPOS 屏幕空间像素位置(x,y). 该语义用于Direct3D 9,之后版本请使用SV_Position float2

输出 描述 类型
COLOR[n] 输出颜色 float4
DEPTH[n] 输出深度 float

2.3 语义变化


Direct3D 10语义 Direct3D 9等价语义
SV_Depth DEPTH
SV_Position POSITION
SV_Target COLOR

2.4 示例


套用《Unity Shader入门精要》一书中的内容作为示例:

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Unlit/TestShader"
{
	SubShader{
		Pass{
			CGPROGRAM

			#pragma vertex vert
			#pragma fragment frag
			//通过结构体定义顶点着色器输入
			struct a2v{
				//POSTION语义:使用模型空间顶点坐标填充vertex变量
				float4 vertex : POSITION; 
				//NORMAL语义:使用模型空间法向量填充normal变量
				float3 normal : NORMAL; 
				//TEXCOORD0语义:使用模型第一套纹理坐标填充texcoord变量
				float4 texcoord : TEXCOORD0; 
			};

			struct v2f{
				//SV_POSTION语义:pos存储了裁剪空间中顶点位置信息
				float4 pos : SV_POSITION; 
				//COLOR0语义:color存储颜色信息
				float3 color : COLOR0; 				
			};


			//SV_POSITION语义:顶点着色器的输出作为裁剪空间顶点坐标
			v2f vert(a2v v){
				v2f o;
				o.pos = UnityObjectToClipPos (v.vertex);
				//将法向量从[-1, 1]映射至[0, 1],通过color传递给像素(片元)着色器
				o.color = v.normal * 0.5 + fixed3(0.5, 0.5, 0.5);
				return o;
			}

			//SV_Target语义:像素着色器的输出存储到一个渲染目标(RenderTarget)当中
			fixed4 frag(v2f i) : SV_Target{			
				return fixed4(i.color, 1.0);
			}
			ENDCG
		}
	}
}

2.5 问题


  • HLSL中POSTION与VS_POSITION的区别?
SV_前缀的变量代表system value,在DX10以后的语义绑定中被使用代表特殊的意义,和POSITION用法并无不同。唯一区别是 SV_POSTION一旦被作为vertex shader的输出语义,那么这个最终的顶点位置就被固定了,直接进入光栅化处理,如果作为fragment shader的输入语义那么和POSITION是一样的,代表着每个像素点在屏幕上的位置,这个说法其实并不准确,事实是fragment 在view space空间中的位置,但直观的感受是如括号之前所述一般。
在DX10版本之前没有引入SV_的预定义语义,POSITION被用作vertex shader的输入和输出,fragment shader的输入参数。但DX10之后就推荐使用SV_POSITION作为vertex shader的输出和fragment shader的输入,**注意vertex shader的输入还是使用POSITION!** **不过,DX10以后的代码依旧兼容POSITION作为全程表达。**

3 函数


3.1 函数声明


HLSL的函数定义与C语言也基本类型,形式如下:

[StorageClass] [clipplanes()] [precise] Return_Value Name ( [ArgumentList] ) [: Semantic]
{
  [StatementBlock]
}; 参数说明:
  • StorageClass: 重定义函数声明的修改器,目前仅支持inline,因此函数总是内联。
  • clipplanes:可选剪裁平面列表,最多为6个定义裁剪平面;该参数功能等同于SV_ClipDistance(特性层次高于9_x)
  • Return_Value: 返回值
  • Name:函数名
  • ArgumentList:参数列表
  • Semantic:返回值的语义(见上一节)
  • StatementBlock:函数块

示例:

struct VS_OUTPUT
{
	float4 Position   : SV_POSITION; 
	float4 Diffuse    : COLOR0;
	float2 TextureUV  : TEXCOORD0;
};

VS_OUTPUT RenderSceneVS( float4 vPos : POSITION,
							float3 vNormal : NORMAL,
							float2 vTexCoord0 : TEXCOORD,
							uniform int nNumLights,
							uniform bool bTexture,
							uniform bool bAnimate )
{
	VS_OUTPUT Output;
	...
	return Output;    
}

3.2 函数参数


参数形式如下:

[InputModifier] Type Name [: Semantic] [InterpolationModifier] [= Initializers]

参数说明:

  • InputModifier:可选参数,定义参数为输入、输出或两者皆是。 in为输入,out为输出,inout为输入输出,uniform为常量输入。不填时参数默认为in,被定义成uniform可视为全局变量,对于非顶层函数,uniform与in同义。
  • Type:参数类型
  • Name:参数名称
  • Semantic :参数语义
  • InterpolationModifier:插值修改器,用于定义着色器的插值函数,应用于函数参数时,仅用像素着色器函数输入参数
  • Initializers:初始值

示例:

VS_OUTPUT RenderSceneVS( 
	float4 vPos : POSITION,
	float3 vNormal : NORMAL,
	float2 vTexCoord0 : TEXCOORD,
	uniform int nNumLights,
	uniform bool bTexture,
	uniform bool bAnimate )
{
	...
}

3.3 返回值


参数形式如下:

return [value];

参数说明:返回值可为一个或多个值

示例:

float4x4 WorldViewProj;

struct VS_OUTPUT
{
	float4 Pos  : POSITION;
};

VS_OUTPUT VertexShader_Tutorial_1(float4 inPos : POSITION )
{
	VS_OUTPUT out;
	out.Pos = mul(inPos, WorldViewProj );
	return out;
};

float4 func(float2 a: POSITION): COLOR
{
	return float4(sin(length(a) * 100.0) * 0.5 + 0.5, sin(a.y * 50.0), 0, 1);
}

3.4 签名


着色器签名是着色器函数输入或输出的一个参数列表(通过语义来实现),输入签名由着色器输入声明产生,输出签名由着色器输出声明产生,若输出签名为输入签名的子集(声明类型及顺序相同),则称输入签名兼容输出签名。最简单的兼容方式便是让着色器的输入输出为相同结构体。

示例一:可兼容签名(官方给出的例子是输入签名输出签名的子集,官方给出的上面定义应该是写错了

// Vertex Shader Output Signature
Struct VSOut
{
	float4 Pos: SV_Position;
	float3 MyNormal: Normal;
	float2 MyTex : Texcoord0;
}

// Pixel Shader Input Signature
Struct PSInWorks
{
	float4 Pos: SV_Position;
	float3 MyNormal: Normal;
}

示例二:非兼容签名

// Vertex Shader Output Signature
Struct VSOut
{
	float4 Pos: SV_Position;
	float3 MyNormal: Normal;
	float2 MyTex : Texcoord0;
}

// Pixel Shader Input Signature
Struct PSInFails
{
	float3 MyNormal: Normal;
	float4 Pos: SV_Position;
}

4 流程控制语句


HLSL的流程控制语句与C语言基本相似,支持以下流程控制语句:

  • break
  • continue
  • discard
  • do
  • for
  • if
  • switch
  • while

比较特殊的流程控制语句仅为discard语句:

  • 功能:当前结果不输出至当前像素点。

  • 备注:该语句只能像素着色器调用,不能被几何着色器或顶点着色器调用。


参考


Tags: Unity Shader Vistied:
Share: Twitter Facebook LinkedIn