ThreeJS——窗口变化自适应渲染
我们在开发的过程中可能会遇到这样一个问题,通过鼠标拖动使浏览器的窗口变化,因为Threejs渲染器的渲染尺寸范围没有跟着变化,所以出现局部空白区域。对于这种情况要做的就是重新获取浏览器窗口新的宽高尺寸,然后通过新的宽高尺寸更新相机Camera和渲染器WebGLRenderer的参数即可。
相机对象Camera本质上就是视图矩阵matrixWorldInverse和投影矩阵projectionMatrix,Threejs渲染场景的时候调用相机对象的视图矩阵和投影矩阵值对顶点进行矩阵变换。
影响视图矩阵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自适应渲染
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;// 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵camera.updateProjectionMatrix ();};
透视投影相机PerspectiveCamera自适应渲染
// onresize 事件会在窗口被调整大小时发生window.onresize=function(){// 重置渲染器输出画布canvas尺寸renderer.setSize(window.innerWidth,window.innerHeight);// 全屏情况下:设置观察范围长宽比aspect为窗口宽高比camera.aspect = window.innerWidth/window.innerHeight;// 如果相机的一些属性发生了变化,需要执行updateProjectionMatrix ()方法更新相机的投影矩阵camera.updateProjectionMatrix ();};
示例代码
<html lang="en"><head><meta charset="UTF-8"><title></title><style>body{margin: 0;overflow: hidden;}</style></head><body><script src="./../js/three.js"></script><script src="./../js/OrbitControls.js"></script><script>/** 创建场景对象Scene* */let scene = new THREE.Scene();let mesh = null// 纹理贴图映射到一个矩形平面上// let geometry = new THREE.PlaneGeometry(250, 250); // 矩形平面let geometry = new THREE.BoxGeometry(150, 150, 150); //立方体// let geometry = new THREE.SphereGeometry(100, 40, 40); //球体/*// TextureLoader创建一个纹理加载器对象,可以加载图片作为几何体纹理let textureLoader = new THREE.TextureLoader();// 执行load方法,加载纹理贴图成功后,返回一个纹理对象TexturetextureLoader.load('./../img/earth.jpg', texture => {let material = new THREE.MeshLambertMaterial({// color: 0x0000ff,// 设置颜色纹理贴图:Texture对象作为材质map属性的属性值side: THREE.DoubleSide,map: texture,// 设置颜色贴图属性值}); // 材质对象Materialmesh = new THREE.Mesh(geometry, material); // 网格模型对象Meshscene.add(mesh); // 网格模型添加到场景中})*//*----------------------------------------------*/// 图片加载器let ImageLoader = new THREE.ImageLoader();// load方法回调函数,按照路径加载图片,返回一个html的元素img对象ImageLoader.load('./../img/earth.jpg', img => {// image对象作为参数,创建一个纹理对象Texturelet texture = new THREE.Texture(img);// 下次使用纹理时触发更新texture.needsUpdate = true;let material = new THREE.MeshLambertMaterial({side: THREE.DoubleSide,map: texture, //设置纹理贴图});mesh = new THREE.Mesh(geometry, material); //网格模型对象Meshscene.add(mesh); //网格模型添加到场景中});/*** 光源设置*///点光源let point = new THREE.PointLight(0xffffff);point.position.set(400, 200, 300);scene.add(point);//环境光let ambient = new THREE.AmbientLight(0x444444);scene.add(ambient);/*** 相机设置*/let width = window.innerWidth; //窗口宽度let height = window.innerHeight;let k = width / height; //窗口宽高比let s = 200;// 创建相机对象let camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);camera.position.set(200, 300, 200); //设置相机位置camera.lookAt(scene.position); //设置相机方向(指向的场景对象)/*** 创建渲染器对象*/let renderer = new THREE.WebGLRenderer();renderer.setSize(width, height);//设置渲染区域尺寸renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色document.body.appendChild(renderer.domElement); // body元素中插入canvas对象//执行渲染操作 指定场景、相机作为参数window.onresize = function() {renderer.setSize(window.innerWidth, window.innerHeight)k = window.innerWidth / window.innerHeightcamera.left = -s*kcamera.right = s*kcamera.top = scamera.bottom = -scamera.updateProjectionMatrix()};let T0 = new Date()function renderModle() {let T1 = new Date()let t = T1 - T0T0 = T1requestAnimationFrame(renderModle)renderer.render(scene, camera)mesh.rotateY(0.0001 * t)}renderModle()</script></body></html>
示例图片
