unity3d内建着色器源码解析(一)

UnityShaderVariables.cginc文件中的着色器常量和函数

UnityShaderVariables.cginc文件中包含大量的工具宏和函数,如变换操作用的矩阵、与摄像机相关的函数、与光照和阴影相关的函数等。下面依次分析这些工具函数和宏。

进行变换操作用的矩阵

1. 判断USING_DIRECTIONAL_LIGHT宏是否定义并分析与立体渲染相关的宏

#ifndef UNITY_SHADER_VARIABLES_INCLUDED
#define UNITY_SHADER_VARIABLES_INCLUDED

#include "HLSLSupport.cginc"

#if defined (DIRECTIONAL_COOKIE) || defined (DIRECTIONAL)
#define USING_DIRECTIONAL_LIGHT
#endif

#if defined(UNITY_SINGLE_PASS_STEREO) || defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED)
#define USING_STEREO_MATRICES
#endif

在上述代码中,首先根据和单程立体渲染相关的预处理宏UNITY_SINGLE_PASS_STEREO、立体多例化渲染预处理宏UNITY_STEREO _INSTANCING_ENABLED、多视角立体渲染预处理宏UNITY_STERO_MULTIVIEW_ENABLED的启用情况决定宏USING_STERO_MATRICES表示立体渲染相关的矩阵是否开启。

立体多例化渲染的预处理宏UNITY_STEREO_INSTANCING_ENABLED是否启用,在HLSLSupport.cginc文件中有定义。这个宏根据另外的预处理宏决定是否启用。立体多例化技术核心思想是一次向渲染管道上提交两份待渲染的几何体数据,减少绘制调用的次数,提升渲染性能。

单程立体渲染是一种高效的支持VR渲染的方式,用于PC活着PlayStation4平台上的VR应用。这种技术同时把左右眼的数据打包进一张渲染纹理中,这也意味着整个场景只需渲染一次即可,否则就需要左右眼各渲染一次。此技术将大幅度的提升渲染性能。要使用单程立体渲染,选择Edit|Project Settings|Player选项,在PlayerSettings面板中选择Other Setting选项,选中Virtual Reality Supported复选框,然后选中Single-Pass Stereo Rendering复选框即可。设置完毕后,宏UNITY_SINGLE_PASS_STEREO将会被启用,如图4-1所示。

unity3d内建着色器源码解析(一)_第1张图片

2. 和立体渲染相关的一系列矩阵1
下面的代码用于定义一系列与立体渲染相关的矩阵。

#if defined(USING_STEREO_MATRICES)
    #define glstate_matrix_projection unity_StereoMatrixP[unity_StereoEyeIndex]
    #define unity_MatrixV unity_StereoMatrixV[unity_StereoEyeIndex]
    #define unity_MatrixInvV unity_StereoMatrixInvV[unity_StereoEyeIndex]
    #define unity_MatrixVP unity_StereoMatrixVP[unity_StereoEyeIndex]

    #define unity_CameraProjection unity_StereoCameraProjection[unity_StereoEyeIndex]
    #define unity_CameraInvProjection unity_StereoCameraInvProjection[unity_StereoEyeIndex]
    #define unity_WorldToCamera unity_StereoWorldToCamera[unity_StereoEyeIndex]
    #define unity_CameraToWorld unity_StereoCameraToWorld[unity_StereoEyeIndex]
    #define _WorldSpaceCameraPos unity_StereoWorldSpaceCameraPos[unity_StereoEyeIndex]
#endif

上面代码中,出现了unity_Stereo前缀命名的数组变量,用unity_前缀重新定义。unity_StereoEyeIndex代表左右边的索引。

3. 和立体渲染相关的一系列矩阵2
带有unity_Stereo前缀的变量和unity_StereoEyeIndex也定义在UnityShaderVariables.cginc文件中,如以下代码所示。

#if defined(USING_STEREO_MATRICES)
GLOBAL_CBUFFER_START(UnityStereoGlobals)
    float4x4 unity_StereoMatrixP[2];//每个眼睛的投影矩阵
    float4x4 unity_StereoMatrixV[2];//左、右眼的观察矩阵
    float4x4 unity_StereoMatrixInvV[2];//左、右眼的观察矩阵的逆矩阵
    float4x4 unity_StereoMatrixVP[2];//左、右眼的观察矩阵与投影矩阵的乘积

    float4x4 unity_StereoCameraProjection[2];//摄像机的投影矩阵
    float4x4 unity_StereoCameraInvProjection[2];//摄像机投影矩阵的逆矩阵
    float4x4 unity_StereoWorldToCamera[2];//世界空间到摄像机观察空间的矩阵
    float4x4 unity_StereoCameraToWorld[2];//摄像机观察空间到世界空间的矩阵

    float3 unity_StereoWorldSpaceCameraPos[2];//摄像机在世界空间中的坐标
    //进行单程立体渲染时,并不是像普通渲染一样将渲染结果写入颜色缓存中,而是写入两个Image中,再用如下的平铺偏移值来合并到一张可渲染纹理中
    float4 unity_StereoScaleOffset[2];
GLOBAL_CBUFFER_END
#endif

#if defined(USING_STEREO_MATRICES) && defined(UNITY_STEREO_MULTIVIEW_ENABLED)
GLOBAL_CBUFFER_START(UnityStereoEyeIndices)
    float4 unity_StereoEyeIndices[2];
GLOBAL_CBUFFER_END
#endif

#if defined(UNITY_STEREO_MULTIVIEW_ENABLED) && defined(SHADER_STAGE_VERTEX)
    #define unity_StereoEyeIndex UNITY_VIEWID
    UNITY_DECLARE_MULTIVIEW(2);
#elif defined(UNITY_STEREO_INSTANCING_ENABLED) || defined(UNITY_STEREO_MULTIVIEW_ENABLED)
    static uint unity_StereoEyeIndex;
#elif defined(UNITY_SINGLE_PASS_STEREO)
    GLOBAL_CBUFFER_START(UnityStereoEyeIndex)
        int unity_StereoEyeIndex;
    GLOBAL_CBUFFER_END
#endif

根据不同的编译条件,unity_StereoEyeIndex的定义方式也有所不同,如上面代码所示。此变量表征了当时使用的左右眼索引。

4. UNITY_DECLARE_MULTIVIEW宏的定义
代码中的UNITY_DECLARE_MULTIVIEW在HLSLSupport.cginc中定义:

// OVR_multiview
// In order to convey this info over the DX compiler, we wrap it into a cbuffer.
#define UNITY_DECLARE_MULTIVIEW(number_of_views) GLOBAL_CBUFFER_START(OVR_multiview) uint gl_ViewID; uint numViews_##number_of_views; GLOBAL_CBUFFER_END

5. 一系列用来进行变换操作的矩阵
在前面的代码段中,如果启用了unity_MatrixInvV等一系列变量,那就相当于使用了unity_StereoMatrixInvV[unity_StereoEyeIndex]等变量。

#define UNITY_MATRIX_P glstate_matrix_projection
#define UNITY_MATRIX_V unity_MatrixV
#define UNITY_MATRIX_I_V unity_MatrixInvV
#define UNITY_MATRIX_VP unity_MatrixVP
#define UNITY_MATRIX_M unity_ObjectToWorld

#define UNITY_MATRIX_MVP mul(unity_MatrixVP, unity_ObjectToWorld)
#define UNITY_MATRIX_MV mul(unity_MatrixV, unity_ObjectToWorld)
#define UNITY_MATRIX_T_MV transpose(UNITY_MATRIX_MV)
#define UNITY_MATRIX_IT_MV transpose(mul(unity_WorldToObject, unity_MatrixInvV))

#define UNITY_LIGHTMODEL_AMBIENT (glstate_lightmodel_ambient * 2)

6. 每一帧由客户端引擎传递进来的逐帧数据
如果没有启用,在HLSL/CG语言中,unity_MatrixV等变量就直接定义为float4x4类型的变量,如以下代码所示。

CBUFFER_START(UnityPerFrame)

    fixed4 glstate_lightmodel_ambient;
    fixed4 unity_AmbientSky;
    fixed4 unity_AmbientEquator;
    fixed4 unity_AmbientGround;
    fixed4 unity_IndirectSpecColor;

#if !defined(USING_STEREO_MATRICES)
    float4x4 glstate_matrix_projection;
    float4x4 unity_MatrixV;
    float4x4 unity_MatrixInvV;
    float4x4 unity_MatrixVP;
    int unity_StereoEyeIndex;
#endif

    fixed4 unity_ShadowColor;
CBUFFER_END

7. GLSL中各种变换操作作用的矩阵
如果使用GLSL,那么在GLSLSupport.cginc中定义的mat4类型的uniform变量,如下:

uniform mat4 unity_ObjectToWorld;
uniform mat4 unity_WorldToObject;
uniform mat4 unity_MatrixVP;
uniform mat4 unity_MatrixV;
uniform mat4 unity_MatrixInvV;
uniform mat4 glstate_matrix_projection;

在编码实践中,通常会单独使用UNITY_MATRIX_V的单独行来进行操作,如UNITY_MATRIX_V[0]等操作方式。UNITY_MATRIX_V[0]表示当前摄像机在世界坐标系下的朝右(right)方向向量,UNITY_MATRIX_V[1]表示在世界坐标系下的朝上(up)方向向量,UNITY_MATRIX_V[2]表示在世界坐标系下的朝前坐标方向。

和摄像机相关的常量缓冲区

1. 常量缓冲区UnityPerCamera的定义
通过以下代码定义常量缓冲区UnityPerCamera。

//定义一个constant buffer以存储shader变量,如下:
//CBUFFER_START(UnityPerCamera)
//    float4 _SomeGlobalValue;
//
//Unity3D内建的,用来传递给摄像机的参数组
//这些参数由引擎从C#层代码传递给着色器
CBUFFER_START(UnityPerCamera)
    // Time (t = time since current level load) values from Unity
    //从载入当前Scene开始算起流逝的时间值,单位是秒。
    float4 _Time; // (t/20, t, t*2, t*3)
    float4 _SinTime; // sin(t/8), sin(t/4), sin(t/2), sin(t)
    float4 _CosTime; // cos(t/8), cos(t/4), cos(t/2), cos(t)
    //本帧到上帧间隔时间
    float4 unity_DeltaTime; // dt, 1/dt, smoothdt, 1/smoothdt

#if !defined(USING_STEREO_MATRICES)//非立体渲染,引擎C#层传入摄像机在世界空间的坐标值
    float3 _WorldSpaceCameraPos;
#endif

    //投影矩阵相关参数
    // x = 1 or -1 (-1 if projection is flipped)
    // y = near plane
    // z = far plane
    // w = 1/far plane
    float4 _ProjectionParams;

    //视口相关参数,x视口宽度,y视口高度
    // x = width
    // y = height
    // z = 1 + 1.0/width
    // w = 1 + 1.0/height
    float4 _ScreenParams;

    //用来线性化Z buffer
    // Values used to linearize the Z buffer (http://www.humus.name/temp/Linearize%20depth.txt)
    // x = 1-far/near
    // y = far/near
    // z = x/far
    // w = y/far
    // or in case of a reversed depth buffer (UNITY_REVERSED_Z is 1)
    // x = -1+far/near
    // y = 1
    // z = x/far
    // w = 1/far
    float4 _ZBufferParams;

    // x = orthographic camera's width 正交投影摄像机宽度
    // y = orthographic camera's height 正交投影摄像机高度
    // z = unused 未使用
    // w = 1.0 if camera is ortho, 0.0 if perspective 1=正交投影 0=透视投影
    float4 unity_OrthoParams;
CBUFFER_END

2. 常量缓冲区UnityPerCameraRare的定义
通过以下代码定义常量缓冲区UnityPerCameraRare。

CBUFFER_START(UnityPerCameraRare)
    //当前摄像机的6个截平面的平面表达式。这些平面表达式在世界坐标系下描述。每个平面表达式用方程ax+by+cz+d=0表达。float4中的分量x、y、z、w依次存储了系数a、b、c、d。分别是左、右、下、上、近、远。
    float4 unity_CameraWorldClipPlanes[6];
    
    //如果不适用立体渲染,各种矩阵变量就是单变量而不是带两个变量的数组
#if !defined(USING_STEREO_MATRICES)
    // Projection matrices of the camera. Note that this might be different from projection matrix
    // that is set right now, e.g. while rendering shadows the matrices below are still the projection
    // of original camera.
    //当前摄像机的投影矩阵
    float4x4 unity_CameraProjection;
    //当前摄像机的投影逆矩阵
    float4x4 unity_CameraInvProjection;
    //当前摄像机的观察矩阵
    float4x4 unity_WorldToCamera;
    //当前摄像机的观察逆矩阵
    float4x4 unity_CameraToWorld;
#endif
CBUFFER_END

与光照相关的工具函数和内置光源

1. 变量_WorldSpaceLightPos0的定义

CBUFFER_START(UnityLighting)

    #ifdef USING_DIRECTIONAL_LIGHT //有向平行光
        //分量x、y、z存储的是有向平行光的方向向量
        half4 _WorldSpaceLightPos0;
    #else
        //x、y、z存储的是光源在世界空间的坐标
        float4 _WorldSpaceLightPos0;
    #endif

UnityCG.cginc和UnityCg.glslinc文件中的定义UnityWorldSpaceLightDir函数就使用了_WorldSpaceLightPos0变量,计算出某点到光源的连线方向向量。

2. 4个非重要点光源的位置、衰减值和照射范围

    float4 _LightPositionRange; // xyz = pos 光源位置, w = 1/range 光照射范围倒数
    //4个光源的x坐标、y坐标、z坐标、衰减值
    float4 unity_4LightPosX0;
    float4 unity_4LightPosY0;
    float4 unity_4LightPosZ0;
    half4 unity_4LightAtten0;

上面代码中定义的4个光源,是等级为非重要光源的点光源。这4个光源仅用在前向渲染途径的base pass中。

3. 8个光源的位置、颜色、衰减值和照射方向

    half4 unity_LightColor[8];//8个光源的颜色

    float4 unity_LightPosition[8]; // view-space vertex light positions (position,1), or (-direction,0) for directional lights.
    // x = cos(spotAngle/2) or -1 for non-spot 半张角余玄值
    // y = 1/cos(spotAngle/4) or 1 for non-spot 
    // z = quadratic attenuation 衰减值方程式的二次项系数
    // w = range*range 影响范围平方
    half4 unity_LightAtten[8];
    float4 unity_SpotDirection[8]; // view-space spot light directions, or (0,0,1,0) for non-spot

在UnityCG.cginc文件中的ShadeVertexLightsFull函数中使用了unity_LightAtten变量计算光照的衰减效果。

4. 球谐光照使用到的参数

    // SH lighting environment
    half4 unity_SHAr;
    half4 unity_SHAg;
    half4 unity_SHAb;
    half4 unity_SHBr;
    half4 unity_SHBg;
    half4 unity_SHBb;
    half4 unity_SHC;

5. 和光探针相关的参数

    // part of Light because it can be used outside of shadow distance
    fixed4 unity_OcclusionMaskSelector;
    fixed4 unity_ProbesOcclusion;
CBUFFER_END

与阴影相关的着色器常量缓冲区

UnityShadows着色器常量缓冲区

CBUFFER_START(UnityShadows)
    //用于构建层叠式阴影贴图时子视锥体用到的包围球
    float4 unity_ShadowSplitSpheres[4];
    //unity_ShadowSplitSpheres中4个包围球半径的平方
    float4 unity_ShadowSplitSqRadii;
    float4 unity_LightShadowBias;
    float4 _LightSplitsNear;
    float4 _LightSplitsFar;
    //把某个坐标从世界空间变换到阴影贴图空间,如果使用层叠式阴影贴图,就表示4个阴影贴图各自的阴影贴图空间
    float4x4 unity_WorldToShadow[4];
    half4 _LightShadowData;
    float4 unity_ShadowFadeCenterAndType;
CBUFFER_END

unity_ShadowSplitSpheres数组用于构建层叠式阴影贴图(cascaded shadow map, CSM)。目前只需了解,该数组的4个元素存储了把当前视截体(view frustum)分割成4个子视截体后,这些子视截体的包围球(bounding sphere)。每个元素中的x、y、z、w分量存储包围球的球心坐标和半径。在Internal-ScreenSpaceShadows.shader文件中的getCascadeWeights_splitSpheres函数中使用到了本数组。

unity_ShadowSplitSqRadii中的4个分量依次定义unity_ShadowSplitSpheres数组对应的4个包围球的半径的平方。

unity_LightShadowBias的分量为产生阴影的光源的光源偏移值乘以一个系数。这个光源偏移值对应于Light面板中的Bias属性,如图4-2所示。如果是聚光灯光源,所乘的系数为1;如果是有向平行光源,所乘系数为投影矩阵的第三行第三列的值的相反数。当光源是聚光灯时,y分量是0;当光源是有向平行光源时,为1。z分量为解决阴影渗漏问题时,沿着物体表面法线移动的偏移值。w分量为0。

_LightSplitsNear对应于Shadows面板中的cascade split属性里面,当把视截体分割成最多4个子视截体时,每个视截体的近平面的z值。

unity_WorldToShadow数组中的每一个元素对应于层叠式贴图中每一个视截体所对应的阴影贴图,存储了从世界坐标变换到阴影贴图空间中的变换坐标。这个阴影贴图空间即是在层叠式阴影贴图技术中,每一个子视截体所对应的阴影贴图所构建的空间。其可以近似的理解为一个由纹理映射坐标做成的空间坐标系,这个空间坐标系的坐标取值范围是[0,1]。显然这一系列的变换,应该是世界坐标上某一点依次乘以观察空间,再乘以投影矩阵后,变换到裁剪空间后,再乘以一个贴图变换矩阵,变换到阴影贴图空间。在裁剪空间中坐标的取值范围是[-1,1],所以这个贴图变换矩阵应该是变换后能把坐标限制在[0,1]范围内的矩阵。此矩阵的行优先形式如下。

0.5 0 0 0.5
0 0.5 0 0.5
0 0 0.5 0.5
0 0 0 1

顶点的坐标值依次乘以“世界矩阵”“观察矩阵”“投影矩阵”后,再乘以上面的矩阵(unity_WorldToShadow所表示的矩阵)。即将顶点变换到阴影贴图空间。需要注意的是,这里的构成观察矩阵的摄像机是光源摄像机。投影矩阵是一个正交投影矩阵,再渲染阴影时,需要把片元从当前空间的位置变换到阴影空间,去执行本片元是否再阴影之中的判断。unity_WorldToShadow数组中的第一个矩阵提供了这个功能。

_LightShadowData的x分量表示阴影的强度,即阴影有多黑,1表示全黑,0表示完全透明不黑;y分量目前暂未被使用;当z分量为阴影离当前摄像机的最远距离;w分量为最近距离。

_unity_ShadowFadeCenterAndType变量包含阴影的中心和阴影的类型。

与逐帧绘制调用相关的着色器常量缓冲区

Unity3D引擎预定义了和逐帧绘制调用相关的着色器常量UnityPerDraw,它定义在UnityShaderVariables.cginc文件。

CBUFFER_START(UnityPerDraw)
    float4x4 unity_ObjectToWorld;//把顶点从局部空间变换到世界空间
    float4x4 unity_WorldToObject;//把顶点从世界空间变换到局部空间
    float4 unity_LODFade; // x is the fade value ranging within [0,1]. y is x quantized into 16 levels
    float4 unity_WorldTransformParams; // w is usually 1.0, or -1.0 for odd-negative scale transforms
CBUFFER_END

与雾效相关的常量缓冲区

Unity3D引擎预定义了和雾效果渲染相关的着色器常量UnityFog,它定义在UnityShaderVariables.cginc文件。

CBUFFER_START(UnityFog)
    fixed4 unity_FogColor;
    // x = density / sqrt(ln(2)), useful for Exp2 mode
    // y = density / ln(2), useful for Exp mode
    // z = -1/(end-start), useful for Linear mode
    // w = end/(end-start), useful for Linear mode
    float4 unity_FogParams;
CBUFFER_END

雾化效果是一种可添加到最终渲染图像的简单大气效果。雾化效果可以提供室外场景的真实度;雾效效果随着距离观察者的距离变远而增加,可以帮助观察者确定物体的远近;靠近视截体远平面的物体就会因为浓厚的雾效变得不可见,这样可以避免原本在视截体之外的不可见物体,因为进入视截体就突然变的可见的现象(poping);雾化效果一般由硬件实现,所以很高效。

在上述代码段中的着色器常量缓冲区UnityFog里,unity_FogColor变量表示雾的颜色。如果某物体的表面颜色为Csrc,则经过雾化处理后显示的像素颜色Cdst可由下式定义:

Cdst = fCsrc + (1-f)unity_FogColor

式中,f为雾化因子(fog factor),它的取值范围是[0,1],随着待计算雾化效果的像素点离摄像机的距离值增加而衰减。

雾化因子随着距离的变化而衰减的方式有很多种,最常见的就是线性雾化因子(linear fog facotr)。假设Zstart和Zend分别表示沿着摄像机的观察方向,雾化效果的开始和终止位置(通常这两个位置会采用深度缓冲区的最大值和最小值)。Zp表示待计算雾化效果的像素,即离当前摄像机位置的距离值(一般根据裁剪空间的片元z值计算得到)。并且当像素离摄像机位置越远,取值就越大。UnityCG.cginc文件中的UNITY_Z_0_FRA_FROM_CLIPSPACE的宏就是用来把裁剪空间的z值计算成Zp值,线性雾化因子为

f = (Zend - Zp) / (Zend - Zstart)

除了线性雾化因子之外,还有雾化因子按指数方式衰减,如下式所示的指数雾化因子(exponential fog factor)

f = 1 / pow(e, Zp * density)

和指数平方雾化因子

f = 1 / pow(e, pow(Zp * density,2))

上面的density变量是用来控制雾化浓度的参数。当计算出雾化因子f后,将这个值clamp到[0,1]范围中,再结合式计算Cdst为雾化操作后的像素颜色。从上面几个式子可以看出,着色器常量缓冲区UnityFog的unity_FogParams变量中的x、y、z、w存储了计算雾化因子的参数的运算组合。一些工具函数和工具宏将会用这4个分量去计算不同的雾化效果。

与光照贴图相关的常量缓冲区

1. unity_Lightmap变量的声明

// Main lightmap
UNITY_DECLARE_TEX2D_HALF(unity_Lightmap);
// Directional lightmap (always used with unity_Lightmap, so can share sampler)
UNITY_DECLARE_TEX2D_NOSAMPLER_HALF(unity_LightmapInd);

2. UNITY_DECLARE_TEX2D_NOSAMPLER宏的定义
UNITY_DECLARE_TEX2D_NOSAMPLER宏在HLSLSupport.cginc中定义,依据不同的目标平台,它的定义也不同,如以下代码所示。

#if defined(SHADER_API_D3D11) || defined(SHADER_API_XBOXONE) || defined(UNITY_COMPILER_HLSLCC) || defined(SHADER_API_PSSL)
    #define UNITY_DECLARE_TEX2D_NOSAMPLER(tex) Texture2D tex
#else
    #define UNITY_DECLARE_TEX2D_NOSAMPLER(tex) sampler2D tex
#endif

3. unity_ShadowMask变量的定义

// Combined light masks
#if defined (SHADOWS_SHADOWMASK)
    #if defined(LIGHTMAP_ON)
        //Can share sampler if lightmap are used.
        UNITY_DECLARE_TEX2D_NOSAMPLER(unity_ShadowMask);
    #else
        UNITY_DECLARE_TEX2D(unity_ShadowMask);
    #endif
#endif

上述代码很简单,其实就是根据不同平台,使用该平台能使用的指令定义一个普通的2D纹理。回到SHADOWS_SHADOWMASK宏的定义中,如果没有声明同时启用LIGHTMAP_ON,即不启用光照贴图,则使用UNITY_DECLARE_TEX2D宏直接定义一个名为unity_ShadowMask的纹理贴图,同时定义一个名为samplerunity_ShadowMask的samplerState。

4. 和全局照明光照贴图贴图相关的变量

// Dynamic GI lightmap
UNITY_DECLARE_TEX2D(unity_DynamicLightmap);
UNITY_DECLARE_TEX2D_NOSAMPLER(unity_DynamicDirectionality);
UNITY_DECLARE_TEX2D_NOSAMPLER(unity_DynamicNormal);

CBUFFER_START(UnityLightmaps)
    //对应于静态光照贴图变量unity_Lightmap,用于tiling和offset操作
    float4 unity_LightmapST;
    //对应于动态光照贴图变量unity_DynamicLightmap,用于tiling和offset操作
    float4 unity_DynamicLightmapST;
CBUFFER_END

5. 与反射用光探针相关的着色器变量

// Reflection Probes
UNITY_DECLARE_TEXCUBE(unity_SpecCube0);
UNITY_DECLARE_TEXCUBE_NOSAMPLER(unity_SpecCube1);

CBUFFER_START(UnityReflectionProbes)
    //反射用光探针的作用区域立方体是一个和世界坐标系坐标轴轴对齐包围盒
    //它的值由反射用光探针的Box Size属性和Box offset属性计算而来
    float4 unity_SpecCube0_BoxMax;//包围盒在x、y、z轴方向上的最大边界值
    float4 unity_SpecCube0_BoxMin;//包围盒在x、y、z轴方向上的最小边界值
    //对应于ReflectionProbe组件中的光探针位置,它由Transform组件的Position属性和Box Offset属性计算而来
    float4 unity_SpecCube0_ProbePosition;
    //反射用光探针使用的立方体贴图中包含高动态范围颜色,这允许它包含大于1的亮度值
    half4  unity_SpecCube0_HDR;

    float4 unity_SpecCube1_BoxMax;
    float4 unity_SpecCube1_BoxMin;
    float4 unity_SpecCube1_ProbePosition;
    half4  unity_SpecCube1_HDR;
CBUFFER_END

UNITY_DECLARE_TEXCUBE宏在HLSLSupport.cginc文件中定义,用来声明一个立方体贴图变量。并且如果当前是运行在Direct3D 11活着XBoxOne平台上,此宏还对应立方体贴图变量声明一个采样器变量。而UNITY_DECLARE_TEXCUBE_NOSAMPLER宏则是一个不声明采样器变量的版本。

6. 立方体贴图的声明变量、对纹理采样等相关的宏

UNITY_SAMPLE_TEXCUBE_LOD宏对立方体纹理贴图根据当前的mipmap层级进行采样。

    // Cubemaps
    #define UNITY_DECLARE_TEXCUBE(tex) samplerCUBE tex
    #define UNITY_ARGS_TEXCUBE(tex) samplerCUBE tex
    #define UNITY_PASS_TEXCUBE(tex) tex
    #define UNITY_PASS_TEXCUBE_SAMPLER(tex,samplertex) tex
    #define UNITY_DECLARE_TEXCUBE_NOSAMPLER(tex) samplerCUBE tex
    #define UNITY_SAMPLE_TEXCUBE(tex,coord) texCUBE (tex,coord)

    // DX9 with SM2.0, and DX11 FL 9.x do not have texture LOD sampling.
    // We will approximate that with mip bias (very poor approximation, but not much we can do)
    #if ((SHADER_TARGET < 25) && defined(SHADER_API_D3D9)) || defined(SHADER_API_D3D11_9X)
    #   define UNITY_SAMPLE_TEXCUBE_LOD(tex,coord,lod) texCUBEbias(tex, half4(coord, lod))
    #   define UNITY_SAMPLE_TEXCUBE_SAMPLER_LOD(tex,samplertex,coord,lod) UNITY_SAMPLE_TEXCUBE_LOD(tex,coord,lod)
    #else
    #   define UNITY_SAMPLE_TEXCUBE_LOD(tex,coord,lod) texCUBElod (tex, half4(coord, lod))
    #   define UNITY_SAMPLE_TEXCUBE_SAMPLER_LOD(tex,samplertex,coord,lod) UNITY_SAMPLE_TEXCUBE_LOD(tex,coord,lod)
    #endif
    #define UNITY_SAMPLE_TEXCUBE_SAMPLER(tex,samplertex,coord) texCUBE (tex,coord)

Unity3D使用这两个宏声明了两个反射用光探针所使用的立方体贴图变量(及采样器):unity_SpecCube0和unity_SpecCube1。同时还声明了着色器常量缓冲区UnityReflectionProbes,里面包含了对应于反射用光探针的若干属性。

你可能感兴趣的:(unity3d内建着色器源码解析(一))