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

使用Scene2d/Box2d时,如何让PerspectiveCamera适配ExtendViewport?

解决PerspectiveCamera与ExtendViewport配合黑屏及匹配正交视野的问题

嘿,咱们一步步来搞定这个问题。我之前在把PerspectiveCamera和为正交相机设计的Viewport搭配时也踩过类似的坑,下面是具体的解决思路和操作步骤:

1. 核心问题:ExtendViewport默认不兼容PerspectiveCamera

ExtendViewport的update()方法是专门为OrthographicCamera设计的,它会自动计算正交投影矩阵,但对PerspectiveCamera完全不生效——这就是你黑屏的主要原因。我们需要手动接管投影矩阵的计算,模拟出和正交相机一样的视野范围。

手动适配投影矩阵与相机位置

初始化相机和Viewport后,在resize()方法里手动更新透视相机的参数,确保它的视锥体覆盖和原正交相机相同的区域:

// 初始化:传入你原来正交相机用的视口尺寸(比如1920x1080)
PerspectiveCamera camera = new PerspectiveCamera(67, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
ExtendViewport viewport = new ExtendViewport(1920, 1080, camera);

@Override
public void resize(int width, int height) {
    viewport.update(width, height, true);
    
    // 计算模拟正交视野所需的参数
    float virtualWidth = 1920; // 原正交视口宽度
    float virtualHeight = 1080; // 原正交视口高度
    float halfHeight = virtualHeight / 2f;
    float halfWidth = virtualWidth / 2f;
    
    // 根据相机视场角计算相机到视口平面的距离
    float distance = halfHeight / (float)Math.tan(Math.toRadians(camera.fieldOfView / 2f));
    
    // 设置相机位置:让相机在Z轴上,看向视口中心(模拟正交的平行投影效果)
    camera.position.set(halfWidth, halfHeight, distance);
    camera.lookAt(halfWidth, halfHeight, 0);
    
    // 设置合理的近远裁剪面,确保所有内容都在视锥体内
    camera.near = 0.1f;
    camera.far = distance * 2f;
    camera.update();
}

2. 修复Stage渲染的关键:启用深度缓冲+正确设置Batch矩阵

透视相机依赖深度测试来正确渲染层级,而默认情况下Stage不会处理这个,这也是黑屏的常见诱因:

@Override
public void render(float delta) {
    // 必须同时清除颜色缓冲和深度缓冲!
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);
    // 开启深度测试
    Gdx.gl.glEnable(GL20.GL_DEPTH_TEST);
    
    camera.update();
    
    // 手动给Stage的Batch设置透视相机的组合矩阵
    stage.getBatch().setProjectionMatrix(camera.combined);
    
    stage.act(delta);
    stage.draw();
    
    // 如果之后要渲染其他不需要深度测试的内容,可以关闭
    Gdx.gl.glDisable(GL20.GL_DEPTH_TEST);
}

3. 让UI/Stage元素和正交相机下看起来一样大

透视相机的透视效果会让远处的物体看起来更小,如果你想让Stage里的Actor保持和正交相机下相同的视觉大小,可以根据相机距离调整缩放:

// 假设Actor在Z=0平面(Stage默认的Z值)
float scale = camera.position.z / (camera.position.z - actor.getZ());
actor.setScale(scale);

不过这里有个更省心的建议:如果你的游戏是3D场景+2D UI,分开用两个相机会更简单——3D场景用PerspectiveCamera+适配的Viewport,UI单独用OrthographicCamera+ExtendViewport,两者互不干扰,也不用折腾透视适配的问题。

4. 排查黑屏的其他常见点

  • 检查near和far值:如果near设得太大,可能会把近处的UI裁掉;far太小则会把远处的内容排除在视锥体外。
  • 确认Viewport的update()第三个参数centerCamera设为true,保证相机居中。
  • 检查是否有其他代码覆盖了相机的投影矩阵,比如某些渲染逻辑强行重置了Batch的矩阵。

内容的提问来源于stack exchange,提问作者Nick Cardoso

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:39:27