ShaderGraph节点解析(124):绕轴旋转节点(Rotate About Axis Node)详解

目录

一、节点功能概述

二、端口详解

控制选项

三、技术原理解析

3.1 数学基础:罗德里格斯旋转公式

3.2 旋转矩阵构造

3.3 生成代码解析

1. 弧度模式(Radians)

2. 度模式(Degrees)

3.4 旋转方向:右手定则

四、应用场景与实战案例

4.1 角色骨骼旋转(动画驱动)

场景:实现角色手臂绕肱骨(上臂骨)旋转,模拟弯曲动作

4.2 相机环绕效果(第三人称视角)

场景:让相机绕目标物体(如角色)的 Y 轴旋转,实现环绕观察

4.3 粒子运动轨迹(螺旋线)

场景:让粒子绕某一轴做螺旋运动,模拟星云、涡流效果

4.4 地形变形(绕轴扭曲)

场景:让地形沿某一倾斜轴旋转扭曲,模拟地震或魔法效果

五、使用技巧与注意事项

5.1 旋转轴的归一化

5.2 角度单位的选择

5.3 旋转方向的控制

5.4 性能考量

5.5 与其他旋转节点的对比

六、总结与拓展应用


一、节点功能概述

绕轴旋转节点(Rotate About Axis Node)是 Unity Shader Graph 中用于实现三维向量绕指定轴旋转的核心工具。它接收一个三维向量(In)、一个旋转轴(Axis)和一个旋转角度(Rotation),返回旋转后的向量(Out)。旋转角度的单位可通过参数(Unit)切换为弧度(Radians)或度(Degrees),满足不同场景的使用习惯。

该节点的核心特性在于:

  • 三维旋转:严格遵循三维空间的旋转规律,基于罗德里格斯旋转公式(Rodrigues' rotation formula)计算旋转矩阵,确保旋转的准确性。
  • 轴任意性:支持绕任意方向的轴旋转(不仅限于 X、Y、Z 轴),适配复杂的空间变换需求(如角色骨骼旋转、相机环绕)。
  • 单位灵活性:通过 Unit 参数切换角度单位,无需手动转换,简化工作流。
  • 应用广泛:是角色动画、相机控制、粒子轨迹、地形变形等 3D 变换场景的基础组件。

二、端口详解

ShaderGraph节点解析(124):绕轴旋转节点(Rotate About Axis Node)详解_第1张图片

端口名称 方向 类型 描述
In 输入 Vector 3 待旋转的三维向量(如顶点位置、方向向量)
Axis 输入 Vector 3 旋转轴向量(任意方向,会被自动归一化)
Rotation 输入 Float 旋转角度(单位由 Unit 参数指定)
Out 输出 Vector 3 旋转后的三维向量

控制选项

控制名称 类型 可选值 描述
Unit 下拉菜单 Radians / Degrees 旋转角度的单位(弧度 / 度)

三、技术原理解析

3.1 数学基础:罗德里格斯旋转公式

绕轴旋转的核心是通过旋转矩阵实现向量变换,节点基于罗德里格斯旋转公式构建矩阵,公式如下:{R} = \mathbf{I} + \sin\theta \cdot [\mathbf{k}]_{\times} + (1 - \cos\theta) \cdot [\mathbf{k}]_{\times}^2其中:

  • R是 3×3 旋转矩阵;
  • I是 3×3 单位矩阵;
  • \theta是旋转角度(弧度);
  • \mathbf{k}是归一化的旋转轴向量;
  • [\mathbf{k}]_{\times}\mathbf{k}的反对称矩阵(叉积矩阵)。

3.2 旋转矩阵构造

根据罗德里格斯公式,节点生成的旋转矩阵展开为:\mathbf{R} = \begin{bmatrix} k_x^2(1-\cos\theta) + \cos\theta & k_xk_y(1-\cos\theta) - k_z\sin\theta & k_xk_z(1-\cos\theta) + k_y\sin\theta \\ k_xk_y(1-\cos\theta) + k_z\sin\theta & k_y^2(1-\cos\theta) + \cos\theta & k_yk_z(1-\cos\theta) - k_x\sin\theta \\ k_xk_z(1-\cos\theta) - k_y\sin\theta & k_yk_z(1-\cos\theta) + k_x\sin\theta & k_z^2(1-\cos\theta) + \cos\theta \\ \end{bmatrix}其中k_x, k_y, k_z是旋转轴\mathbf{k}的分量(已归一化)。

3.3 生成代码解析

节点根据角度单位(Unit)生成两种代码,核心差异在于是否需要将角度从度转换为弧度:

1. 弧度模式(Radians)

hlsl

void Unity_RotateAboutAxis_Radians_float(float3 In, float3 Axis, float Rotation, out float3 Out)
{
    float s = sin(Rotation); // 正弦值(旋转角度已为弧度)
    float c = cos(Rotation); // 余弦值
    float one_minus_c = 1.0 - c; // 1 - cosθ

    Axis = normalize(Axis); // 旋转轴归一化
    // 构造旋转矩阵(基于罗德里格斯公式)
    float3x3 rot_mat =
    {   one_minus_c * Axis.x * Axis.x + c, one_minus_c * Axis.x * Axis.y - Axis.z * s, one_minus_c * Axis.z * Axis.x + Axis.y * s,
        one_minus_c * Axis.x * Axis.y + Axis.z * s, one_minus_c * Axis.y * Axis.y + c, one_minus_c * Axis.y * Axis.z - Axis.x * s,
        one_minus_c * Axis.z * Axis.x - Axis.y * s, one_minus_c * Axis.y * Axis.z + Axis.x * s, one_minus_c * Axis.z * Axis.z + c
    };
    Out = mul(rot_mat, In); // 向量与旋转矩阵相乘,得到旋转后向量
}
2. 度模式(Degrees)

hlsl

void Unity_RotateAboutAxis_Degrees_float(float3 In, float3 Axis, float Rotation, out float3 Out)
{
    Rotation = radians(Rotation); // 先将度转换为弧度
    float s = sin(Rotation);
    float c = cos(Rotation);
    float one_minus_c = 1.0 - c;

    Axis = normalize(Axis);
    float3x3 rot_mat = // 后续矩阵构造与弧度模式完全一致
    {   one_minus_c * Axis.x * Axis.x + c, one_minus_c * Axis.x * Axis.y - Axis.z * s, one_minus_c * Axis.z * Axis.x + Axis.y * s,
        one_minus_c * Axis.x * Axis.y + Axis.z * s, one_minus_c * Axis.y * Axis.y + c, one_minus_c * Axis.y * Axis.z - Axis.x * s,
        one_minus_c * Axis.z * Axis.x - Axis.y * s, one_minus_c * Axis.y * Axis.z + Axis.x * s, one_minus_c * Axis.z * Axis.z + c
    };
    Out = mul(rot_mat, In);
}

3.4 旋转方向:右手定则

旋转方向遵循右手定则:右手拇指指向旋转轴(Axis)的正方向,四指弯曲的方向即为旋转方向(逆时针为正角度)。

四、应用场景与实战案例

4.1 角色骨骼旋转(动画驱动)

场景:实现角色手臂绕肱骨(上臂骨)旋转,模拟弯曲动作
  1. 需求:手臂顶点绕肱骨方向的轴旋转,角度随动画参数变化
  2. 实现步骤

    hlsl

    // 肱骨方向(旋转轴,从肩部到肘部的向量)
    float3 humerusAxis = normalize(_ElbowPos - _ShoulderPos);
    
    // 动画参数:旋转角度(度,0-90度对应弯曲程度)
    float bendAngle = _BendParameter * 90.0;
    
    // 手臂顶点的初始位置(相对于肩部)
    float3 armVertex = IN.vertex.xyz - _ShoulderPos;
    
    // 绕肱骨轴旋转顶点
    float3 rotatedVertex = RotateAboutAxisNode.Out; // In=armVertex, Axis=humerusAxis, Rotation=bendAngle, Unit=Degrees
    
    // 旋转后位置 = 肩部位置 + 旋转后的顶点相对位置
    o.vertex.xyz = _ShoulderPos + rotatedVertex;
    

4.2 相机环绕效果(第三人称视角)

场景:让相机绕目标物体(如角色)的 Y 轴旋转,实现环绕观察
  1. 步骤

    hlsl

    // 目标物体位置(旋转中心)
    float3 targetPos = _TargetWorldPos;
    
    // 相机到目标的初始方向(半径固定)
    float3 cameraOffset = _CameraDistance * float3(1, 0, 0); // 初始在目标右侧
    
    // 旋转轴:世界Y轴(垂直向上)
    float3 rotateAxis = float3(0, 1, 0);
    
    // 旋转角度:随鼠标X轴输入变化(度/帧)
    float rotateAngle = _MouseXInput * _Sensitivity;
    
    // 旋转相机偏移量
    float3 rotatedOffset = RotateAboutAxisNode.Out; // In=cameraOffset, Axis=rotateAxis, Rotation=rotateAngle, Unit=Degrees
    
    // 相机新位置 = 目标位置 + 旋转后的偏移
    float3 newCameraPos = targetPos + rotatedOffset;
    
    // 更新相机视图矩阵(简化示例)
    _WorldSpaceCameraPos = newCameraPos;
    

4.3 粒子运动轨迹(螺旋线)

场景:让粒子绕某一轴做螺旋运动,模拟星云、涡流效果
  1. 实现

    hlsl

    // 粒子初始方向(沿Z轴)
    float3 particleDir = float3(0, 0, 1);
    
    // 旋转轴:沿Z轴(螺旋中心轴)
    float3 spiralAxis = float3(0, 0, 1);
    
    // 旋转角度:随粒子生命周期递增(每移动1单位距离旋转180度)
    float travelDistance = length(IN.vertex.xyz - _EmitterPos);
    float spiralAngle = travelDistance * 180.0; // 度
    
    // 旋转粒子方向
    float3 rotatedDir = RotateAboutAxisNode.Out; // In=particleDir, Axis=spiralAxis, Rotation=spiralAngle, Unit=Degrees
    
    // 粒子新位置 = 发射位置 + 旋转方向 * 距离
    o.vertex.xyz = _EmitterPos + rotatedDir * travelDistance;
    

4.4 地形变形(绕轴扭曲)

场景:让地形沿某一倾斜轴旋转扭曲,模拟地震或魔法效果
  1. 示例

    hlsl

    // 扭曲轴:沿XZ平面的对角线(如(1,0,1)方向)
    float3 twistAxis = normalize(float3(1, 0, 1));
    
    // 扭曲强度:距离扭曲中心越远,旋转角度越大(弧度)
    float distanceToCenter = length(IN.worldPos.xz - _TwistCenter.xz);
    float twistAngle = distanceToCenter * _TwistStrength; // 弧度
    
    // 地形顶点的初始位置
    float3 terrainVertex = IN.worldPos;
    
    // 绕扭曲轴旋转顶点
    float3 twistedVertex = RotateAboutAxisNode.Out; // In=terrainVertex, Axis=twistAxis, Rotation=twistAngle, Unit=Radians
    
    // 应用扭曲变形
    o.vertex.xyz = twistedVertex;
    

五、使用技巧与注意事项

5.1 旋转轴的归一化

虽然节点内部会对旋转轴(Axis)进行归一化(Axis = normalize(Axis)),但建议在输入前手动归一化,避免因轴向量模长异常导致的计算误差(尤其是动态生成的轴向量):

hlsl

float3 safeAxis = normalize(dynamicAxis); // 提前归一化,更可靠

5.2 角度单位的选择

  • 度(Degrees):适合人工输入(如动画参数、UI 控制),符合直觉(0-360 度对应一圈);
  • 弧度(Radians):适合程序驱动(如时间、噪声输出),无需转换(_Time.y * 2π直接对应一圈)。

5.3 旋转方向的控制

若需反向旋转(顺时针),可对角度取负:

hlsl

float reverseAngle = -originalAngle; // 顺时针旋转

5.4 性能考量

旋转矩阵的计算包含多次乘法、三角函数(sin/cos)和矩阵乘法,属于中高开销操作。在片段着色器中高频使用时(如每像素旋转),建议:

  • 对静态旋转轴(如世界 Y 轴)预计算旋转矩阵,避免重复计算;
  • 减少旋转角度的精度(如用 half 代替 float);
  • 对大面积相同旋转的物体,在顶点着色器中完成旋转(而非片段着色器)。

5.5 与其他旋转节点的对比

节点 核心逻辑 适用场景
Rotate About Axis 绕任意轴旋转 复杂 3D 旋转(如骨骼、相机)
Rotate Around 绕指定点 + 轴旋转(含平移) 环绕目标旋转(如卫星运动)
Transform 基于模型 / 世界矩阵的整体旋转 模型空间到世界空间的变换

六、总结与拓展应用

绕轴旋转节点通过罗德里格斯旋转公式,为三维向量绕任意轴的旋转提供了精准工具,其核心价值在于:

  1. 空间变换基础:是角色动画、相机控制、粒子轨迹等 3D 变换场景的核心组件,确保旋转符合物理规律。
  2. 灵活性与准确性:支持任意旋转轴和角度单位,兼顾易用性与数学严谨性。
  3. 拓展性强:可与动画曲线、噪声函数等结合,实现复杂的动态旋转效果(如非线性加速旋转、随机扰动旋转)。

拓展方向

  • 结合动画曲线(Animation Curve),用曲线控制旋转角度随时间的变化,实现自然的加速 / 减速旋转;
  • 物理模拟中,通过绕轴旋转计算刚体的角速度与线速度的转换;
  • 开发自定义变形器,对网格顶点按不同轴和角度进行分层旋转,模拟布料褶皱、地形隆起等效果。

你可能感兴趣的:(#,unity,ShaderGraph,Unity)