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方法,加载纹理贴图成功后,返回一个纹理对象Texture
textureLoader.load('./../img/earth.jpg', texture => {
let material = new THREE.MeshLambertMaterial({
// color: 0x0000ff,
// 设置颜色纹理贴图:Texture对象作为材质map属性的属性值
side: THREE.DoubleSide,
map: texture,// 设置颜色贴图属性值
}); // 材质对象Material
mesh = new THREE.Mesh(geometry, material); // 网格模型对象Mesh
scene.add(mesh); // 网格模型添加到场景中
})*/
/*----------------------------------------------*/
// 图片加载器
let ImageLoader = new THREE.ImageLoader();
// load方法回调函数,按照路径加载图片,返回一个html的元素img对象
ImageLoader.load('./../img/earth.jpg', img => {
// image对象作为参数,创建一个纹理对象Texture
let texture = new THREE.Texture(img);
// 下次使用纹理时触发更新
texture.needsUpdate = true;
let material = new THREE.MeshLambertMaterial({
side: THREE.DoubleSide,
map: texture, //设置纹理贴图
});
mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
scene.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.innerHeight
camera.left = -s*k
camera.right = s*k
camera.top = s
camera.bottom = -s
camera.updateProjectionMatrix()
};
let T0 = new Date()
function renderModle() {
let T1 = new Date()
let t = T1 - T0
T0 = T1
requestAnimationFrame(renderModle)
renderer.render(scene, camera)
mesh.rotateY(0.0001 * t)
}
renderModle()
</script>
</body>
</html>
示例图片