Unity中的坐标转换

一:Unity中的四种坐标系


——世界坐标(World Space)
世界坐标很好理解,它是一个3D坐标。就是游戏物体在你创造世界中的坐标。transfrom.position获得的是物体相对于世界坐标的位置,transfrom.localPosition获得的是物体相对于父物体坐标的位置
模型Mesh保存的顶点坐标均为局部坐标系下的坐标


——屏幕坐标(Screen Space)
屏幕坐标是以像素来定义的,与分辨率有关,例如分辨率为1280*720的屏幕则Screen.width为1280,Screen.height为720。
Screen.width = Camera.main.pixelWidth和Screen.height = Camera.main.pixelHeight只有在相机视口坐标是整个屏幕时才满足。所以不难看出Screen.width是屏幕的分辨率即屏幕的宽度, 而Camera.main.pixelWidth是相机的视口像素大小,也可以理解为相机视口的像素宽度。
屏幕的左下角坐标为(0 , 0),右上角为(Screen.width , Screen.height),z轴坐标是相机的世界坐标中z轴的负值
我们常用的Input.mousePosition和移动端的Input.GetTouch(0).position都是获得的光标在屏幕坐标的位置


——视口坐标(Viewport Space)
视口坐标系其实就是将屏幕坐标系单位化
视口坐标的左下角为(0 , 0),右上角为(1 , 1),z轴坐标是相机的世界坐标中z轴的负值
可用于制作分屏游戏

——GUI坐标
只作了解就好
它的原点在左上角为(0,0),右下角坐标为(Screen.width, Screen.height), 因为这是一个二维的坐标系,所以坐标z的值永远都为0

二:各种坐标转换


——InverseTransformPoint和TransformPoin
例如物体A的世界坐标坐标为(1,2,3),物体B的世界坐标为(2,2,2),现在需要计算物体B相对于物体A的局部坐标,则应该使用A.transform.InverseTransformPoint(B)


——屏幕坐标转世界坐标

Vector3 mousePos = Input.mousePosition;
Vector3 screenToWorld = Camera.main.ScreenToWorldPoint(new Vector3(mousePos.x, mousePos.y, -Camera.main.transform.position.z));
Debug.Log(screenToWorld);


——世界坐标转屏幕坐标

Vector3 worldToScreen = Camera.main.WorldToScreenPoint(transform.position);
Debug.Log(worldToScreen);


——屏幕坐标转视口坐标

Vector3 mousePos = Input.mousePosition;
Vector3 screenToViewport = Camera.main.ScreenToViewportPoint(mousePos);
Debug.Log(screenToViewport);


——视口坐标转屏幕坐标

Vector3 viewportToScreen = Camera.main.ViewportToScreenPoint(new Vector3(1, 1, 0));
Debug.Log(viewportToScreen);


——世界坐标转视口坐标

Vector3 worldToViewport = Camera.main.WorldToViewportPoint(transform.position);
Debug.Log(worldToViewport);


——视口坐标转世界坐标

 Vector3 viewportToWord = Camera.main.ViewportToWorldPoint(new Vector3(1, 1, -Camera.main.transform.position.z));
 Debug.Log(viewportToWord);


——屏幕坐标转UI坐标

Vector2 mousePos;
RectTransformUtility.ScreenPointToLocalPointInRectangle(transform.parent.GetComponent<RectTransform>(), Input.mousePosition, null, out mousePos);
Debug.Log(mousePos);


1.Canvas的RenderMode为Overlay时,cam参数应该为NULL

任何一个坐标转世界坐标时,z的参数都应该为相机在世界坐标中z的负值
从世界坐标转到任何一个坐标时,计算出的z值都是相机的世界坐标中z轴的负值

三:屏幕坐标转世界坐标时为什么要使用-Camera.transform.position.z

 

任何一个坐标转世界坐标时的z值,可以理解为离相机的距离。其实是把屏幕坐标投影到相机的视锥体平面上,如果z的值为0,则相当于投影到了相机的近平面上,但是近平面的最小值为0.01,所以在进行屏幕坐标转世界坐标时,屏幕坐标的z值不能为0(注意Input.mousePosition的z值为0)
而且随着z的值越来越大,投影到的平面也会越来越大,x和y的值也会越来越大

四:坐标转换的工具类

using UnityEngine;
 
/// <summary>
/// 坐标转换工具类
/// </summary>
public static class CTUtils
{
    /// <summary>
    /// 世界坐标转屏幕坐标
    /// </summary>
    public static Vector2 World2Screen(Vector3 wp, Camera camera = null)
    {
        if (camera == null)
        {
            camera = Camera.main;
        }
        return camera.WorldToScreenPoint(wp);
    }
 
    /// <summary>
    /// 屏幕坐标转世界坐标
    /// </summary>
    public static Vector3 Screen2World(Vector3 sp, Camera camera = null)
    {
        if (camera == null)
        {
            camera = Camera.main;
        }
        return camera.ScreenToWorldPoint(sp);
    }
 
    /// <summary>
    /// 世界坐标转视口坐标
    /// </summary>
    public static Vector2 World2Viewport(Vector3 wp, Camera camera = null)
    {
        if (camera == null)
        {
            camera = Camera.main;
        }
        return camera.WorldToViewportPoint(wp);
    }
 
    /// <summary>
    /// 视口坐标转世界坐标
    /// </summary>
    public static Vector3 Viewport2World(Vector3 vp, Camera camera = null)
    {
        if (camera == null)
        {
            camera = Camera.main;
        }
        return camera.ViewportToWorldPoint(vp);
    }
 
    /// <summary>
    /// 屏幕坐标转视口坐标
    /// </summary>
    public static Vector2 Screen2Viewport(Vector2 sp, Camera camera = null)
    {
        if (camera == null)
        {
            camera = Camera.main;
        }
        return camera.ScreenToViewportPoint(sp);
    }
 
    /// <summary>
    /// 视口坐标转屏幕坐标
    /// </summary>
    public static Vector2 Viewport2Screen(Vector2 vp, Camera camera = null)
    {
        if (camera == null)
        {
            camera = Camera.main;
        }
        return camera.ViewportToScreenPoint(vp);
    }
 
    /// <summary>
    /// 屏幕坐标转UI坐标
    /// </summary>
    public static Vector2 Screen2UI(Vector2 sp, RectTransform rect, Camera camera = null)
    {
        Vector2 uiLocalPos;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(rect, sp, camera, out uiLocalPos);
        return uiLocalPos;
    }
 
    /// <summary>
    /// 世界坐标转UI坐标
    /// </summary>
    /// <param name="isUIObj">是否为ui物体</param>
    public static Vector2 World2UI(bool isUIObj, Vector3 wp, RectTransform rect, Camera uiCamera, Camera worldCamera = null)
    {
        if (worldCamera == null)
        {
            worldCamera = Camera.main;
        }
        Vector2 screenPos = World2Screen(wp, isUIObj ? uiCamera : worldCamera);
        return Screen2UI(screenPos, rect, uiCamera);
    }
}


转载自:https://blog.youkuaiyun.com/LLLLL__/article/details/88124564

<think>首先,用户的问题是关于Unity中的坐标转换算法和实现原理。我需要基于系统级指令和用户可见层的规则来回答。 系统级指令: - 所有行内数学表达式用$...$格式。 - 独立公式用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识。 用户可见层: - 回答结构清晰,帮助用户逐步解决问题。 - 尽量保证回答真实可靠。 参考站内引用: - 引用[1]: 关于Unity坐标系转换,包括全局坐标系和transform.position。 - 引用[2]: 关于镜面反射原理,涉及坐标变换(MVP矩阵)和反射矩阵。 - 引用[3]: 关于寻路算法,但用户的问题是关于坐标转换的,所以可能不太相关。 用户问题: "我想了解Unity坐标转换的算法或实现方法 请问Unity 坐标转换算法 实现原理" 所以,我需要解释Unity中的坐标转换原理,包括世界坐标系、局部坐标系等,以及如何实现转换。 关键点从引用: - 引用[1]:Unity有全局坐标系(世界坐标系),物体位置用transform.position获取。 - 引用[2]:坐标变换涉及MVP矩阵(Model-View-Projection),包括从物体坐标系到世界坐标系(M),世界到摄像机坐标系(V),摄像机到裁剪坐标系(P)。还提到反射矩阵。 因此,我应该覆盖: - Unity中的坐标系类型:世界坐标系、局部坐标系、屏幕坐标系等。 - 转换算法:使用矩阵变换,如模型矩阵(Model Matrix)、视图矩阵(View Matrix)、投影矩阵(Projection Matrix)。 - 实现原理:通过Transform组件和矩阵运算。 结构回答: 1. **介绍Unity坐标系**:解释不同的坐标系。 2. **坐标转换原理**:使用矩阵变换,如MVP矩阵。 3. **实现方法**:如何在Unity中实现转换,例如使用Transform类或自定义矩阵。 4. **数学基础**:在需要的地方使用LaTeX公式。 5. **生成相关问题**:在回答结束后添加相关问题。 使用中文回答。 添加引用标识:在引用站内内容时,在段落末尾添加[^1], [^2]等。 现在,大纲回答: - **步骤1: 介绍Unity中的坐标系** - 全局坐标系(世界坐标系) - 局部坐标系(物体坐标系) - 摄像机坐标系 - 屏幕坐标系 引用[1]和[2]。 - **步骤2: 坐标转换算法** - 解释MVP矩阵变换: - Model矩阵:局部到世界 - View矩阵:世界到摄像机 - Projection矩阵:摄像机到裁剪/屏幕 - 数学公式:使用独立公式块。 - 例如,一个点的转换:$$ \mathbf{p}_{\text{clip}} = P \times V \times M \times \mathbf{p}_{\text{local}} $$ 引用[2]。 - **步骤3: 实现方法** - 在Unity中,Transform组件处理局部到世界转换。 - 使用Camera.worldToCameraMatrix和Camera.projectionMatrix。 - 示例代码:展示简单的实现。 - 引用[2]中的反射矩阵例子。 - **步骤4: 总结** - **相关问题**:生成3-5个相关问题。 确保LaTeX正确: - 行内:如 $M$ 表示模型矩阵。 - 独立:如矩阵乘法公式。 生成相关问题: - 类似于示例,但针对坐标转换。 - 例如: 1. 如何在Unity中实现自定义坐标转换? 2. Unity中的坐标转换性能优化方法? 3. 坐标转换在游戏开发中的常见应用场景? 现在,构建回答。</think>### Unity 坐标转换算法实现原理 在Unity游戏引擎中,坐标转换是核心渲染和物理系统的基础,涉及多个坐标系之间的变换。这种转换通过矩阵运算实现,确保物体在三维空间中的位置、旋转和缩放正确映射到屏幕。下面我将逐步解释Unity中的坐标系类型、转换算法原理及实现方法,帮助您全面理解。 #### 1. **Unity中的坐标系类型** Unity使用多种坐标系来描述物体位置: - **全局坐标系(世界坐标系)**:描述场景中所有物体的绝对位置,原点为 $(0,0,0)$。例如,使用 `transform.position` 获取物体在世界坐标中的位置[^1]。 - **局部坐标系(物体坐标系)**:以物体自身为原点,用于描述父子物体关系。例如,子物体的位置相对于父物体。 - **摄像机坐标系(视点坐标系)**:以摄像机为原点,用于渲染视角计算。世界坐标通过视图矩阵转换到此坐标系[^2]。 - **裁剪坐标系**:经过投影变换后,用于裁剪超出视锥体的顶点。 - **屏幕坐标系**:最终映射到屏幕像素坐标,如 $(x,y)$ 像素位置。 这些坐标系通过矩阵变换链实现转换,核心是**MVP矩阵变换流程**(Model-View-Projection)。 #### 2. **坐标转换算法原理** 坐标转换基于线性代数中的矩阵乘法,确保顶点在不同坐标系间高效转换。核心算法是MVP变换链: - **Model矩阵(M)**:将顶点从局部坐标系转换到世界坐标系。它包含物体的位置、旋转和缩放信息。数学表示为: $$ \mathbf{p}_{\text{world}} = M \times \mathbf{p}_{\text{local}} $$ 其中,$\mathbf{p}_{\text{local}}$ 是局部坐标向量,$M$ 是4×4模型矩阵(例如,Unity中的 `transform.localToWorldMatrix`)。 - **View矩阵(V)**:将顶点从世界坐标系转换到摄像机坐标系。这通过摄像机的位置和朝向计算,例如使用 `Camera.worldToCameraMatrix` 获取[^2]。公式为: $$ \mathbf{p}_{\text{view}} = V \times \mathbf{p}_{\text{world}} $$ - **Projection矩阵(P)**:将顶点从摄像机坐标系转换到裁剪坐标系,处理透视或正交投影(例如, `Camera.projectionMatrix`)。最终输出为: $$ \mathbf{p}_{\text{clip}} = P \times V \times M \times \mathbf{p}_{\text{local}} $$ 这里,$\mathbf{p}_{\text{clip}}$ 是裁剪空间坐标,后续会通过透视除法转换为屏幕坐标。 整个变换过程是高效的矩阵乘法链,每个矩阵由Unity引擎自动计算。例如,在渲染管线中,顶点着色器应用这些矩阵来实现实时转换[^2]。这种方法的优势在于: - **数学基础**:使用齐次坐标(4D向量)支持仿射变换(如平移、旋转)。 - **性能优化**:GPU硬件加速矩阵运算,确保高帧率。 - **灵活性**:可通过自定义矩阵(如反射矩阵)扩展功能,如镜面效果[^2]。 #### 3. **实现方法** 在Unity中,坐标转换的实现主要通过内置API和自定义脚本完成,无需手动计算底层矩阵(但了解原理有助于调试和优化)。以下是关键实现步骤: - **基本实现**: - 使用 `Transform` 组件获取或设置坐标:`Vector3 worldPos = transform.position;` 获取世界坐标,`transform.localPosition` 获取局部坐标[^1]。 - 摄像机相关转换:通过 `Camera` 类,如 `Vector3 screenPos = Camera.main.WorldToScreenPoint(worldPos);` 将世界坐标转换为屏幕坐标。 - 矩阵访问:直接使用 `Matrix4x4` 类,例如 `Matrix4x4 viewMatrix = Camera.main.worldToCameraMatrix;`[^2]。 - **自定义转换示例**: 如果需要实现特殊效果(如反射),可以组合矩阵。例如,镜面反射算法: ```csharp // 基于引用[2]的简化示例:应用反射矩阵 void ApplyReflection() { // 获取当前摄像机的视图矩阵 Matrix4x4 viewMatrix = Camera.main.worldToCameraMatrix; // 定义反射平面(例如,法线向量和距离) Vector3 planeNormal = new Vector3(0, 1, 0); // 假设为Y轴平面 float planeDistance = 0.0f; Matrix4x4 reflectionMatrix = Matrix4x4.Reflect(planeNormal, planeDistance); // 组合视图矩阵与反射矩阵:V' = V * R Matrix4x4 modifiedViewMatrix = viewMatrix * reflectionMatrix; // 应用修改后的矩阵到新摄像机 Camera reflectionCamera = new Camera(); reflectionCamera.CopyFrom(Camera.main); reflectionCamera.worldToCameraMatrix = modifiedViewMatrix; } ``` 此代码复制摄像机并修改视图矩阵,实现反射效果[^2]。 - **性能注意事项**: - **优化建议**:避免在Update()中频繁计算矩阵;使用缓存(如存储 `localToWorldMatrix`)。 - **底层原理**:Unity引擎在渲染循环中自动应用MVP矩阵,您可以通过Shader编写自定义变换(例如,在顶点着色器中操作矩阵)。 #### 4. **总结** Unity坐标转换算法基于MVP矩阵链,将局部坐标逐步映射到屏幕坐标,核心是矩阵乘法($ \mathbf{p}_{\text{clip}} = P \times V \times M \times \mathbf{p}_{\text{local}} $)。实现上,Unity提供了高级API(如 `Transform` 和 `Camera` 类),简化了开发。理解这些原理有助于处理复杂场景,如VR中的空间定位或物理模拟[^1][^2]。如果您需要深入特定矩阵的数学推导或代码示例,我可以进一步扩展。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值