前言
我们的画布现在是一个固定的尺寸800x600
,并没有撑满整个网页。如果可以撑满整个屏幕的话,势必会带来更有沉浸感的体验。
在实际应用时,并不是任何时候都需要让画布撑满屏幕,请根据需求来设置。
准备工作
让我们先拿出上一小节最后完成的项目代码,在画布中间有一个立方体,我们可以使用鼠标点击拖动来旋转相机。
适配网页可视区尺寸
要让画布完美的匹配网页可视区的尺寸,我们先通过window.innerWidth
和window.innerHeight
来获得网页可视区的宽和高,并赋值给sizes
对象:
// ...
// Sizes
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}
// ...
我们可以看到画布现在几乎
已经撑满了可视区。但四周还有空白并且出现了滚动条。这是因为浏览器有一些默认的CSS样式设定,比如内边距和外边距。我们可以通过添加样式来调整一下。在index.html文件中添加<style>
标签,样式设置如下
<style>
html,body{
margin: 0;
padding: 0;
}
</style>
现在WebGL画布已经撑满了可视区,不过当我们缩放窗口时,画布仍然保持初始的可视区尺寸,我们需要监听窗口的resize事件来持续更改画布尺寸。
监听窗口Resize事件
首先我们要添加监听窗口的resize事件:
window.addEventListener('resize', () =>
{
console.log('window has been resized')
})
现在,在网页窗口发生缩放时我们都会收到通知,接着我们在每次收到通知时都重新获取一下网页可视区的大小并更新sizes对象
window.addEventListener('resize', () =>
{
// Update sizes
sizes.width = window.innerWidth
sizes.height = window.innerHeight
})
我们在创建相机的时候设置过一个宽高比对不对?也要根据最新的画布尺寸重新设置
window.addEventListener('resize', () =>
{
// ...
// Update camera
camera.aspect = sizes.width / sizes.height
})
当我们更改了像aspect
这样的相机属性时,还需要使用camera.Updatejectionmatrix()
来更新投影矩阵。
window.addEventListener('resize', () =>
{
// ...
camera.updateProjectionMatrix()
})
最后别忘了更新渲染器renderer的尺寸
window.addEventListener('resize', () =>
{
// ...
// Update renderer
renderer.setSize(sizes.width, sizes.height)
})
以下是全部代码
window.addEventListener('resize', () =>
{
// Update sizes
sizes.width = window.innerWidth
sizes.height = window.innerHeight
// Update camera
camera.aspect = sizes.width / sizes.height
camera.updateProjectionMatrix()
// Update renderer
renderer.setSize(sizes.width, sizes.height)
})
最终我们获得了一个可以根据窗口的大小,自动调整尺寸的Three.js画布。
处理像素比
很多高清显示屏,尤其是移动设备上的显示屏,一个显示单元往往具有多个物理像素,这就是像素比。比如第一代iPhone4的Retina高清显示屏的像素比就是2,这为我们带来了更加细致入微的视觉体验,但无疑也会消耗更多的性能,当性能消耗过大时,我们的动画和渲染也就会变慢,俗称掉帧。
我们可以通过window.devicePixelRatio
来获取当前设备的像素比,同时通过调用渲染器的renderer.setPixelRatio(...)
方法来使渲染器根据像素比渲染画面。但这样做过于草率了,就像前面说的,更大的像素比意味着更加消耗性能,而当像素比大于2的时候,其实肉眼已经很难看出来差别了。所以我们最好做一个限制。我们使用Math.min
方法来使渲染器像素比不会超过2。
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
加入处理像素比的最终代码:
window.addEventListener('resize', () =>
{
// Update sizes
sizes.width = window.innerWidth
sizes.height = window.innerHeight
// Update camera
camera.aspect = sizes.width / sizes.height
// Update renderer
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
})
使网页全屏
现在我们的画布已经撑满了网页可视区,不过依然能看见浏览器的导航栏,系统菜单等,如果要获得更进一步的沉浸式体验,最好是把这些和三维世界无关的东西统统去掉。还好浏览器给我们提供了全屏的方法,我们可以设置以下和全屏有关的规则
- 双击网页任意区域进入全屏状态
- 在全屏状态下双击或按下ESC键退出全屏
我们可以通过添加dblclick
来捕获鼠标双击的消息,然后在这个消息中处理网页全屏
window.addEventListener('dblclick', () =>
{
console.log('double click')
})
逻辑很简单
我们通过document.fullscreenElement
来判断当前是否已经是全屏状态了,如果不是(false
),则进入全屏。如果是(true
),则退出全屏。
把上面这句话换成Javascript:
window.addEventListener('dblclick', () =>
{
if(!document.fullscreenElement)
{
canvas.requestFullscreen()
}
else
{
document.exitFullscreen()
}
})
注意:主流的浏览器都支持双击事件以及网页全屏的方法,但仍然有一小部分浏览器不支持。