26.CG-内置文件
26.1 知识点
CG内置文件的位置和作用
在Unity的安装目录中,可以找到CG内置文件,它们位于Unity版本号->Editor—>Data—>CGIncludes目录中。
这些文件的后缀为.cginc,是CG语言内置文件。
这些文件是预定义的Shader文件,包含了一些已经写好的Shader相关逻辑。
和CG内置函数一样,这些文件可以提升我们的Shader开发效率,我们可以直接使用其中的方法等内容来进行逻辑开发。
Unity中常用的内置文件有:
UnityCG.cginc
:包含最常用的帮助函数、宏和结构体等。Lighting.cginc
:包含各种内置光照模型。如果编写的是Surface Shader(标准表面着色器),会自动包含进来。UnityShaderVariables.cginc
:编译UnityShader时,会自动包含进来。包含许多内置的全局变量。HLSLSupport.cginc
:编译UnityShader时,会自动包含进来。声明了很多用于跨平台编译的宏和定义等等。
尝试用sublimetext打开
UnityCG.cginc
,可以看到无非是用CG语法帮我们写好了常用的帮助函数、宏和结构体
如何使用CG内置文件
在CG语句块中进行引用,通过编译指令
#include "内置文件名.cginc"
的形式进行引用,我们便可以在CG语言中使用其中的内容。注意:一些常用的函数、宏、变量,可以不用引用,Unity会在编译时自动识别。但是为了避免报错,建议都引用。
“宏”通常指的是一种预处理指令或代码片段,用于在代码中进行文本替换。宏允许程序员定义一个标识符(通常以大写字母表示)来代表一个代码片段,然后在编译时将这个标识符替换为相应的代码,这种替换过程称为宏展开。
说人话:就是为一些代码片段,取一个别名,方便使用。在真正编译时在把这个别名翻译成对应的代码。
使用CG内置文件代码示例
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
//...
ENDCG
}
}
常用内容
方法(UnityCG.cginc中)
float3 WorldSpaceViewDir(float4 v)
: 输入一个模型空间中的顶点位置,返回世界空间中从该点到摄像机的观察方向。float3 ObjSpaceViewDir(float4 v)
: 输入一个模型空间中的顶点位置,返回模型空间中从该点到摄像机的观察方向。float3 WorldSpaceLightDir(float4 v)
: 仅用于向前渲染中。输入一个模型空间中的顶点位置,返回世界空间中从该点到光源的光照方向。(返回值没有被归一化)float3 ObjSpaceLightDir(float4 v)
: 仅用于向前渲染中。输入一个模型空间中的顶点位置,返回模型空间中从该点到光源的光照方向。(返回值没有被归一化)float3 UnityObjectToWorldNormal(float3 norm)
: 把法线方向从模型空间转换到世界空间中。float3 UnityObjectToWorldDir(in float3 dir)
: 把方向矢量从模型空间转换到世界空间中。float3 UnityWorldToObjectDir(float3 dir)
: 把方向矢量从世界空间转换到模型空间中。
结构体(UnityCG.cginc中)
appdata_base
: 用于顶点着色器输入,包含顶点位置、顶点法线、第一组纹理坐标。appdata_tan
: 用于顶点着色器输入,包含顶点位置、顶点法线、顶点切线、第一组纹理坐标。appdata_full
: 用于顶点着色器输入,包含顶点位置、顶点法线、顶点切线、四组(或更多)纹理坐标。appdata_img
: 用于顶点着色器输入,包含顶点位置、第一组纹理坐标。v2f_img
: 用于顶点着色器输出,包含裁剪空间中的位置、纹理坐标。
结构体使用示例
- 之前我们是自己声明结构体在顶点函数中使用的和片元函数
struct a2v
{
//顶点坐标(基于模型空间)
float4 vertex:POSITION;
//顶点法线(基于模型空间)
float3 normal:NORMAL;
//纹理坐标(uv坐标)
float2 uv:TEXCOORD0;
};
struct v2f
{
//裁剪空间下的坐标
float4 position:SV_POSITION;
//顶点法线(基于模型空间)
float3 normal:NORMAL;
//纹理坐标(uv坐标)
float2 uv:TEXCOORD0;
};
// 顶点着色器函数,将a2v数据转换为v2f数据
v2f vert(a2v data)
{
//定义顶点着色器传递给片段着色器的数据结构体 需要传递给片元着色器的数据
v2f v2fData;
// 将顶点坐标转换为裁剪空间下的坐标
v2fData.position = UnityObjectToClipPos(data.vertex);
// 传递顶点法线
v2fData.normal = data.normal;
// 传递纹理坐标
v2fData.uv = data.uv;
return v2fData;
}
// 片段着色器函数,返回贴图对应uv的颜色
fixed4 frag(v2f data) : SV_Target
{
fixed4 color = tex2D(_My2D, data.uv);
return color;
}
- 现在直接可以在顶点函数和片元函数中使用定义好的appdata_base和v2f_img结构体
//使用UnityCG.cginc内置结构体v2f_img和appdata_base
v2f_img vert(appdata_base data)
{
//定义顶点着色器传递给片段着色器的数据结构体 需要传递给片元着色器的数据
v2f_img v2fData;
// 将顶点坐标转换为裁剪空间下的坐标
v2fData.pos = UnityObjectToClipPos(data.vertex);
// v2fData.pos = mul(UNITY_MATRIX_MVP,data.vertex);
// 传递顶点法线 v2f_img结构体中不存在normal 注释
// v2fData.normal = data.normal;
// 传递纹理坐标
v2fData.uv = data.texcoord;
return v2fData;
}
//使用UnityCG.cginc内置结构体v2f_img和appdata_base
fixed4 frag(v2f_img data) : SV_Target
{
fixed4 color = tex2D(_My2D, data.uv);
return color;
}
- 完整代码如下
Shader "ShaderTeach/Lesson26_NewUnlitShader"
{
Properties
{
// 纹理贴图类型属性
_My2D("My2D", 2D) = "white" {}
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// 纹理贴图类型属性
sampler2D _My2D;
//使用UnityCG.cginc内置结构体v2f_img和appdata_base
v2f_img vert(appdata_base data)
{
//定义顶点着色器传递给片段着色器的数据结构体 需要传递给片元着色器的数据
v2f_img v2fData;
// 将顶点坐标转换为裁剪空间下的坐标
v2fData.pos = UnityObjectToClipPos(data.vertex);
// v2fData.pos = mul(UNITY_MATRIX_MVP,data.vertex);
// 传递顶点法线 v2f_img结构体中不存在normal 注释
// v2fData.normal = data.normal;
// 传递纹理坐标
v2fData.uv = data.texcoord;
return v2fData;
}
//使用UnityCG.cginc内置结构体v2f_img和appdata_base
fixed4 frag(v2f_img data) : SV_Target
{
fixed4 color = tex2D(_My2D, data.uv);
return color;
}
ENDCG
}
}
}
变换矩阵宏(UnityShaderVariables.cginc中)
坐标空间变换顺序:模型空间 -> 世界空间 -> 观察空间 -> 裁剪空间 -> 屏幕空间。
UNITY_MATRIX_MVP
: 当前的模型观察投影矩阵,用于将顶点/方向向量从模型空间变换到裁剪空间中。UNITY_MATRIX_MV
: 当前的模型*观察矩阵,用于将顶点/方向向量从模型空间变换到观察空间中。UNITY_MATRIX_V
: 当前的观察矩阵,用于将顶点/方向向量从世界空间变换到观察空间中。UNITY_MATRIX_P
: 当前的投影矩阵,用于将顶点/方向向量从观察空间变换到裁剪空间中。UNITY_MATRIX_VP
: 当前的观察*投影矩阵,用于将顶点/方向向量从世界空间变换到裁剪空间中。UNITY_MATRIX_T_MV
:UNITY_MATRIX_MV
的转置矩阵。UNITY_MATRIX_IT_MV
:UNITY_MATRIX_MV
的逆转置矩阵,用于将法线从模型空间变换到观察空间,也可用于得到UNITY_MATRIX_MV
的逆矩阵。_Object2World
: 当前的模型矩阵,用于将顶点/方向矢量从模型空间变换到世界空间。_World2Object
:_Object2World
的逆矩阵,用于将顶点/方向矢量从世界空间变换到模型空间。注意:
- Unity5.5版本中_Object2World已经变成unity_ObjectToWorld,_World2Object也变成了unity_WorldToObject。
- 但由于Unity的向下兼容性,Unity会自动改写它们,不会出错。如下是自动改后的提示,出现在代码最上方。
变换矩阵宏使用示例
//使用UnityCG.cginc内置结构体v2f_img和appdata_base
v2f_img vert(appdata_base data)
{
//...
//把模型的点转换成世界坐标
float worldPos = mul(unity_ObjectToWorld,data.vertex);
//...
}
变量
_Time
(不用引用,直接使用即可): 自关卡加载以来的时间(t/20、t、t2、t3)用于对着色器内的事物进行动画处理。_LightColor0
(向前渲染时,UnityLightingCommon.cginc;延迟渲染,UnityDeferredLibrary.cginc): 光的颜色等等。
总结
- CG中的内置文件和内置函数一样,是用于帮助我们进行Shader开发的。
- 利用其中的函数、宏、全局变量等内容可以提升我们Shader的开发效率。
- 我们需要做的是,将这些常用内容记到笔记中,之后进行查阅。如果想要了解更多的内置内容可以参阅Unity官网的资料。
- 内置文件相关:https://docs.unity3d.com/Manual/SL-BuiltinIncludes.html
- 函数相关:https://docs.unity3d.com/Manual/SL-BuiltinFunctions.html
- 宏相关:https://docs.unity3d.com/Manual/SL-BuiltinMacros.html
- 变量相关:https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html。
26.2 知识点代码
Lesson26_CG_内置文件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Lesson26_CG_内置文件 : MonoBehaviour
{
void Start()
{
#region 知识点一 CG内置文件的位置和作用
//我们可以在Unity的安装目录中找到CG内置文件
//在Editor—>Data—>CGIncludes中
//后缀为cginc的文件为CG语言内置文件
//后缀为glslinc的文件为GLSL语言内置文件
//他们是预定义的Shader文件
//里面包含了一些已经写好的Shader相关逻辑
//作用和CG内置函数一样,可以提升我们的Shader开发效率
//可以直接使用其中的方法等内容来进行逻辑开发
//Unity中常用的内置文件有
//1.UnityCG.cginc 包含最常用的帮助函数、宏和结构体等
//2.Lighting.cginc 包含各种内置光照模型。如果编写的是Surface Shader(标准表面着色器),会自动包含进来
//3.UnityShaderVariables.cginc 编译UnityShader时,会自动包含进来。包含许多内置的全局变量
//4.HLSLSupport.cginc 编译UnityShader时,会自动包含进来。声明了很多用于跨平台编译的宏和定义
//等等
#endregion
#region 知识点二 如何使用CG内置文件
//在CG语句块中进行引用
//通过编译指令
//#include "内置文件名.cginc"
//的形式进行引用
//我们便可以在CG语言中使用其中的内容
//注意:一些常用的函数、宏、变量,可以不用引用,Unity会在编译时自动识别
// 但是为了避免报错,建议都引用
//"宏"通常指的是一种预处理指令或代码片段,用于在代码中进行文本替换。
//宏允许程序员定义一个标识符(通常以大写字母表示)来代表一个代码片段,
//然后在编译时将这个标识符替换为相应的代码,这种替换过程称为宏展开。
//说人话:就是为一些代码片段,取一个别名,方便使用。在真正编译时在把这个别名翻译成对应的代码。
#endregion
#region 知识点三 常用内容
#region 方法(UnigyCG.cginc中)
//1.float3 WorldSpaceViewDir(float4 v)
// 输入一个模型空间中的顶点位置,返回世界空间中从该点到摄像机的观察方向
//2.float3 ObjSpaceViewDir(float4 v)
// 输入一个模型空间中的顶点位置,返回模型空间中从该点到摄像机的观察方向
//3.float3 WorldSpaceLightDir(float4 v)
// 仅用于向前渲染中。输入一个模型空间中的顶点位置,返回世界空间中从该点到光源的光照方向。(返回值没有被归一化)
//4.flaot3 ObjSpaceLightDir(float4 v)
// 仅用于向前渲染中。输入一个模型空间中的顶点位置,返回模型空间中从该点到光源的光照方向。(返回值没有被归一化)
//5.float3 UnityObjectToWorldNormal(float3 norm)
// 把法线方向从模型空间转换到世界空间中
//6.float3 UnityObjectToWorldDir(in float3 dir)
// 把方向矢量从模型空间转换到世界空间中
//7.float3 UnityWorldToObjectDir(float3 dir)
// 把方向矢量从世界空间转换到模型空间中
//等等
#endregion
#region 结构体(UnigyCG.cginc中)
//1.appdata_base
// 用于顶点着色器输入
// 顶点位置、顶点法线、第一组纹理坐标
//2.appdata_tan
// 用于顶点着色器输入
// 顶点位置、顶点法线、顶点切线、第一组纹理坐标
//3.appdata_full
// 用于顶点着色器输入
// 顶点位置、顶点法线、顶点切线、四组(或更多)纹理坐标
//4.appdata_img
// 用于顶点着色器输入
// 顶点位置、第一组纹理坐标
//5.v2f_img
// 用于顶点着色器输出
// 裁剪空间中的位置,纹理坐标
//等等
#endregion
#region 变换矩阵宏(UnityShaderVariables.cginc中)
//坐标空间变换顺序
// 模型空间 -> 世界空间 -> 观察空间 -> 裁剪空间 -> 屏幕空间
//1.UNITY_MATRIX_MVP
// 当前的模型*观察*投影矩阵,用于将顶点/方向向量从模型空间变换到裁剪空间中
//2.UNITY_MATRIX_MV
// 当前的模型*观察矩阵,用于将顶点/方向向量从模型空间变换到观察空间中
//3.UNITY_MATRIX_V
// 当前的观察矩阵,用于将顶点/方向向量从世界空间变换到观察空间中
//4.UNITY_MATRIX_P
// 当前的投影矩阵,用于将顶点/方向向量从观察空间变换到裁剪空间中
//5.UNITY_MATRIX_VP
// 当前的观察*投影矩阵,用于将顶点/方向向量从世界空间变换到裁剪空间中
//6.UNITY_MATRIX_T_MV
// UNITY_MATRIX_MV的转置矩阵
//7.UNITY_MATRIX_IT_MV
// UNITY_MATRIX_MV的逆转置矩阵,用于将法线从模型空间变换到观察空间,也可用于得到UNITY_MATRIX_MV的逆矩阵
//8._Object2World
// 当前的模型矩阵,用于将顶点/方向矢量从模型空间变换到世界空间
//9._World2Object
// _Object2World的逆矩阵,用于将顶点/方向矢量从世界空间变换到模型空间
//等等
#endregion
#region 变量
//1._Time (不用引用,直接使用即可)
// 自关卡加载以来的时间(t/20、t、t*2、t*3)用于对着色器内的事物进行动画处理
//2._LightColor0 (向前渲染时,UnityLightingCommon.cginc;延迟渲染,UnityDeferredLibrary.cginc)
// 光的颜色
//等等
#endregion
#endregion
#region 总结
//CG中的内置文件和内置函数一样
//是用于帮助我们进行Shader开发的
//利用其中的函数、宏、全局变量等内容
//可以提升我们Shader的开发效率
//我们需要做的是,将这些常用内容记到笔记中
//之后进行查阅
//如果想要了解更多的内置内容可以参阅Unity官网的资料
//内置文件相关:https://docs.unity3d.com/Manual/SL-BuiltinIncludes.html
//函数相关:https://docs.unity3d.com/Manual/SL-BuiltinFunctions.html
//宏相关:https://docs.unity3d.com/Manual/SL-BuiltinMacros.html
//变量相关:https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html
#endregion
}
}
Lesson26_NewUnlitShader
Shader "ShaderTeach/Lesson26_NewUnlitShader"
{
Properties
{
// 纹理贴图类型属性
_My2D("My2D", 2D) = "white" {}
}
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
// 纹理贴图类型属性
sampler2D _My2D;
//使用UnityCG.cginc内置结构体v2f_img和appdata_base
v2f_img vert(appdata_base data)
{
//定义顶点着色器传递给片段着色器的数据结构体 需要传递给片元着色器的数据
v2f_img v2fData;
// 将顶点坐标转换为裁剪空间下的坐标
v2fData.pos = UnityObjectToClipPos(data.vertex);
// v2fData.pos = mul(UNITY_MATRIX_MVP,data.vertex);
//把模型的点转换成世界坐标
float worldPos = mul(unity_ObjectToWorld,data.vertex);
// 传递顶点法线 v2f_img结构体中不存在normal 注释
// v2fData.normal = data.normal;
// 传递纹理坐标
v2fData.uv = data.texcoord;
return v2fData;
}
//使用UnityCG.cginc内置结构体v2f_img和appdata_base
fixed4 frag(v2f_img data) : SV_Target
{
fixed4 color = tex2D(_My2D, data.uv);
return color;
}
ENDCG
}
}
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com