开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第10天,点击查看活动详情
场景
当这个立方体的场景中,虽然看到立方体是正常的场景,但是仔细放大的时候,发现立方体的直线没有水平或者垂直。如图下:
1.锯齿
1.1抗锯齿(AA)
根据上图,发现这些直线还是没有完全水平或垂直。所以我们采用**抗锯齿(AA)**的技术来解决这个问题。
我们首先可以通过向WebGLRenderer构造函数传递一个新参数来启用抗锯齿,然后采用antialias:true来开启抗锯齿,来编写开启抗锯齿。
function createRenderer(){ //添加开启抗锯齿
const renderer = new WebGLRenderer({antialias:true});
renderer.physicallyCorrectLights = true;
return renderer;
}
开启抗锯齿之后,效果图:
1.2多重采样抗锯齿(MSAA)
其实抗锯齿就是内置的WebGL方法执行的。MSAA不是优先的解决方案,就算你启用了抗锯齿(AA),有一些场景还是显示锯齿。但是有些场景为多个立方体、很多线条的场景中是很难消除混叠的。不只是这个MSAA,也有其他抗锯齿技术,比如:SMAA、FXAA等。
2.处理自动调整浏览器的窗口大小
2.1侦听resize浏览器窗口上的事件
我们需要某种方式来监听浏览器,所以我们想要侦听调整大小事件。可以采用resize事件来触发,就是说当它们调整浏览器窗口大小时,resize事件将触发。
任何HTML元素上的各种事件,例如说click、scroll、keypress等等。
(1)当用户点击的时候,click事件将触发。
(2)当用户旋转滚轮的时候,scroll事件将触发。
(3)当用户调整浏览器窗口大小的时候,resize事件将触发。
注:resize事件侦听器必须要附加到全局window对象
测试:addEventListener和resize事件在浏览器控制台中来测试
function onResize(){
console.log('You resized the browser window!');
}
window.addEventListener('resize',onResize);
可以把这些以上的代码粘贴到浏览器控制台。
当在测试中,用鼠标拖动窗口来调整浏览器的大小都会导致resize事件来触发。
当调整窗口大小的时候,发现onResize()方法会被多次调用。但是resize事件已触发十次或更多次,可以考虑使用loadsh之_.throttle类的节流函数来防止过于频繁地调用。
2.2扩展Resizer类
首先在加载时,设置初始大小,然后在调整浏览器的大小发生变化时再次调用。因此,在我们的场景加载时调用一次:
在Resizer.js文件里,把自动调整大小代码到setSize函数中并在加载时调用它,设置事件监听器。
const setSize = (container,camera,renderer)=>{
// 设置相机的宽高比
camera.aspect = container.clientWidth / container.clientHeight;
// 更新相机的截锥
camera.updateProjectionMatrix();
// 更新渲染器和画布的大小
renderer.setSize(container.clientWidth,container.clientHeight);
// 设置像素比率(用于移动设备)
renderer.setPixelRatio(window.devicePixelRatio);
};
class Resizer{
constructor(container,camera,renderer){
// 在负载上设置初始大小
setSize(container,camera,renderer);
// 添加一个事件侦听器,并setSize在事件触发时再次调用。
window.addEventListener('resize',()=>{
// 如果发生大小调整,请再次设置大小
setSize(container,camera,renderer);
});
}
}
export { Resizer };
当调整窗口大小的时候,立方体就会变形,包括压扁和拉伸,效果图:
其实它只有在画布中绘制了一个帧,当画布被调整大小时,那么立方体就会变形。
2.3创建一个onResize钩子
当每一次触发调整大小事件时我们都需要生成一个新的帧。我们需要调用的是Workd.render之后setSize,在事件监听器Resizer类。要避免整个World类传递给Resizer。我们将创建一个Resizer.onResize钩子。
class Resizer {
constructor(container, camera, renderer){
// 在负载上设置初始大小
setSize(container, camera, renderer);
windows.addEventListener('resize',()=>{
//如果发生大小调整,请再次设置大小
setSize(container, camera, renderer);
//执行任何自定义操作
this.onResize();
});
}
onResize(){}
}
其实.onResize是一个空方法,我们可以从Resizer类外部自定义。
2.4Resizer.onResize在世界中自定义
在World.js中,.onResize方法用一个新的调用World.render。
onstructor(container){
camera = createCamera();
scene = createScene();
renderer = createRenderer();
container.append(renderer.doElement);
const cube = crateCube();
const light = createLights();
scene.add(cube, light);
const resizer = new Resizer(container, camera, renderer);
//添加调用World.render
resizer.onResize = () =>{
this.render();
}
}
这样自动调整大小就完成了。
3.练习
(1)和(2)为合并,需要处理启用和禁用抗锯齿,看看它们有什么不同?
在WebGLRenderer构造函数中(antinalias)把true改为false。
//启用抗锯齿
const renderer = new WebGLRenderer({antinalias:true});
以上的代码例子,启用了抗锯齿,来看看这个效果图:
可以看到立方体边缘出现有直线或垂直。
//禁用抗锯齿
const renderer = new WebGLRenderer({antinalias:false})
以上的代码例子,禁用了抗锯齿,来看看这个效果图:
根据上面的两个图,发现立方体边缘还是有所不同的,该图的立方体边缘是没有直线或者垂直。
(3)和(4)首先把部分代码改为注释。
// 设置调整大小及onResize钩子
resizer.onResize = () =>{
this.render();
};
当随着浏览器的窗口调整大小,就会发现立方体就会变形,拉伸或缩短,效果图: