【节点】[Truncate节点]原理解析与实际应用
Unity URP ShaderGraph中的Truncate节点是处理浮点数截断操作的核心工具,它通过移除小数部分保留整数来实现向零取整。该节点支持多维数据输入(float至float4),在着色器编程中广泛应用于棋盘格、像素化等效果。与Floor、Ceiling等取整函数不同,Truncate直接舍弃小数部分(如2.8→2.0,-2.8→-2.0)。节点生成的HLSL代码调用内置trunc函数
在Unity URP Shader Graph中,Truncate节点是一个功能强大且实用的数学运算节点,专门用于处理浮点数的截断操作。这个节点在着色器编程中扮演着重要角色,特别是在需要将连续值转换为离散值的场景中。Truncate节点的核心功能是移除浮点数的小数部分,仅保留整数部分,这种操作在图形渲染中有着广泛的应用。
Truncate节点的工作原理基于数学中的截断函数概念,它不同于四舍五入,而是直接舍弃小数部分,无论小数部分的大小如何。例如,对于数值3.9,Truncate操作后得到的是3而不是4,这与Floor函数在正数范围内的行为相似,但在负数范围内有所不同。
在Shader Graph中,Truncate节点属于数学节点类别,可以处理各种精度和维度的数据,从简单的浮点数到复杂的矢量数据。它的灵活性和高效性使其成为着色器开发中不可或缺的工具之一。
描述
Truncate节点的核心功能是截取输入值的整数部分,完全舍弃小数部分。这一操作在数学上称为向零取整,意味着无论输入值是正数还是负数,都会朝着零的方向进行截断。例如,输入值2.8经过Truncate操作后得到2.0,而输入值-2.8则得到-2.0。
与其它取整函数相比,Truncate有着独特的行为特征:
- 与Floor函数的区别:Floor函数总是向下取整,对于负数,Floor(-2.8) = -3,而Truncate(-2.8) = -2
- 与Ceiling函数的区别:Ceiling函数总是向上取整,对于正数,Ceiling(2.2) = 3,而Truncate(2.2) = 2
- 与Round函数的区别:Round函数进行四舍五入,Round(2.8) = 3,而Truncate(2.8) = 2
在着色器编程中,Truncate节点的应用场景非常广泛。它可以用于创建棋盘格图案、实现像素化效果、处理UV坐标、创建离散颜色分级等。由于着色器通常需要处理大量的数学运算,Truncate节点的高效性使其成为优化性能的重要工具。
Truncate节点支持动态矢量输入,这意味着它可以处理各种维度的数据,包括:
- 单精度浮点数(float)
- 二维矢量(float2)
- 三维矢量(float3)
- 四维矢量(float4)
这种灵活性使得Truncate节点可以同时处理多个通道的数据,大大提高了着色器编写的效率。
端口

Truncate节点的端口设计简洁而强大,遵循了Shader Graph节点设计的一致性原则。了解每个端口的特性和用法对于正确使用该节点至关重要。
输入端口
输入端口名为"In",是Truncate节点接收数据的入口。这个端口具有以下特点:
- 方向:输入
- 类型:动态矢量
- 绑定:无强制绑定,可以连接任何产生数值的节点
- 数据范围:支持任意浮点数范围,包括正数、负数和零
动态矢量类型意味着输入端口可以自适应地接受不同维度的数据。当连接一个标量值时,它作为单通道数据处理;当连接一个矢量时,它会并行处理所有通道。这种设计极大地增强了节点的灵活性和复用性。
输入数据的精度取决于前驱节点的输出精度,Truncate节点会保持相同的精度进行处理。在大多数现代图形API中,浮点数运算遵循IEEE 754标准,确保跨平台的一致性。
输出端口
输出端口名为"Out",是Truncate节点处理结果的出口。这个端口具有以下特征:
- 方向:输出
- 类型:动态矢量
- 数据特性:输出值的整数部分,小数部分完全归零
输出端口的维度始终与输入端口保持一致。如果输入是float3类型,输出也会是float3类型,每个分量都独立进行了截断操作。这种逐分量处理的方式是Shader Graph中数学节点的标准行为。
输出值的数据范围取决于输入值的范围,但小数部分始终为零。例如:
- 输入(1.2, 2.7, -3.8, 4.0) → 输出(1.0, 2.0, -3.0, 4.0)
- 输入(0.1, -0.9, 1.5, -2.4) → 输出(0.0, 0.0, 1.0, -2.0)
端口连接实践
在实际使用中,Truncate节点的端口连接非常灵活。以下是一些常见的连接示例:
- 连接Time节点:可以创建基于时间的离散动画效果
- 连接UV坐标:可以实现网格化或像素化效果
- 连接位置数据:可以创建对齐到网格的物体运动
- 连接颜色数据:可以实现颜色量化效果
端口连接的兼容性是Shader Graph的一个重要特性。Truncate节点可以无缝地与其它数学节点、纹理节点、输入节点等连接,形成复杂的数据处理流水线。
生成的代码示例
Truncate节点在背后生成的HLSL代码体现了其高效和简洁的设计理念。通过理解生成的代码,可以更深入地掌握节点的运作机制和优化可能性。
基础代码结构
Truncate节点生成的核心代码通常遵循以下模式:
HLSL
void Unity_Truncate_float4(float4 In, out float4 Out)
{
Out = trunc(In);
}
这段代码展示了一个处理float4类型数据的Truncate函数实现。函数接受一个float4输入参数In,并通过输出参数Out返回结果。在函数体内,调用了HLSL内置的trunc函数来完成实际的截断操作。
不同数据类型的处理
根据输入数据的维度不同,Shader Graph会生成相应版本的函数:
单精度浮点数处理:
HLSL
void Unity_Truncate_float(float In, out float Out)
{
Out = trunc(In);
}
二维矢量处理:
HLSL
void Unity_Truncate_float2(float2 In, out float2 Out)
{
Out = trunc(In);
}
三维矢量处理:
HLSL
void Unity_Truncate_float3(float3 In, out float3 Out)
{
Out = trunc(In);
}
这种多态性的实现使得同一节点可以处理不同类型的数据,大大提高了代码的复用性和可维护性。
底层实现原理
在HLSL中,trunc函数是内置的数学函数,其实现通常基于硬件的浮点数处理能力。从数学角度看,trunc函数的定义可以表示为:
trunc(x) = sign(x) × floor(abs(x))
其中sign(x)返回x的符号,floor(x)返回不大于x的最大整数,abs(x)返回x的绝对值。
在实际的GPU执行中,trunc操作通常非常高效,因为现代GPU都有专门的硬件单元来处理这类数学运算。大多数情况下,trunc操作可以在一个时钟周期内完成。
性能优化考虑
理解生成的代码有助于进行性能优化:
- 向量化处理:当处理多个标量时,尽量使用适当维度的矢量一次处理,而不是多次调用标量版本
- 精度控制:在不需要高精度的场合,可以考虑使用half或fixed精度类型
- 指令优化:trunc操作通常比除法或乘法操作更加高效,在适当场合可以替代复杂的数学运算
自定义扩展
基于生成的代码模式,开发者可以创建自定义的变体函数来满足特殊需求。例如,可以创建一个带有多重截断级别的函数:
HLSL
void Unity_TruncateMultiple_float(float In, float Level, out float Out)
{
Out = trunc(In * Level) / Level;
}
这种扩展允许在更细的粒度上控制截断行为,比如创建0.5单位的截断网格。
平台兼容性
生成的trunc函数在大多数现代图形API中都有良好的支持,包括:
- DirectX 9及以上版本
- OpenGL ES 2.0及以上版本
- Metal
- Vulkan
在不同平台上,编译器可能会对trunc函数进行不同的优化,但功能行为保持一致。这种跨平台的一致性是通过HLSL到各个目标平台着色语言的转换层来实现的。
【Unity Shader Graph 使用与特效实现】专栏-直达
(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)
这里是一个专注于游戏开发的社区,我们致力于为广大游戏爱好者提供一个良好的学习和交流平台。我们的专区包含了各大流行引擎的技术博文,涵盖了从入门到进阶的各个阶段,无论你是初学者还是资深开发者,都能在这里找到适合自己的内容。除此之外,我们还会不定期举办游戏开发相关的活动,让大家更好地交流互动。加入我们,一起探索游戏开发的奥秘吧!
更多推荐



所有评论(0)