【UnityShader预备知识】内置变量和函数

本文详细介绍了Unity引擎中常用的预处理器指令,如模型视图投影矩阵、时间变量、摄像机参数和光照贴图,以及它们在HLSL程序中的应用场景和作用,帮助开发者理解和运用这些资源来实现3D图形和动画效果。
摘要由CSDN通过智能技术生成

一、转换

名称
UNITY_MATRIX_MVP当前模型 * 视图 * 投影矩阵。
UNITY_MATRIX_MV当前模型 * 视图矩阵。
UNITY_MATRIX_V当前视图矩阵。
UNITY_MATRIX_P当前投影矩阵。
UNITY_MATRIX_VP当前视图 * 投影矩阵。
UNITY_MATRIX_T_MV模型转置 * 视图矩阵。
UNITY_MATRIX_IT_MV模型逆转置 * 视图矩阵。
unity_ObjectToWorld当前模型矩阵。
unity_WorldToObject当前世界矩阵的逆矩阵。

Unity引擎中使用的预处理器指令,用于在HLSL程序中获取常用的矩阵和向量(float4x4,以列为主序),以便于进行数学运算和变换操作,具体如下:

UNITY_MATRIX_MVP:表示当前模型视图投影矩阵,也就是将模型变换到屏幕空间的矩阵,用于计算最终像素的位置和深度等信息。
UNITY_MATRIX_MV:表示当前模型*视图矩阵,用于计算模型在视图空间中的位置和方向等信息。
UNITY_MATRIX_V:表示当前视图矩阵,用于将模型从世界空间转换到视图空间。
UNITY_MATRIX_P:表示当前投影矩阵,用于将视图空间中的坐标转换成NDC(Normalized Device Coordinates)。
UNITY_MATRIX_VP:表示当前视图*投影矩阵,用于将模型从世界空间转换到屏幕空间。
UNITY_MATRIX_T_MV:表示模型转置*视图矩阵,用于计算模型在视图空间中的法线向量。
UNITY_MATRIX_IT_MV:表示模型逆转置*视图矩阵,用于计算模型在视图空间中的反法线向量。
unity_ObjectToWorld:表示当前模型矩阵,用于将模型从局部空间转换到世界空间。
unity_WorldToObject:表示当前世界矩阵的逆矩阵,用于将模型从世界空间转换到局部空间。

这些宏定义通常在HLSL程序的前几行声明,以便于在后续的代码中直接调用。它们可以通过#define指令进行定义,也可以在Unity编辑器中通过Properties属性进行定义。在使用这些宏定义时,需要注意它们的数据类型和作用域,以确保正确地使用它们进行数学运算和变换操作。

二、时间

名称类型
_Timefloat4
_SinTimefloat4
_CosTimefloat4
unity_DeltaTimefloat4

这些变量是用于获取时间和相关的时间变化信息,以便于在HLSL程序中进行动画和动态效果的实现。下面是对每个变量的简要介绍:

  • _Time:表示自关卡加载以来的时间,是一个四元数,包含了四个不同的时间值,分别为t/20tt*2t*3,可以用于创建不同频率的动画效果。
  • _SinTime:表示时间的正弦值,也是一个四元组,包含了四个不同的正弦波形,分别为t/8t/4t/2t,可以用于创建周期性的动画效果。
  • _CosTime:表示时间的余弦值,也是一个四元组,包含了四个不同的余弦波形,分别为t/8t/4t/2t,可以用于创建周期性的动画效果。
  • unity_DeltaTime:表示增量时间,是一个浮点数,表示上一帧和当前帧之间的时间差,可用于计算动画和物理等效果的速度和加速度。

这些变量可以在HLSL程序中使用,但是需要注意它们的数据类型和作用域,以及如何与其他变量结合使用,以实现所需的效果。例如,可以使用_Time变量来控制动画的播放速度,或者使用_CosTime和_SinTime来创建周期性的波动效果。而unity_DeltaTime则可以用于计算动画的速度和加速度,或者实现基于时间的动画。

三、相机

名称类型
_WorldSpaceCameraPosfloat3摄像机的世界空间位置。
_ProjectionParamsfloat4x 是 1.0(如果当前使用翻转投影矩阵进行渲染,则为 –1.0),y 是摄像机的近平面,z 是摄像机的远平面,w 是远平面的倒数。
_ScreenParamsfloat4x 是摄像机目标纹理的宽度(以像素为单位),y 是摄像机目标纹理的高度(以像素为单位),z 是 1.0 + 1.0/宽度,w 为 1.0 + 1.0/高度。
_ZBufferParamsfloat4用于线性化 Z 缓冲区值。x 是 (1-远/近),y 是 (远/近),z 是 (x/远),w 是 (y/远)。
unity_OrthoParamsfloat4x 是正交摄像机的宽度,y 是正交摄像机的高度,z 未使用,w 在摄像机为正交模式时是 1.0,而在摄像机为透视模式时是 0.0。
unity_CameraProjectionfloat4x4摄像机的投影矩阵。
unity_CameraInvProjectionfloat4x4摄像机投影矩阵的逆矩阵。
unity_CameraWorldClipPlanes[6]float4摄像机视锥体平面世界空间方程,按以下顺序:左、右、底、顶、近、远。

这些变量也是在Unity引擎中使用的预处理器指令,用于获取与摄像机相关的参数和矩阵,以便于在HLSL程序中进行数学运算和变换操作。下面是对每个变量的简要介绍:

  • _WorldSpaceCameraPos:表示摄像机的世界空间位置,是一个三维向量,通常用于计算光照和阴影等效果。
  • _ProjectionParams:表示当前摄像机的投影参数,其中x表示是否使用翻转投影矩阵,y和z分别表示近平面和远平面的距离,w表示远平面的倒数,用于计算Z缓冲区值。
  • _ScreenParams:表示当前摄像机的目标纹理大小和比例,x表示宽度,y表示高度,z和w表示屏幕比例,用于计算屏幕空间坐标系下的纹理坐标。
  • _ZBufferParams:表示用于线性化Z缓冲区值的参数,用于计算深度值。
  • unity_OrthoParams:表示当前摄像机的正交参数,x和y表示正交窗口的宽高比,z未使用,w表示是否为正交模式。
  • unity_CameraProjection:表示当前摄像机的投影矩阵,用于将视图空间中的坐标转换成NDC。
  • unity_CameraInvProjection:表示当前摄像机的逆投影矩阵,用于将NDC转换回视图空间坐标。
  • unity_CameraWorldClipPlanes:表示摄像机视锥体平面的世界空间方程,包括左、右、底、顶、近、远六个平面,用于计算视锥体裁剪。

这些变量同样可以在HLSL程序中使用,但需要注意它们的用途和数据类型,以确保正确地使用它们进行数学运算和变换操作。例如,在计算光照和阴影时,可以使用_WorldSpaceCameraPos来获取摄像机位置,而计算深度值时则需要用到_ZBufferParams等变量。

四、光照贴图

unity_LightmapTexture2D包含光照贴图信息。
unity_LightmapSTfloat4[8]缩放 UV 信息并转换到正确的范围以对光照贴图纹理进行采样。

unity_Lightmap 和 unity_LightmapST 是Unity引擎提供的内置变量,专门用于实时光照贴图烘焙效果。在Unity中,当场景中的物体被烘焙以使用预先计算的光照信息时,这些变量会被使用。

  • unity_Lightmap 是一个Texture2D类型的变量,存储了场景中物体表面的光照信息。这张贴图包含了静态光源照射到物体上的光照强度和颜色,可以用来模拟静态光照效果。

  • unity_LightmapST 是一个数组,包含8个float4类型的元素,每个性质代表不同的UV坐标的缩放和平移参数。这些参数用于调整unity_Lightmap贴图的UV坐标,使得其能够适配到物体表面上的不同区域。具体来说,每个float4变量包含四个分量,分别是S和T的缩放因子以及偏移量,用于映射到对应的UV坐标上。这样可以确保光照贴图正确地覆盖在物体表面上,即使物体的形状发生了改变(如移动、旋转或缩放)。

在编写涉及实时光照烘焙的着色器时,可以利用这些变量来读取光照贴图信息,并根据材质属性和光照情况进行相应的计算,从而得出最终的颜色输出。通常情况下,这些变量不需要程序员手动设置,Unity会在编译着色器时自动填充这些值。开发者只需要在片元着色器中正确地采样unity_Lightmap纹理即可获得所需的光照信息。例如:

// 定义了两个变量,用于访问光照贴图和光照贴图的缩放和偏移
uniform sampler2D unity_Lightmap; // 光照贴图的采样器
uniform float4 unity_LightmapST; // 光照贴图的缩放和偏移量

然后在片元着色器中,可以按照这样的方式使用它们来获取光照信息:

// 使用给定的UV坐标从光照贴图中采样颜色
fixed4 LightingUnlit_DirLightmap(SurfaceOutput s, fixed3 lightDir, fixed atten)
{
    // 计算光照贴图的UV坐标
    // 这里假设使用了unity_LightmapST[0]作为缩放和偏移
    // 如果有多个光照贴图层,可能需要使用不同的ST值
    float2 uv = s.uv.xy * unity_LightmapST[0].xy + unity_LightmapST[0].zw;
    
    // 从光照贴图中采样颜色
    fixed4 lm = tex2D(unity_Lightmap, uv);
    
    // 将采样的颜色应用到最终的颜色上
    // 这里假设使用了简单的乘法来混合原始颜色和光照贴图颜色
    fixed4 c = s.Albedo * lm;
    
    // 返回最终的颜色
    return c;
}

需要注意的是,这些变量只适用于实时光照烘焙的场景,而且只有在使用Unity的实时光照系统时才会被填充。对于动态光源或其他非烘焙光源,需要使用其他的变量和方法来获取光照信息。此外,由于这些变量是Unity引擎内部管理的,因此在编写自己的着色器时应该检查它们是否可用,并根据具体情况做出适当的处理。

五、几个示例

示例一:UNITY_MATRIX_MVP

UNITY_MATRIX_MVP 是Unity引擎中定义的一个全局常量,它代表了模型(Model)、视图(View)、投影(Project)三者组合而成的矩阵,即 MVP 矩阵。这个矩阵用于将模型的空间位置、朝向和缩放等信息转化为在屏幕上的二维投影坐标。在图形编程和游戏开发领域,MVP 矩阵广泛应用于将三维对象绘制到二维平面上,它是将三维模型的顶点数据从模型空间转换到屏幕空间的关键步骤之一。

在 Unity 中,MVP 矩阵是由三个矩阵相乘得到的:

// 定义了当前模型、视图和投影矩阵的宏
#define UNITY_MATRIX_MVP (unity_Matrix_MVP * _Object2World)

这里的 _Object2World 变量是一个模型到世界空间的变换矩阵,unity_Matrix_MVP 是视图和投影矩阵的组合。当你想把模型的顶点数据转换到屏幕空间时,你需要使用这个矩阵来进行变换。例如,在顶点着色器中,你可能会这样做:

// 使用UNITY_MATRIX_MVP来计算最终的MVP矩阵
void vert(inout appdata_full v)
{
    // 计算顶点在世界空间的位置
    float4 worldPosition = mul(_Object2World, v.vertex);
    // 计算顶点在屏幕空间的位置
    float4 screenPosition = mul(UNITY_MATRIX_MVP, v.vertex);
    // ...
}

在这个例子中,我们首先将顶点从模型空间转换到世界空间,然后再次使用UNITY_MATRIX_MVP将其转换到屏幕空间。这是因为在Unity中,顶点数据是以模型空间的形式给出的,所以我们首先需要将其转换到世界空间,然后再转换到屏幕空间。

示例二:_Time

_Time 是Unity引擎提供的一种特殊变量,用于在着色器中获取时间信息。它的值是一个四元组(float4),包含四个不同的时间尺度,具体如下:

  • x轴:自关卡加载以来经过的时间,除以20,即t/20
  • y轴:自关卡加载以来经过的时间t
  • z轴:自关卡加载以来经过的时间的两倍t*2
  • w轴:自关卡加载以来经过的时间的三倍t*3

这四种时间尺度可以让你在着色器中实现各种各样的动画效果,比如随时间变化的颜色变化、位移等等。例如,你可以用t/20来实现缓慢的变化,用t*2来实现快速的变化。这种变量通常用于制作粒子效果、流动效果或者其他需要随时间变化的效果。

例如,如果你想让一个物体沿着某个方向移动,你可以使用_Time.y来计算它的位移:

// 使用_Time全局变量来创建动画效果
void vert(inout appdata_full v)
{
    // 假设我们想要根据时间的不同阶段来改变顶点的位置
    // _Time.x 是自关卡加载以来的总时间
    // _Time.y 是自关卡加载以来的时间(通常与帧率同步)
    // 我们可以根据_Time的不同分量来创建复杂的动画序列
    
    // 例如,我们可以让某些顶点沿X轴移动,而其他顶点沿Y轴移动
    // 这里我们创建一个简单的波动效果
    float wave = sin(_Time.x * 10.0) * 0.1; // 正弦波动,振幅为0.1
    v.vertex.x += wave; // 沿X轴移动
    
    // 如果我们想要在Y轴上也有波动,可以这样做:
    float waveY = cos(_Time.y * 15.0) * 0.2; // 余弦波动,振幅为0.2
    v.vertex.y += waveY; // 沿Y轴移动
    
    // 如果我们想要根据时间的不同阶段来改变顶点的颜色,可以这样做:
    // 这里我们根据_Time.y的不同阶段来改变顶点的颜色
    if (_Time.y < 5.0) {
        // 如果时间小于5秒,顶点颜色设置为红色
        v.color = float4(1.0, 0.0, 0.0, 1.0);
    } else if (_Time.y < 10.0) {
        // 如果时间在5秒到10秒之间,顶点颜色设置为绿色
        v.color = float4(0.0, 1.0, 0.0, 1.0);
    } else {
        // 如果时间超过10秒,顶点颜色设置为蓝色
        v.color = float4(0.0, 0.0, 1.0, 1.0);
    }
    
    // 应用变换
    v.vertex = mul(_Object2World, v.vertex);
    v.normal = normalize(mul(_Object2World, v.normal));
}

注意,这里只是示例代码,实际使用时需要根据你的需求进行修改和调整。

  • 26
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值