Shader笔记_003UNITY提供的内置变量和文件及特殊语义

风流意气都作罢 提交于 2020-07-28 11:11:36

当我们查看别人的shader,如果没有在代码里找到声明那多半是使用了UNITY内置的文件和变量。

一、包含文件

UNITY可以使用#include 来包含部分文件,文件后缀.cginc,类似C++头文件/java的包 

例如

CGPROGRAM
...
   #include "UnityCG.cginc"
...
ENDCG

 

通过这种方式可以引用UNITY已经封装好的函数/变量我们可以通过 http://unity3d.com/cn/get-unity/download/archive 下载(虽然网站没法访问)

常用的UNITY内置文件

UnityCG.cginc 包含了最常用的函数结构体和宏等

UnityShaderVariables.cginc 在编译UNITY SHADER时 会自动被包含进来 ,包含了很多全局变量 如 UNITY_MATRIX_MVP转换矩阵

Lighting.cginc 包含了各种光照模型,如果编写Surface Shader的话 会被自动包含进来

HLSLSupport.cginc 在编译UNITY SHADER时被自动包含进来,声明了很多用于跨平台编译的宏和定义

UnityStandardBRDF.cginc、UnityStandardCore.cginc 这些文件里面包含了用于基于物理的渲染 

-----------------------------------------------------------

其中UnityCG.cginc是最常用的组件 他里面提供了很多常用的定义和文件

常用结构体名 包含变量
appdata_base  顶点位置 顶点法线 第一组纹理坐标
appdata_tan 顶点位置 顶点法线 顶点切线 第一组纹理坐标
appdata_full 顶点位置 顶点法线 顶点切线 第四组(或者更多)纹理坐标
appdata_img 顶点位置 第一组纹理坐标
v2f_img 裁剪空间中的位置 纹理坐标

UnityCG.cginc常用的函数

函数名 描述
float3 WordSpaceViewDir(float4 v)  输入一个模型空间的顶点位置,返回在世界空间中这个点到摄像机的方向
float3 ObjSpaceViewDir(flaot4 v) 输入一个模型空间的顶点位置,返回在模型空间中这个点到摄像机的方向
float3 WordSpaceLightDir(float4 v) 仅可用于前向渲染,输入一个模型空间的顶点,返回世界空间中该点到光源的光照方向,没有被归一化
flaot3 ObjSpaceLightDir(float4 v) 仅可用于前向渲染,输入一个模型空间的顶点,返回模型空间中该点到光源的光照方向,没有被归一化
float3 UnityObjToWorldNormal(flaot3 normal) 把法线方向从模型空间转换到世界空间
float3 UnityObjToWorldDir(int float3 dir) 把方向矢量从模型空间转换到世界空间中
float3 UnityWorldToObjDir(int float3 dir) 把方向矢量从世界空间转换到模型空间中

二、内置变量

除了上述常用的函数和文件,unity还提供了很多常用的变量,如用于访问环境光、雾效、时间、光照等目的的变量,这些变量大都在UnityShaderVariables.cginc中

光照的变量还位于 Lighting.cginc 和AutoLight.cginc

三、Unity支持的语义

SV_POSITION/SV_Target/POSITION/COLOR0等等都是CG/HLSL提供的语义

可以在微软的DirectX的文档里找到说明(网址倒是能打开 ,就是没看懂)

http://msdn.microsoft.com/en-us/library/windows/desktop/bb509674(v=vs8.5).aspx#VS

语义其实就是赋给shader的一个输入输出的字符串,这个字符串表达了参数的含义,这些语义可以让shader知道从哪里读取数据,并把数据输出到哪里

他们在CG/HLSL的shader流水线中是不可获取的,需要注意的是 Unity并没有支持所有的语义

通常情况下 这些输入输出的参数并不需要特别有意义,我们可以自行决定这些变量的用途.变量本身存储什么 shader并不关心

UNITY为了方便数据传输,对一些特殊的语义进行了特殊的含义规定,例如TEXCOORD0,在顶点着色器的入参结构体a2v的内部我们用它描述texcoord,UNITY会识别该语义并把第一组纹理坐标填充给texcoord,需要注意即使语义一样出现的位置不同,意义也可能不同,如TEXCOORD0出现在输出结构体内时,这个修饰的变量由我自己定义。

在DirectX10之后出现了一种新语义,系统语义,SV开头 System Value Semantics

例如上面的SV_POSITION修饰pos,那么就表示pos包含了可以用于光栅化的变换后的顶点坐标,即齐次裁剪空间坐标,这些语义修饰的变量是不可随便赋值的,因为流水线需要靠他们去实现一些特殊的目的,例如渲染引擎会把SV_POSITION的坐标经过光栅化后显示在屏幕上,有的时候我们会看到同样的变量在不同的shader里用不同的语义修饰,例如一些shader会使用POSITION而不是SV_POSITION来修饰顶点的着色器输出,SV_POSITION 和POSITION在大多数平台上是等价的,但在某些平台上必须使用SV_POSITION来修饰输出,同样的情况还会在COLOR0和SV_Target上出现,所以我们尽量使用SV开头的修饰符。

语义名称 描述
POSITION 模型空间中的顶点位置,通常是float4类型
NORMAL 顶点法线,通常是float3类型
TANGENT 顶点切线,通常是float4类型
TEXCOORDn 第n组纹理坐标,通常是float2和float4类型
COLOR 顶点颜色,通常是float4或者fixed4

TEXCOORDn的n是由shader model决定的 ,在shader model2 的时候 n最大为4,在shader model 3的时候为8,在shader model 4的时候为16

通常情况下 一个模型的纹理坐标不超过2,即我们往往只使用TEXCOORD0/TEXCOORD1,在UNITY内置的appdata_full中,最多使用6个坐标纹理组

从顶点着色器传递到片元着色器的常用语义

语义 描述
SV_POSITION 裁剪空间里的顶点坐标,输出结构体必须包含这个修饰的变量,DirectX9里面是POSITION,但最好使用SV_POSITION
COLOR0 通常用于输出的第一组颜色 但是不是必须的
COLOR1 通常用于输出的第二组颜色,但是不是必须的
TEXCOORD0~TEXCOORD7 通常用于输出纹理坐标,但是不是必须的

上面的语义 除了SV_POSITION之外,其他语义对变量没有明确的要求,也就是说我们可以存储任意值到语义描述的变量中,通常我们把一些自定义数据从顶点着色器传递到片元着色器,使用TEXCOORD0修饰。

片元着色器输出时使用的常用语义 SV_Target:输出值会存储到渲染目标Render Target中,等同于DirectX9中的COLOR语义,但最好使用SV_Target。

四、如何定义复杂的变量类型

上面提到的语义多半用来描述矢量或者标量类型的变量,例如fixed2 float float4 fixed4

下面的代码给出了一些使用语义来修饰不同变量的例子

struct v2f{

  float4 pos:SV_POSITION;

  fixed3 color0:COLOR0;

  fixed4 color1:COLOR1;

  half value0:TEXCOORD0;

  float2 value1:TEXCOORD1;

}

需要注意 一个语义可以使用的寄存器最多只能使用四个浮点值,因此如果我们想要定义矩阵类型,如float3*4,float4*4等变量就需要使用更多的空间,另一种方法就是把这些变量拆分成多个变量,如float4*4 可以拆分成4个float4,每个变量存储一行矩阵的元素。

 

 

 


 

 

 

 

 

 

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!