携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第4天,点击查看活动详情 >>
前言
这篇文章尝试去说明如何让ThreeJs创建的场景适应各种变化,为了方便写代码,本文里对于扩展对象的引用将会采用module的方式直接引入,不再演示如何进行去模块化改造。
前期准备
利用之前的学习笔记,快速构建一个场景,在场景中放置立方体,添加光源,代码较多,所以用代码片段的方式进行引入
下面将利用当前构造立方体的代码,进行响应式场景改造 首先我们通过设置css的方式,让canvas元素充满屏幕,canvas默认是行内块,行内块在结尾有空格,所以需要设置为块元素
#c {
width: 100%;
height: 100%;
display: block;
}
这个时候立方体他,不清晰了,而且拉伸了
解决立方体被拉伸
立方体被拉伸是因为相机宽高比和渲染立方体的canvas宽高比不一致导致的,这里需要设置一下
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const fov = 75;
const aspect = window.innerWidth/ window.innerHeight; // 相机默认值
const near = 0.1;
const far = 1000;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
camera.position.z = 2;
+ camera.aspect = canvas.clientWidth / canvas.clientHeight;
+ camera.updateProjectionMatrix();
这样拉伸变形就处理好了,看起来像一个正方形了
解决锯齿
canvs是有两个宽高的,一个就是css设置的宽高,也叫画布宽高,还有一个,是canvas内像素的数量,就好像img标签的宽高属性一样,img同样也有两个宽高。
一个canvas的内部尺寸,它的分辨率,学名被叫做绘图缓冲区(drawingbuffer)尺寸。这里显然是因为canvas分辨率和他的宽高不一致导致的,这里就需要把他们处理成一致的。
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render(time) {
time *= 0.001; // 将时间单位变为秒
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
.........
高分屏处理
- 不做任何处理,因为threejs会自动帮我们做这样的工作。
renderer.setPixelRatio(window.devicePixelRatio);让渲染器适配高分屏物理分辨率,这样做会导致你每次调用rerender.setSize的时候,都会自动乘以像素比- 在检测canvas宽高的时候处理
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement
const pixelRatio = window.devicePixelRatio
const width = canvas.clientWidth * (pixelRatio | 1)
const height = canvas.clientHeight * (pixelRatio | 1)
const needResize = canvas.width !== width || canvas.height !== height
if (needResize) {
renderer.setSize(width, height, false)
}
return needResize
}
完整代码以代码片段的方式引入