You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何查找绕原点旋转的3D网格中任意点的最近格点(Unity C#适用)

通用求解思路

这个问题的核心解法是坐标空间转换,不需要在世界空间做复杂的几何计算,具体步骤如下:

  • 首先明确网格的变换参数:本题中网格仅绕原点旋转,我们只需要存储网格的旋转矩阵/四元数R即可。
  • 逆变换到网格局部空间:将世界空间下的待查询点P乘R的逆矩阵,得到网格局部坐标系下的坐标P_local。由于旋转矩阵是正交矩阵,逆矩阵等于转置矩阵,计算开销极低。
  • 局部空间找最近格点:网格在自身局部空间是对齐坐标轴、步长为1的规则网格,因此直接对P_local的三个分量分别四舍五入,就能得到局部空间下的最近格点G_local。
  • 正变换回世界空间:将G_local乘原始旋转矩阵R,得到的结果就是世界空间下的最近格点坐标。

如果你的网格后续需要支持偏移、缩放,只需要在变换步骤中对应加减偏移、乘除缩放系数即可,逻辑完全通用。

Unity C# 实现

我们可以把逻辑封装为可复用的工具类,预计算逆旋转避免重复计算,单次查询时间复杂度为O(1),适合运行时高频调用:

using UnityEngine;

public class RotatedGridSnapper
{
    private Quaternion _gridRotation;
    private Quaternion _inverseGridRotation;

    /// <summary>
    /// 构造旋转网格吸附工具
    /// </summary>
    /// <param name="gridRotation">网格的世界空间旋转</param>
    public RotatedGridSnapper(Quaternion gridRotation)
    {
        UpdateGridRotation(gridRotation);
    }

    /// <summary>
    /// 运行时更新网格的旋转参数
    /// </summary>
    public void UpdateGridRotation(Quaternion newRotation)
    {
        _gridRotation = newRotation;
        _inverseGridRotation = Quaternion.Inverse(newRotation);
    }

    /// <summary>
    /// 查询世界空间点对应的最近格点坐标
    /// </summary>
    /// <param name="worldPoint">待查询的世界空间点</param>
    /// <param name="gridStep">网格步长,默认1</param>
    /// <param name="gridOffset">网格原点的世界空间偏移,默认无偏移</param>
    /// <returns>世界空间下的最近格点坐标</returns>
    public Vector3 GetNearestGridPoint(Vector3 worldPoint, float gridStep = 1f, Vector3 gridOffset = default)
    {
        // 抵消网格全局偏移
        Vector3 offsetPoint = worldPoint - gridOffset;
        // 转换到网格局部空间
        Vector3 localPoint = _inverseGridRotation * offsetPoint;
        // 局部空间按步长吸附
        Vector3 localGridPoint = new Vector3(
            Mathf.Round(localPoint.x / gridStep) * gridStep,
            Mathf.Round(localPoint.y / gridStep) * gridStep,
            Mathf.Round(localPoint.z / gridStep) * gridStep
        );
        // 转换回世界空间并恢复偏移
        return _gridRotation * localGridPoint + gridOffset;
    }
}

使用示例

// 初始化:网格绕Y轴旋转45度,步长1,原点无偏移
Quaternion gridRotation = Quaternion.Euler(0, 45f, 0);
RotatedGridSnapper snapper = new RotatedGridSnapper(gridRotation);

// 查询示例
Vector3 testPoint = new Vector3(2.1f, 0.3f, 1.7f);
Vector3 nearestPoint = snapper.GetNearestGridPoint(testPoint);
Debug.Log($"最近格点坐标:{nearestPoint}");

注意事项

  • 默认使用Unity的Mathf.Round实现四舍五入,采用银行家舍入规则(即中间值舍入到最近的偶数),如果需要自定义舍入规则,替换Mathf.Round为自定义实现即可。
  • 如果网格有非均匀缩放,只需要把缩放参数也存入工具类,逆变换时对应除以各轴缩放系数,正变换时乘回缩放系数即可。

内容的提问来源于stack exchange,提问作者starbi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 13:36:04