unity 与cad 坐标系映射

cs 复制代码
 #region 坐标系转化
    [System.Serializable]
    public class CoordGroup
    {
        [Header("区域名称/备注")]
        public string areaName;

        [Header("现实三点(CAD原始坐标)")]
        public Vector3 W0, W1, W2;
        [Header("对应Unity三点(场景世界坐标)")]
        public Vector3 U0, U1, U2;

        [Header("坐标系适配配置")]
        [Tooltip("自动映射:CAD(XY平面+Z高程) → Unity(XZ平面+Y高程),建筑场景默认开启")]
        public bool autoMapAxes = true;
        [Tooltip("左手系适配:修正CAD右手系与Unity左手系的镜像偏差,默认开启")]
        public bool adaptLeftHand = true;

        [HideInInspector] public Matrix4x4 transMatrix;
        [HideInInspector] public Matrix4x4 transMatrixInv; // Unity转现实逆矩阵
        [HideInInspector] public bool isValid = false;
    }

    [Header("添加所有独立坐标系区域")]
    public CoordGroup[] coordGroups;

    /// <summary>
    /// 批量计算所有坐标系矩阵
    /// </summary>
    void BuildAllMatrix()
    {
        for (int i = 0; i < coordGroups.Length; i++)
        {
            var group = coordGroups[i];
            group.isValid = BuildSingleMatrix(group);
            if (!group.isValid)
            {
                Debug.LogError($"【{group.areaName}】坐标系三点共线,构建失败!");
            }
            else
            {
                Debug.Log($"【{group.areaName}】矩阵构建成功");
            }
        }
    }

    /// <summary>
    /// 构建单个坐标系矩阵(核心适配逻辑已改造)
    /// </summary>
    bool BuildSingleMatrix(CoordGroup group)
    {
        // ========== 1. CAD轴向自动对齐Unity ==========
        Vector3 w0, w1, w2;
        if (group.autoMapAxes)
        {
            // CAD原始(X,Y,Z) → 对齐Unity轴向:X不变,CAD平面Y→Unity平面Z,CAD高程Z→Unity高程Y
            w0 = new Vector3(group.W0.x, group.W0.z, group.W0.y);
            w1 = new Vector3(group.W1.x, group.W1.z, group.W1.y);
            w2 = new Vector3(group.W2.x, group.W2.z, group.W2.y);
        }
        else
        {
            w0 = group.W0;
            w1 = group.W1;
            w2 = group.W2;
        }

        // ========== 2. 计算两侧基向量 ==========
        // 现实(CAD)侧基向量
        Vector3 wAxisX = w1 - w0;
        Vector3 wAxisY = w2 - w0;
        Vector3 wAxisZ = Vector3.Cross(wAxisX, wAxisY);

        // Unity侧基向量
        Vector3 uAxisX = group.U1 - group.U0;
        Vector3 uAxisY = group.U2 - group.U0;
        Vector3 uAxisZ = Vector3.Cross(uAxisX, uAxisY);

        // 左手系适配:Unity为左手坐标系,第三轴取反消除镜像
        if (group.adaptLeftHand)
        {
            uAxisZ = -uAxisZ;
        }

        // 双侧校验三点共线
        if (wAxisZ.magnitude < Mathf.Epsilon || uAxisZ.magnitude < Mathf.Epsilon)
            return false;

        // ========== 3. 构建局部坐标系矩阵 ==========
        // 现实坐标系矩阵(已对齐轴向)
        Matrix4x4 worldLocal = Matrix4x4.identity;
        worldLocal.SetColumn(0, new Vector4(wAxisX.x, wAxisX.y, wAxisX.z, 0));
        worldLocal.SetColumn(1, new Vector4(wAxisY.x, wAxisY.y, wAxisY.z, 0));
        worldLocal.SetColumn(2, new Vector4(wAxisZ.x, wAxisZ.y, wAxisZ.z, 0));
        worldLocal.SetColumn(3, new Vector4(w0.x, w0.y, w0.z, 1));

        // Unity坐标系矩阵
        Matrix4x4 unityLocal = Matrix4x4.identity;
        unityLocal.SetColumn(0, new Vector4(uAxisX.x, uAxisX.y, uAxisX.z, 0));
        unityLocal.SetColumn(1, new Vector4(uAxisY.x, uAxisY.y, uAxisY.z, 0));
        unityLocal.SetColumn(2, new Vector4(uAxisZ.x, uAxisZ.y, uAxisZ.z, 0));
        unityLocal.SetColumn(3, new Vector4(group.U0.x, group.U0.y, group.U0.z, 1));

        // ========== 4. 计算最终变换矩阵 ==========
        group.transMatrix = unityLocal * worldLocal.inverse;
        group.transMatrixInv = group.transMatrix.inverse;
        return true;
    }

    /// <summary>
    /// 根据区域下标,CAD现实坐标转Unity坐标
    /// </summary>
    /// <param name="worldPos">CAD原始坐标(X,Y,Z)</param>
    /// <param name="areaIndex">区域下标(从0开始)</param>
    public Vector3 WorldToUnity(Vector3 worldPos, int areaIndex)
    {
        if (areaIndex < 0 || areaIndex >= coordGroups.Length)
        {
            Debug.LogError("区域下标越界");
            return Vector3.zero;
        }

        var group = coordGroups[areaIndex];
        if (!group.isValid)
        {
            Debug.LogError($"【{group.areaName}】坐标系无效");
            return Vector3.zero;
        }

        // 输入轴向对齐
        Vector3 input = worldPos;
        if (group.autoMapAxes)
        {
            input = new Vector3(worldPos.x, worldPos.z, worldPos.y);
        }
        return group.transMatrix.MultiplyPoint3x4(input);
    }

    /// <summary>
    /// 根据区域名称转换 CAD → Unity
    /// </summary>
    public Vector3 WorldToUnityByName(Vector3 worldPos, string areaName)
    {
        foreach (var group in coordGroups)
        {
            if (group.areaName == areaName && group.isValid)
            {
                Vector3 input = worldPos;
                if (group.autoMapAxes)
                {
                    input = new Vector3(worldPos.x, worldPos.z, worldPos.y);
                }
                return group.transMatrix.MultiplyPoint3x4(input);
            }
        }
        Debug.LogError($"未找到区域:{areaName}");
        return Vector3.zero;
    }

    /// <summary>
    /// 根据区域下标,Unity坐标转CAD现实坐标
    /// </summary>
    /// <param name="unityPos">Unity场景坐标</param>
    /// <param name="areaIndex">区域下标(从0开始)</param>
    public Vector3 UnityToWorld(Vector3 unityPos, int areaIndex)
    {
        if (areaIndex < 0 || areaIndex >= coordGroups.Length)
        {
            Debug.LogError("区域下标越界");
            return Vector3.zero;
        }

        var group = coordGroups[areaIndex];
        if (!group.isValid)
        {
            Debug.LogError($"【{group.areaName}】坐标系无效");
            return Vector3.zero;
        }

        Vector3 result = group.transMatrixInv.MultiplyPoint3x4(unityPos);
        // 输出轴向还原为CAD原始坐标
        if (group.autoMapAxes)
        {
            result = new Vector3(result.x, result.z, result.y);
        }
        return result;
    }

    /// <summary>
    /// 根据区域名称,Unity坐标转CAD现实坐标
    /// </summary>
    public Vector3 UnityToWorldByName(Vector3 unityPos, string areaName)
    {
        foreach (var group in coordGroups)
        {
            if (group.areaName == areaName && group.isValid)
            {
                Vector3 result = group.transMatrixInv.MultiplyPoint3x4(unityPos);
                if (group.autoMapAxes)
                {
                    result = new Vector3(result.x, result.z, result.y);
                }
                return result;
            }
        }
        Debug.LogError($"未找到区域:{areaName}");
        return Vector3.zero;
    }
    #endregion
相关推荐
Aman19849 小时前
Claude Code做Unity项目移植(二): 自动执行只读操作,告别频繁的
unity·游戏开发·vibe coding·claude code
暴走约伯18 小时前
【VFX工具链源码拆解 02】告别机械劳动(上):一键统改百个子粒子颜色与批量重命名
3d·unity·c#·材质
郝学胜-神的一滴18 小时前
游戏设计:原型与开发 18:Unity入门的第一课
人工智能·程序人生·游戏·ui·unity·游戏引擎
淡海水20 小时前
09-01-内存-Unity资源生命周期全景
unity·c#·游戏引擎·.netcore·gc
Solange__1 天前
AI世界模型、3D场景生成和游戏引擎怎么选?按5类任务比较交互、物理与导出
开发语言·人工智能·游戏·平面·3d·自然语言处理·游戏引擎
LF男男1 天前
Flower Defense—UIFacade
unity
呆呆敲代码的小Y1 天前
【实战精选面试题】Unity精选面试题详细解答,按模块整理汇总
人工智能·游戏·unity·游戏引擎
小贺儿开发1 天前
《流光绘忆》Unity 沉浸式光影互动
科技·unity·ai·程序员·工具·互动·光影
Aman19842 天前
Claude Code做Unity项目移植(一):从零散工具到团队式
unity·游戏开发·vibe coding·claude code·项目迁移
地狱为王2 天前
Unity使用VoxLock实现语音隔离
unity·游戏引擎·音频处理·voxlock