Three.js浏览器窗口尺寸变化(自适应渲染)
本文是Three.js电子书的9.2节
开发的过程中你可能会遇到这样一个问题,通过鼠标拖动使浏览器的窗口变大,因为Threejs渲染器的渲染尺寸范围没有跟着变化,出现局部空白区域。对于这种情况要做的就是重新获取浏览器窗口新的宽高尺寸,然后通过新的宽高尺寸更新相机Camera和渲染器WebGLRenderer的参数即可。
视图矩阵.matrixWorldInverse
和投影矩阵.projectionMatrix
所谓相机对象Camera本质上就是视图矩阵.matrixWorldInverse
和投影矩阵.projectionMatrix
,Threejs渲染场景的时候调用相机对象的视图矩阵和投影矩阵值对顶点进行矩阵变换。
上节课讲解过正投影相机OrthographicCamera和透视投影相机PerspectiveCamera,其实对相机对象一些参数的设置本质上就是设置相机对象的视图矩阵.matrixWorldInverse
和投影矩阵.projectionMatrix
属性,因为Threejs渲染的时候会通过你设置的相机参数按照一定的算法计算出来投影和视图矩阵值,至于如何计算的,如果你想深入研究,你可以学习计算机图形学或者查看OrthographicCamera和PerspectiveCamera类封装的代码。如果你不想深入研究,只要知道相机参数会影响视图矩阵和投影矩阵就行,至于内部如何影响的可以当成黑箱。
影响视图矩阵.matrixWorldInverse
计算的相关代码,无论透视投影相机还是正投影相机都一样。
camera.position.set(200, 300, 200); //设置相机位置
camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
影响投影矩阵.projectionMatrix
计算相机参数的相关代码
// 正投影相机对象
var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
// 透视投影相机对象
var camera = new THREE.PerspectiveCamera(60, width / height, 1, 1000);
正投影相机OrthographicCamera自适应渲染
比如全屏渲染的时候,为了适应窗口的大小变化,要重新设置相机对象和渲染器对象的参数,不需要在渲染函数render
中周期性更新,只需要通过窗口事件window.onresize
来触发一个函数,然后在函数中更新相机Camera
和渲染器WebGLRenderer
的参数。
渲染区域变化了,要通过Three.js渲染器.setSize()
方法重置渲染器渲染尺寸。
// onresize 事件会在窗口被调整大小时发生
window.onresize=function(){
// 重置渲染器输出画布canvas尺寸
renderer.setSize(window.innerWidth,window.innerHeight);
// 重置相机投影的相关参数
k = window.innerWidth/window.innerHeight;//窗口宽高比
camera.left = -s*k;
camera.right = s*k;
camera.top = s;
camera.bottom = -s;
// 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
// 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
// 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
camera.updateProjectionMatrix ();
};
渲染区域尺寸变化,相机的相关参数自然也需要变化,改变相机的参数后,注意需要执行相机对象.updateProjectionMatrix ()
方法更新相机对象的投影矩阵.projectionMatrix
,之所以需要手动更新,是因为Threejs为了提高渲染效率,Threejs系统每次执行渲染器WebGLRenderer
渲染方法.rener()
的时候不会读取相机相关的参数重新计算一次投影矩阵.projectionMatrix
,Threejs系统只会首次渲染的时候计算一次投影矩阵,所以当你改变影响相机投影矩阵的属性,自然需要调用.updateProjectionMatrix ()
更新相机对象的投影矩阵.projectionMatrix
。
透视投影相机PerspectiveCamera自适应渲染
// onresize 事件会在窗口被调整大小时发生
window.onresize=function(){
// 重置渲染器输出画布canvas尺寸
renderer.setSize(window.innerWidth,window.innerHeight);
// 全屏情况下:设置观察范围长宽比aspect为窗口宽高比
camera.aspect = window.innerWidth/window.innerHeight;
// 渲染器执行render方法的时候会读取相机对象的投影矩阵属性projectionMatrix
// 但是不会每渲染一帧,就通过相机的属性计算投影矩阵(节约计算资源)
// 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
camera.updateProjectionMatrix ();
};
Three.js自适应渲染不一定就是窗口变化,本质上还是你要渲染的区域宽高尺寸变化了。