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

Unity WebGL App在Bootstrap模态框隐藏时出现"Screen position out of view frustum"错误的解决方法

嘿,这个问题我太熟了!之前帮好几个做Unity WebGL嵌入Bootstrap模态框的开发者解决过,本质是当模态框被display:none隐藏时,Unity的容器尺寸会被压缩到0×0,这时候相机的视锥体计算就会彻底混乱,抛出那个烦人的"Screen position out of view frustum"错误。下面给你几个实用的解决方案,按优先级排序:

方案1:隐藏时暂停渲染,显示时恢复(最推荐)

这是最合理的做法——既然模态框看不见,干脆暂停Unity的渲染,既解决错误又节省浏览器性能。

  • 第一步,在网页端监听Bootstrap模态框的显示/隐藏事件,同时保存Unity实例的引用:

    // 假设你的模态框ID是unityModal
    const unityModal = document.getElementById('unityModal');
    let unityInstance = null;
    
    // Unity加载完成后保存实例(用Unity默认的Progress回调)
    function UnityProgress(instance, progress) {
      if (progress === 1) {
        window.unityInstance = instance;
      }
    }
    
    // 模态框隐藏时暂停渲染
    unityModal.addEventListener('hidden.bs.modal', () => {
      if (window.unityInstance) {
        // 给Unity发送消息,让内部暂停渲染
        window.unityInstance.SendMessage('GameManager', 'ToggleRendering', false);
        // 也可以直接调用WebGL API暂停整个实例
        // window.unityInstance.Pause();
      }
    });
    
    // 模态框显示时恢复渲染并更新尺寸
    unityModal.addEventListener('shown.bs.modal', () => {
      if (window.unityInstance) {
        window.unityInstance.SendMessage('GameManager', 'ToggleRendering', true);
        // 恢复实例
        // window.unityInstance.Resume();
        // 强制Unity更新容器尺寸,避免显示异常
        window.unityInstance.Module.resize();
      }
    });
    
  • 第二步,在Unity里写一个简单的GameManager脚本,接收网页发来的消息控制渲染:

    using UnityEngine;
    
    public class GameManager : MonoBehaviour
    {
      public Camera mainCamera;
      // 如果有多个相机,可以用数组批量控制
      // public Camera[] allCameras;
    
      public void ToggleRendering(bool enable)
      {
        mainCamera.enabled = enable;
        // 批量控制多个相机的写法
        // foreach(var cam in allCameras) cam.enabled = enable;
        // 也可以配合时间缩放暂停游戏逻辑(可选)
        // Time.timeScale = enable ? 1 : 0;
      }
    }
    
方案2:替换display:none,用其他方式隐藏模态框

如果不想暂停Unity渲染,可以修改Bootstrap模态框的隐藏逻辑,让容器保持原有尺寸,只是移出可视区域:

  • 先自定义一个隐藏样式:

    .modal.hidden-offscreen {
      display: block !important;
      visibility: hidden;
      position: absolute;
      top: -9999px;
      left: -9999px;
    }
    
  • 然后修改模态框的显示/隐藏逻辑,不用Bootstrap默认的hide()方法,而是切换自定义类:

    const unityModal = document.getElementById('unityModal');
    
    // 自定义隐藏方法
    function hideUnityModal() {
      unityModal.classList.add('hidden-offscreen');
    }
    
    // 自定义显示方法
    function showUnityModal() {
      unityModal.classList.remove('hidden-offscreen');
      // 显示后强制更新Unity容器尺寸
      if (window.unityInstance) {
        window.unityInstance.Module.resize();
      }
    }
    

这种方法的缺点是Unity依然在后台渲染,会占用额外资源,适合必须保持游戏运行的场景。

方案3:Unity内部修复视锥体异常

如果上面的方法都不适用,可以在Unity端监听相机状态,当检测到视锥体异常时强制修正参数:

using UnityEngine;

public class CameraFrustumFix : MonoBehaviour
{
    private Camera _cam;
    private float _originalAspect;
    private float _originalFov;

    void Start()
    {
        _cam = GetComponent<Camera>();
        _originalAspect = _cam.aspect;
        _originalFov = _cam.fieldOfView;
    }

    void Update()
    {
        // 检测宽高比是否异常(比如容器尺寸为0导致的NaN或极小值)
        if (float.IsNaN(_cam.aspect) || _cam.aspect <= 0.001f)
        {
            // 恢复初始的宽高比和视野参数
            _cam.aspect = _originalAspect;
            _cam.fieldOfView = _originalFov;
        }
    }
}

这个方法属于“治标”,只能抑制错误日志,还是推荐结合方案1一起使用。

内容的提问来源于stack exchange,提问作者Patrick Münster

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:23:10