日期:2021年12月9日标签:ComputerGraphics

Threejs 分屏绘制 #

做三维渲染时,偶尔会有分屏绘制的需求,将从不同角度观察到的场景绘制到屏幕上,类似下面这种。

threejs 分屏绘制

某些本地双人游戏,也是利用了这种分屏机制,例如《双人成行》《胡闹厨房》(在这里,特别向大家推荐《双人成行》这款游戏,真的非常棒)。

本篇文章,讲解如何使用 Threejs 进行分屏绘制。

讲解 Threejs 分屏绘制之前,先了解下 CS 中的两个概念 viewport 和 scissor。

一. viewport 和 scissor #

viewport,中文意,即视口、视窗的意思,scissor 是用剪刀剪、剪刀的意思。

关于viewport的详细解释,可以看这里。简答的说viewport就是摄像机观察到的空间(可以绘制到屏幕上的区域)。

scissor 就是裁剪的意思,可以将 viewport 进行裁剪,绘制 viewport 其中的一块区域,我在 StackExchange 上找到一个关于 viewport 和 scissor 很形象的解释,作者用图片很形象的解释了 viewport、scissor 和窗口大小之间的关系,分为四种不同情况。

在 opengl(webGL) 中裁剪空间的范围是 -1 ~ + 1的。

裁剪空间的X、Y坐标范围

然后,裁剪空间内的图像需要映射到屏幕窗口坐标系。

想像一下,我们的窗口是黑色的背景,在绘制之前使用白色去清除颜色(openGL 中使用 glClearColor 指定清屏颜色)。

  1. 一般情况下,我们使 viewport 和 scissor 覆盖到整个窗口区域。

viewport 与 scissor 覆盖到全部窗口区域

  1. 有时候,我们想将图像绘制到屏幕的某一个区域,此时只需要将viewport设置为某个子区域。

viewport 与 scissor 覆盖到窗口区域的子区域

  1. scissor 也可以取 viewport 的一个子区域。

scissor 也可以取 viewport 的一个子区域

  1. 最后 scissor 也可以比 viewport 范围更大,例如 scissor 覆盖到整个屏幕,但是 viewport 取某个子区域。

scissor 覆盖到整个屏幕, viewport 取屏幕的某一块区域

注意到此时,viewport是一个较小的区域,但是 glClear 影响的却是整个屏幕,因为 glClear 的范围由 scissor 的范围决定。

理解了 viewport 和 scissor,接下来我们使用 Threejs 进行分屏绘制。

二. 分屏绘制 #

需要完整的代码,请戳这里

看一下效果,点击这里大屏查看。

在例子中,使用了两个不同位置的相机,然后利用WebGLRenderer分屏渲染这两个相机。

    renderer.setScissorTest(true); // enable scissor test

    // view1
    scene.background = new THREE.Color("black");
    
    renderer.setViewport(0, 0, halfW, container.clientHeight);
    renderer.setScissor(0, 0, halfW, container.clientHeight);

    renderer.render(scene, camera1);

    // view2
    scene.background = new THREE.Color("gray");

    renderer.setViewport(halfW, 0, container.clientWidth / 2, container.clientHeight);
    renderer.setScissor(halfW, 0, container.clientWidth / 2, container.clientHeight);

    renderer.render(scene, camera2);

首先需要通过 renderer.setScissorTest(true) 开启 scissor test,然后使用 renderer.setViewportrenderer.setScissor分别设置 viewport 和 scissor 的位置,这样就可以进行分屏渲染。

(完)

目录