【节点】[RoundedPolygon节点]原理解析与实际应用

【Unity Shader Graph 使用与特效实现】专栏-直达

Rounded Polygon 节点是Unity URP Shader Graph中一个功能强大的形状生成工具,专门用于创建具有圆角效果的多边形形状。这个节点在游戏开发中有着广泛的应用,特别是在UI设计、特效制作和风格化渲染等领域。通过灵活调整参数,开发者可以创建从简单的圆角矩形到复杂的星形图案等各种几何形状。

该节点的核心价值在于它能够生成平滑的圆角过渡,这在现代UI设计和视觉效果中尤为重要。与传统的锐角多边形相比,圆角多边形在视觉上更加柔和友好,能够减少尖锐角度带来的视觉冲击,提升用户体验。在移动设备UI、游戏HUD界面和各类图标设计中,圆角设计已经成为主流趋势。

从技术实现角度来看,Rounded Polygon 节点生成的是基于距离场的形状表示,这意味着它能够提供高质量的边缘抗锯齿效果,并且在不同分辨率下都能保持清晰的边缘质量。这种实现方式使得生成的形状非常适合用于遮罩、轮廓描边和各种形状组合操作。

描述

Rounded Polygon 节点的主要功能是基于输入的UV坐标生成圆角多边形形状。该形状的大小由宽度(Width)和高度(Height)两个参数精确控制,允许用户创建各种比例的长方形、正方形或其他矩形变体。通过调整边数(Sides)参数,用户可以定义多边形的基本结构,从三角形(3边)到圆形(理论上无限多边)之间的任意正多边形。

圆度(Roundness)参数是该节点的特色功能,它定义了多边形每个角的圆滑程度。当Roundness值为0时,多边形将保持原始的锐角状态;随着值的增加,角部会逐渐变得圆滑;当值接近1时,多边形将趋近于圆形或椭圆形,具体取决于宽度和高度的比例关系。

在实际使用中,该节点通常与其他节点配合使用以增强其功能。例如,通过连接Tiling And Offset节点,用户可以轻松地对生成的形状进行偏移或平铺操作,创建重复的图案效果。需要注意的是,为了保持形状在UV空间中偏移的能力,节点在设计时没有内置自动重复功能。如果用户需要创建重复的点状图案,建议先通过Fraction节点处理UV输入,然后再连接到Rounded Polygon节点。

从着色器阶段的角度来看,此节点仅限于片段着色器阶段使用,这意味着它主要在像素级别进行计算和渲染。这种限制确保了形状生成的精度和视觉效果的质量,但同时也意味着它不能直接用于顶点着色器阶段的几何变形操作。

技术原理深度解析

Rounded Polygon 节点的内部实现基于复杂的数学计算,主要包括极坐标变换、角度分割和圆弧插值等技术。节点首先将输入的UV坐标从标准的0,1范围转换到-1,1的对称空间,然后根据宽度和高度参数进行适当的缩放,确保形状能够正确适应指定的尺寸。

多边形边数的处理涉及到底层的三角函数计算。节点通过将360度圆周等分来创建正多边形的边,每个边对应一个特定的角度区间。圆角的实现则更加复杂,它需要在多边形的每个角点处计算一个圆弧过渡,这个圆弧的半径由Roundness参数控制,半径越大,圆角效果越明显。

距离场技术是该节点的核心技术之一。节点输出的实际上是一个有符号距离场(SDF)值,表示每个像素到形状边界的距离。正值表示像素在形状内部,负值表示在形状外部,零值恰好位于边界上。这种表示方法使得形状的边缘可以通过fwidth函数进行高质量的抗锯齿处理,最终通过saturate函数将距离场转换为标准的0,1遮罩值。

端口

Rounded Polygon 节点提供了五个输入端口和一个输出端口,每个端口都有特定的功能和数据类型要求。理解这些端口的作用对于正确使用该节点至关重要。

UV输入端口

UV输入端口接收Vector2类型的坐标数据,通常绑定到着色器的UV通道。这个端口决定了形状在纹理空间中的位置和分布。用户可以直接使用模型的原始UV坐标,也可以通过其他节点(如Tiling And Offset、Rotate等)对UV进行变换,从而实现形状的平移、旋转、缩放等效果。

在实际应用中,UV输入端口的灵活性使得用户可以创建复杂的图案组合。例如,通过将Time节点连接到UV的偏移,可以实现形状的动画效果;通过使用不同的UV通道,可以在同一材质中创建多个独立的形状层。

Width和Height输入端口

Width和Height输入端口均接受Float类型的数值,分别控制生成形状的宽度和高度。这两个参数共同决定了形状的基本比例和尺寸。当Width和Height值相等时,形状在各个方向上对称;当值不相等时,形状会相应地拉伸或压缩。

  • Width控制形状在水平方向(U轴)的尺寸
  • Height控制形状在垂直方向(V轴)的尺寸
  • 两个参数都支持动态调整,可以通过其他节点驱动
  • 当参数值为0时,节点内部会使用一个极小的epsilon值避免除零错误

Sides输入端口

Sides输入端口接受Float类型的数值,用于指定多边形的边数。这个参数决定了形状的基本几何结构:

  • 当Sides=3时,生成圆角三角形
  • 当Sides=4时,生成圆角矩形或正方形
  • 当Sides=5时,生成圆角五边形
  • 当Sides=6时,生成圆角六边形
  • 当Sides值较大时(如Sides≥8),形状趋近于圆形

需要注意的是,Sides参数理论上支持任意正整数值,但实际使用中通常设置在3到8之间,因为边数过多时视觉上难以与圆形区分,但计算成本会增加。

Roundness输入端口

Roundness输入端口接受Float类型的数值,范围通常在0,1之间,用于控制多边形角的圆滑程度。这个参数是Rounded Polygon节点的特色功能,它通过复杂的数学计算在多边形的每个角点处创建平滑的圆弧过渡。

  • Roundness=0时,多边形保持原始锐角
  • Roundness=0.5时,角部呈现明显的圆角效果
  • Roundness=1时,形状趋近于椭圆形

在内部实现中,Roundness参数实际上控制的是圆角半径与多边形边长的比例关系。较高的Roundness值会产生较大的圆角半径,直到圆角半径达到多边形内切圆半径的上限。

Out输出端口

Out输出端口提供Float类型的数值,表示基于输入参数生成的形状遮罩。输出值的范围通常是0,1,其中1表示像素完全在形状内部,0表示完全在形状外部,中间值表示抗锯齿的边缘区域。

这个输出可以连接到各种其他节点的输入,如:

  • 颜色节点的Alpha输入,用于创建形状遮罩
  • 混合节点的透明度输入,用于形状间的混合操作
  • 步长节点的阈值输入,用于创建硬边缘效果
  • 自定义光照模型的输入,用于特殊渲染效果

生成的代码示例

以下示例代码展示了Rounded Polygon节点的完整实现,通过分析这段代码可以深入理解节点的内部工作原理和数学基础。

scss 复制代码
HLSL

void RoundedPolygon_Func_float(float2 UV, float Width, float Height, float Sides, float Roundness, out float Out)
{
    // 将UV从[0,1]转换到[-1,1]范围
    UV = UV * 2. + float2(-1.,-1.);

    // 防止除零错误的小值
    float epsilon = 1e-6;

    // 根据宽度和高度缩放UV
    UV.x = UV.x / ( Width + (Width==0)*epsilon);
    UV.y = UV.y / ( Height + (Height==0)*epsilon);

    // 限制圆度参数的有效范围
    Roundness = clamp(Roundness, 1e-6, 1.);

    // 计算实际使用的边数(取整并确保为正数)
    float i_sides = floor( abs( Sides ) );

    // 计算多边形的基本角度参数
    float fullAngle = 2. * PI / i_sides;        // 每个边的完整角度
    float halfAngle = fullAngle / 2.;           // 半边角度
    float opositeAngle = HALF_PI - halfAngle;   // 对边角度

    // 计算多边形的对角线长度(用于后续缩放)
    float diagonal = 1. / cos( halfAngle );

    // 计算倒角(圆角)相关的参数
    float chamferAngle = Roundness * halfAngle;           // 倒角占据的角度
    float remainingAngle = halfAngle - chamferAngle;      // 剩余的角度
    float ratio = tan(remainingAngle) / tan(halfAngle);   // 多边形三角形长度与倒角中心距离的比例

    // 计算倒角圆弧的中心坐标
    float2 chamferCenter = float2(
        cos(halfAngle),
        sin(halfAngle)
    ) * ratio * diagonal;

    // 计算倒角圆弧的起点坐标
    float2 chamferOrigin = float2(
        1.,
        tan(remainingAngle)
    );

    // 使用三角学计算距离参数
    float distA = length(chamferCenter);                     // 倒角中心到多边形中心的距离
    float distB = 1. - chamferCenter.x;                      // 倒角半径
    float distCref = length(chamferOrigin);                  // 倒角起点的参考距离

    // 计算UV缩放因子以确保多边形适合UV空间
    float uvScale = diagonal;
    UV *= uvScale;

    // 将笛卡尔坐标转换为极坐标
    float2 polaruv = float2 (
        atan2( UV.y, UV.x ),    // 角度分量
        length(UV)              // 半径分量
    );

    // 调整角度范围和对齐
    polaruv.x += HALF_PI + 2*PI;
    polaruv.x = fmod( polaruv.x + halfAngle, fullAngle );
    polaruv.x = abs(polaruv.x - halfAngle);

    // 将极坐标转换回笛卡尔坐标(但已进行角度对齐)
    UV = float2( cos(polaruv.x), sin(polaruv.x) ) * polaruv.y;

    // 计算倒角区域的角度比例
    float angleRatio = 1. - (polaruv.x - remainingAngle) / chamferAngle;

    // 使用余弦定理计算多边形中心到倒角边缘的距离
    float distC = sqrt( distA*distA + distB*distB - 2.*distA*distB*cos( PI - halfAngle * angleRatio ) );

    // 初始化输出值为X坐标(用于非倒角区域)
    Out = UV.x;

    // 检测当前像素是否位于倒角区域
    float chamferZone = ( halfAngle - polaruv.x ) < chamferAngle;

    // 根据区域选择使用不同的距离计算
    Out = lerp( UV.x, polaruv.y / distC, chamferZone );

    // 将距离场转换为形状遮罩(包含抗锯齿)
    Out = saturate((1 - Out) / fwidth(Out));
}

代码解析与优化建议

这段生成的代码展示了Rounded Polygon节点的完整计算流程,从坐标变换到最终的距离场生成。代码的逻辑可以分为几个主要阶段:

坐标预处理阶段将输入的UV从标准的0,1范围转换到-1,1的对称空间,这样便于后续的中心对称计算。同时根据Width和Height参数进行适当的缩放,确保形状能够正确匹配指定的尺寸。

几何参数计算阶段根据Sides参数计算多边形的各种角度关系,包括完整角度、半角度和对角线长度。这些参数是构建多边形几何的基础。

圆角处理阶段是代码中最复杂的部分,它根据Roundness参数计算倒角(圆角)的各种属性,包括倒角角度、倒角中心位置和倒角半径等。这里使用了三角学和几何关系来精确计算圆角的形状。

极坐标变换阶段将笛卡尔坐标系转换为极坐标系,这样可以更方便地处理多边形的径向对称性。通过角度对齐和模运算,代码将问题简化为处理单个扇形区域。

距离场计算阶段根据像素所在的不同区域(平面边区域或圆角区域)使用不同的距离计算方法。对于平面边区域,直接使用X坐标作为距离;对于圆角区域,使用复杂的三角公式计算到圆弧边缘的距离。

后期处理阶段将计算得到的距离场通过fwidth函数进行抗锯齿处理,最终通过saturate函数转换为标准的0,1遮罩值。

在实际使用中,如果性能成为瓶颈,可以考虑以下优化策略:

  • 对于不需要动态变化的形状,可以预计算某些参数
  • 在远处或小尺寸情况下使用简化的计算方式
  • 利用着色器LOD技术在不同情况下使用不同精度的计算
  • 将复杂的形状计算转移到查找纹理中,用空间换时间

【Unity Shader Graph 使用与特效实现】专栏-直达 (欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)

相关推荐
SmalBox1 天前
【节点】[Rectangle节点]原理解析与实际应用
unity3d·游戏开发·图形学
SmalBox2 天前
【节点】[Polygon节点]原理解析与实际应用
unity3d·游戏开发·图形学
_zhourui_h_2 天前
MyFramework:整体代码结构与热更新分层解析
unity3d·游戏开发
甲维斯3 天前
Fable+Codex 《坦克大战3D》双端发布了!
人工智能·ai编程·游戏开发
SmalBox3 天前
【节点】[Houndstooth节点]原理解析与实际应用
unity3d·游戏开发·图形学
龙智DevSecOps解决方案5 天前
3A 游戏优化技术栈:如何打通引擎级分析工具与 DevOps 持续集成管线?
unity·性能优化·游戏开发·技术美术·perforce·unrealengine
SmalBox5 天前
【节点】[Herringbone节点]原理解析与实际应用
unity3d·游戏开发·图形学
_zhourui_h_5 天前
MyFramework:ClassPool 对象池与 resetProperty 的实现解析
unity3d
SmalBox6 天前
【节点】[Grid节点]原理解析与实际应用
unity3d·游戏开发·图形学