使用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
相关产品推荐
相关产品推荐

