Unity 在编译着色器程序时会定义几个预处理器宏。
宏: | 目标平台: |
---|---|
SHADER_API_D3D11 |
Direct3D 11 |
SHADER_API_GLCORE |
桌面端 OpenGL“核心”(GL 3/4) |
SHADER_API_GLES3 |
OpenGL ES 3.0/3.1 |
SHADER_API_METAL |
iOS/Mac Metal |
SHADER_API_VULKAN |
Vulkan |
SHADER_API_D3D11_9X |
适用于通用 Windows 平台的 Direct3D 11“功能级别 9.x”目标 |
SHADER_API_DESKTOP |
Windows, Mac and Linux desktop platforms, Web |
SHADER_API_MOBILE |
iOS and Android mobile platforms, tvOS |
此外,当目标着色语言为 GLSL 时,还会定义 SHADER_TARGET_GLSL
(对于 OpenGL/GLES 平台来说始终会定义)。
SHADER_TARGET
被定义为与着色器目标编译模型匹配的数值(即匹配 #pragma target
指令)。例如,当编译到着色器模型 3.0 时,SHADER_TARGET
为 30
。您可以在着色器代码中使用此宏来进行条件检查。例如:
# if SHADER_TARGET < 30
// 低于着色器模型 3.0:
// 着色器功能非常有限,执行近似操作
# else
// 不错的功能,执行更高级的任务
# endif
UNITY_VERSION
contains the numeric value of the Unity version. For example, UNITY_VERSION
is 202030
for Unity 2020.3.0. This can be used for version comparisons if you need to write Shaders that use different built-in Shader functionality. For example, a #if UNITY_VERSION >= 202000
preprocessor check only passes on versions 2020 or later.
编译每个着色器阶段时会定义预处理器宏 SHADER_STAGE_VERTEX
、SHADER_STAGE_FRAGMENT
、SHADER_STAGE_DOMAIN
、SHADER_STAGE_HULL
、SHADER_STAGE_GEOMETRY
或 SHADER_STAGE_COMPUTE
。通常,在像素着色器和计算着色器之间共享着色器代码时,这些宏非常有用,可以解决某些工作必须以略有不同的方式来完成的情况。
不鼓励直接使用这些平台宏,因为它们并非始终有助于代码的未来验证。例如,如果您正在编写一个检查 D3D11 的着色器,您可能希望确保在将来将这项检查扩展为包含 Vulkan。应改用 Unity 定义的几个 helper 宏(在 HLSLSupport.cginc
中):
宏: | 用途: |
---|---|
UNITY_BRANCH |
在条件语句之前添加此宏,告知编译器应将其编译为实际分支。在 HLSL 平台上扩展为 [branch] 。 |
UNITY_FLATTEN |
在条件语句之前添加此宏,告知编译器应该将其展平以避免实际的分支指令。在 HLSL 平台上扩展为 [flatten] 。 |
UNITY_NO_SCREENSPACE_SHADOWS |
在不使用级联屏幕空间阴影贴图的平台(移动平台)上定义。 |
UNITY_NO_LINEAR_COLORSPACE |
在不支持线性颜色空间的平台(移动平台)上定义。 |
UNITY_NO_RGBM |
在不使用光照贴图 RGBM 压缩的平台(移动平台)上定义。 |
UNITY_NO_DXT5nm |
在不使用 DXT5nm 法线贴图压缩的平台(移动平台)上定义。 |
UNITY_FRAMEBUFFER_FETCH_AVAILABLE |
Defined on platforms where “framebuffer color fetch” functionality can be available (generally iOS platforms). |
UNITY_USE_RGBA_FOR_POINT_SHADOWS |
在点光源阴影贴图使用具有编码深度的 RGBA 纹理的平台(其他平台使用单通道浮点纹理)上定义。 |
UNITY_ATTEN_CHANNEL |
定义光源衰减纹理的哪个通道包含数据;用于每像素光照代码。定义为“r”或“a”。 |
UNITY_HALF_TEXEL_OFFSET |
Defined on platforms that need a half-texel offset adjustment in mapping texels to pixels. |
UNITY_UV_STARTS_AT_TOP |
始终定义值为 1 或 0。值为 1 表示在平台上的纹理之上的纹理 V 坐标为 0。Direct3D 类平台使用值 1;OpenGL 类平台使用值 0。 |
UNITY_MIGHT_NOT_HAVE_DEPTH_Texture |
如果平台可以通过手动将深度渲染到纹理中来模拟阴影贴图或深度纹理,则定义此宏。 |
UNITY_PROJ_COORD(a) |
给定一个 4 分量矢量,此宏返回一个适合投影纹理读取的纹理坐标。在大多数平台上,它直接返回给定值。 |
UNITY_NEAR_CLIP_VALUE |
Defined to the value of near clipping plane. Direct3D-like platforms use 1.0 while OpenGL-like platforms use –1.0. |
UNITY_VPOS_TYPE |
定义像素位置输入 (VPOS) 所需的数据类型:D3D9 上为 float2 ,其他为 float4 。 |
UNITY_CAN_COMPILE_TESSELLATION |
在着色器编译器“理解”曲面细分着色器 HLSL 语法时定义(当前仅限 D3D11)。 |
UNITY_INITIALIZE_OUTPUT(type,name) |
将给定_类型_的变量_名称_初始化为零。 |
UNITY_COMPILER_HLSL , UNITY_COMPILER_HLSL2GLSL , UNITY_COMPILER_CG
|
指示正在使用哪个着色器编译器来编译着色器。有关更多详细信息,请参阅有关着色器编译的文档。如果遇到编译器之间有非常具体的着色器语法处理差异,并希望为每个编译器编写不同的代码,请使用此宏。 |
UNITY_REVERSED_Z
- 在使用反转 Z 缓冲区的平台上定义。存储的 Z 值的范围是 1 到 0,而不是 0 到 1。根据平台的不同,声明和采样阴影贴图可能会有很大差异。Unity 有几个宏可帮助解决这个问题:
宏: | 用途: |
---|---|
UNITY_DECLARE_SHADOWMAP(tex) |
声明一个名为“tex”的阴影贴图纹理变量。 |
UNITY_SAMPLE_SHADOW(tex,uv) |
在给定的“uv”坐标处采样阴影贴图纹理“tex”(XY 分量是纹理位置,Z 分量是要比较的深度)。返回单个浮点值,阴影项的范围在 0 到 1 之间。 |
UNITY_SAMPLE_SHADOW_PROJ(tex,uv) |
与上面类似,但是会读取投影阴影贴图。“uv”是一个 float4,所有其他分量除以 .w 来执行查找。 |
The format of tex
must be RenderTextureFormat.Shadowmap.
注意:并非所有显卡都支持阴影贴图。请使用 SystemInfo.SupportsRenderTextureFormat 检查是否支持。
Direct3D 11 将所有着色器变量分组为“常量缓冲区”。Unity 的大多数内置变量已经分组,但对于您自己的着色器中的变量,更加理想的做法是,根据预期的更新频率将它们放入单独的常量缓冲区。
对此,请使用 CBUFFER_START(name)
和 CBUFFER_END
宏:
CBUFFER_START(MyRarelyUpdatedVariables)
float4 _SomeGlobalValue;
CBUFFER_END
If you use a GPU compute buffer or graphics buffer to set the value of the variables, make sure the buffer and the constant buffer have matching data layouts on all graphics APIs you build for. See Using constant buffers with GPU buffers for more information.
通常,在着色器代码中使用 texture2D
来声明纹理和采样器对。
但是在某些平台(例如 DX11)上,纹理和采样器是单独的对象,
并且可能的采样器最大数量非常有限。Unity 有一些宏来声明
没有采样器的纹理,并使用另一个纹理中的采样器对纹理进行采样。
如果您遇到采样器限制,并且知道几个纹理实际上可以共享同一个采样器
(采样器定义纹理过滤和包裹模式),请使用这些宏。
宏: | 用途: |
---|---|
UNITY_DECLARE_TEX2D(name) |
声明纹理和采样器对。 |
UNITY_DECLARE_TEX2D_NOSAMPLER(name) |
声明不含采样器的纹理。 |
UNITY_DECLARE_TEX2DARRAY(name) |
声明纹理数组采样器变量。 |
UNITY_SAMPLE_TEX2D(name,uv) |
使用给定的纹理坐标从纹理和采样器对中采样。 |
UNITY_SAMPLE_TEX2D_SAMPLER( name,samplername,uv) |
使用另一个纹理中的采样器 (samplername),从纹理 (name) 中采样。 |
UNITY_SAMPLE_TEX2DARRAY(name,uv) |
从具有 float3 UV 的纹理数组中采样;坐标的 z 分量是数组元素索引。 |
UNITY_SAMPLE_TEX2DARRAY_LOD(name,uv,lod) |
从具有显式 Mipmap 级别的纹理数组中采样。 |
有关更多信息,请参阅采样器状态文档。
编译表面着色器时,表面着色器会为各种通道生成大量代码以产生光照。编译每个通道时,将定义以下宏之一:
宏: | 用途: |
---|---|
UNITY_PASS_FORWARDBASE |
前向渲染基础通道(主方向光、光照贴图和 SH)。 |
UNITY_PASS_FORWARDADD |
前向渲染附加通道(每个通道一个光源)。 |
UNITY_PASS_DEFERRED |
延迟着色通道(渲染 G 缓冲区)。 |
UNITY_PASS_SHADOWCASTER |
阴影投射物和深度纹理渲染通道。 |
UNITY_SHADER_NO_UPGRADE
允许您禁止 Unity 自动升级或修改着色器文件。
大多数情况下,深度纹理用于渲染距离摄像机的深度。在此情况下,UnityCG.cginc include 文件包含的一些宏可以处理上述复杂问题:
Note: On DX11/12 and Metal, the Z buffer range is 1–0 and UNITY_REVERSED_Z is defined. On other platforms, the range is 0–1.
例如,以下着色器将渲染其游戏对象的深度:
Shader "Render Depth" {
SubShader {
Tags { "RenderType"="Opaque" }
Pass {
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f {
float4 pos : SV_POSITION;
float2 depth : TEXCOORD0;
};
v2f vert (appdata_base v) {
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
UNITY_TRANSFER_DEPTH(o.depth);
return o;
}
half4 frag(v2f i) : SV_Target {
UNITY_OUTPUT_DEPTH(i.depth);
}
ENDCG
}
}
}