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
相关推荐
WiChP1 小时前
【V0.1B15】从零开始的2D游戏引擎开发之路
游戏引擎
zhchyun20081 天前
# 【Unity UI 进阶】仿 Element UI 打造企业级 Unity UI 组件库(06)
ui·unity·游戏引擎
Behaviour2 天前
Unity游戏HybridCLR 热更新接入实战
游戏·unity·游戏引擎
LONGZETECH2 天前
新能源汽车动力电池实训教学痛点与虚拟仿真技术解决方案
c语言·3d·unity·架构·汽车·汽车教学软件
王维志2 天前
UiSplineRenderer
unity·游戏引擎
k4m7v2pz2 天前
Godot 4 仿 agar.io:相机缩放被 max_zoom 卡死,窗口越大球越小的根因与修复
游戏引擎·godot·相机·缩放·clamp·camera2d
FairGuard手游加固2 天前
iOS 游戏加固技术解析:代码混淆、资源加密、内存保护与重签名检测
安全·游戏·macos·unity·ios·objective-c
k4m7v2pz3 天前
Godot 4 窗口拉伸黑边与变形:stretch 配置全解析
数码相机·游戏引擎·godot·2d游戏·黑边·stretch·画面比例
UWA4 天前
GPM 2.0 WebGL 监测能力扩容|覆盖 Unity/Cocos/LayaAir 多引擎微信 & 抖音小游戏
unity·微信·性能优化·小游戏·webgl
Behaviour4 天前
Unity 手游网络同步技术
网络·unity·c#·游戏引擎