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

Unity运行时双击墙创建正交相机并聚焦选中墙的技术问题

问题描述

我有一个包含房间设计的场景和一台正交相机,希望双击特定墙体时,相机缩放并仅显示被选中的墙体(点击绿圈标记的墙后,期望效果如附图所示)。请问如何通过脚本定位相机?我尝试编写了以下MakeCamera函数,传入选中墙体作为targetObject,创建新的正交相机并尝试将其置于墙前看向墙体,但该函数在不同朝向的墙体上均无法正常工作:相机未朝向墙体,且不同方位(左、右、前、后)墙体的相机位置设置错误(例如右侧墙体的相机本该位于墙左侧看向墙体,实际却朝向正前方)。

原代码:

private void MakeCamera(GameObject targetObject, Vector3 normal)
{
    if (targetObject == null)
    {
        Debug.LogError("Target object is not assigned.");
        return;
    }

    if(normal == new Vector3(1,0,0))
    {
        Debug.Log("right");
        //right
    }
    else if(normal == new Vector3(-1, 0, 0))
    {
        Debug.Log("Left");
        //left
    }
    else if(normal == new Vector3(0,0,-1))
    {
        Debug.Log("backward");
        //backward
    }
    else if(normal == new Vector3(0,0,1))
    {
        Debug.Log("forward");
        //forward
    }

    // Create a new GameObject for the camera
    GameObject cameraGameObject = new GameObject("OrthographicCamera");

    // Add a Camera component
    Camera camera = cameraGameObject.AddComponent<Camera>();

    // Set the camera to orthographic mode
    camera.orthographic = true;

    // Set the orthographic size
    camera.orthographicSize = 5;

    // Position the camera with the given offset
    camera.transform.position = targetObject.GetComponent<Collider>().bounds.center + offset ;

    // Make the camera look at the target object
    camera.transform.LookAt(targetObject.GetComponent<Collider>().bounds.center);

    Debug.Log("Orthographic camera created and positioned.");
}
问题分析与解决方案

核心问题点

  • 向量比较精度误差:直接用==比较Vector3会因为浮点数精度问题导致判断失效,比如模型缩放、导入误差会让法线向量出现微小偏差。
  • 相机位置计算逻辑错误:仅给墙体中心加固定偏移,没有结合墙体法线方向,导致相机无法精准处于墙的正前方。
  • 朝向设置不准确:LookAt虽然能让相机看向目标,但正交相机更适合直接设置forward方向,避免不必要的旋转偏差。
  • 固定正交尺寸不合理:固定orthographicSize = 5无法适配不同大小的墙体,会出现墙体显示不全或留白过多的问题。

修正后的代码

private void MakeCamera(GameObject targetObject, Vector3 normal)
{
    if (targetObject == null)
    {
        Debug.LogError("未指定目标物体。");
        return;
    }

    // 归一化法线向量,避免模型缩放导致的长度异常
    normal = normal.normalized;

    // 获取墙体碰撞体的边界信息
    Bounds wallBounds = targetObject.GetComponent<Collider>().bounds;
    Vector3 wallCenter = wallBounds.center;

    // 相机与墙体的距离,可根据需求调整
    float cameraOffsetDistance = 5f;

    // 计算相机位置:从墙体中心沿法线反方向移动指定距离,确保在墙的正前方
    Vector3 cameraPosition = wallCenter - normal * cameraOffsetDistance;

    // 创建相机对象
    GameObject cameraGameObject = new GameObject("OrthographicCamera");
    Camera camera = cameraGameObject.AddComponent<Camera>();

    // 设置为正交模式
    camera.orthographic = true;

    // 动态计算正交尺寸,适配不同大小的墙体
    Vector3 localWallSize = cameraGameObject.transform.InverseTransformVector(wallBounds.size);
    // 取宽高中较大值,留10%余量避免边缘裁切
    camera.orthographicSize = Mathf.Max(localWallSize.y, localWallSize.x) / 2f * 1.1f;

    // 设置相机位置与朝向
    camera.transform.position = cameraPosition;
    // 让相机朝向墙体,forward方向与法线方向一致
    camera.transform.forward = normal;

    Debug.Log("正交相机已创建并定位完成。");
}

关键优化说明

  • 法线归一化:确保法线向量长度为1,避免因模型缩放导致的位置计算偏差。
  • 精准位置计算:通过wallCenter - normal * cameraOffsetDistance让相机始终处于墙体正前方,适配任意朝向的墙体。
  • 动态尺寸适配:根据墙体实际大小计算正交尺寸,保证墙体完整显示在相机视野内。
  • 直接设置朝向:用transform.forward = normal代替LookAt,避免多余旋转,确保相机朝向精准。

额外建议

  • 若需隐藏其他物体,可给目标墙体单独设置图层,修改相机的cullingMask只渲染该图层。
  • 可预先创建相机对象池,避免频繁创建销毁相机带来的性能损耗。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 01:39:52