08.Fullscreen and resizing 全屏和调整大小
介绍
我们的画布目前有一个固定的分辨率800x600
。项目中不一定需要 WebGL 填满整个屏幕,但如果您想要身临其境的体验,填满整屏的体验可能会更好。
首先,我们想让画布占据所有屏幕可用空间。然后,我们需要确保在用户调整窗口大小时它仍然自适应变化视口。最后,我们需要为用户提供一种全屏体验的方法。
设置
入门包含我们在上一课中完成的内容。我们的立方体位于中心,我们可以拖放以移动相机。
适合视口
要使画布完全根据视口变化,那就不能在sizes
变量中使用固定数字了,请使用window.innerWidth
and window.innerHeight
:
// ...
// Sizes
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}
// ...
您可以看到画布现在具有视口的宽度和高度。不幸的是,有一个白色边距和一个滚动条(如果看不到任何滚动条,请尝试滚动)。
原因是浏览器都有默认样式,例如重要的标题<h1>
、带下划线的链接<a/>
、段落之间的空格以及页面上的填充。有很多方法可以解决这个问题,这可能取决于您网站的其余页面。如果您有其他页面的内容,请尽量不要在执行此操作时污染全局样式。
我们将保持样式并使用 CSS 固定画布的位置。
我们的 HTML 加载src/style.css
文件:
<link rel="stylesheet" href="./style.css">
您可以像往常一样编写标准 CSS,页面将自动重新加载。
首先要做的一件好事是使用*
通配符删除所有元素上的margin
和padding
的样式:
*
{
margin: 0;
padding: 0;
}
然后,我们可以将画布固定在左上角,使用它的class webgl
来选择它:
.webgl
{
position: fixed;
top: 0;
left: 0;
}
您不需要在画布上指定width
或者height
因为 Three.js 在您调用renderer.setSize(...)
该方法时已经处理好了。
拖放时,您可能已经注意到上面有一个蓝色轮廓。这主要发生在最新版本的 Chrome 上。要解决这个问题,我们可以简单地在.webgl
添加outline: none
:
.webgl
{
position: fixed;
top: 0;
left: 0;
outline: none;
}
如果你想删除任何类型的滚动,即使是在触摸屏上,你可以在html
,body
上添加overflow: hidden
:
html,
body
{
overflow: hidden;
}
不幸的是,如果调整窗口大小,画布将不会随之改变。
我们需要处理渲染器,让他自适应窗口调整大小。
处理调整大小
要调整画布大小,我们首先需要知道何时调整窗口大小。为此,可以在窗口上监听resize
事件。
添加侦听器resize
,在浏览器的sizes
变量改变之后会自动触发:
window.addEventListener('resize', () =>
{
console.log('window has been resized')
})
现在我们在调整窗口大小时触发了一个函数,我们需要更新代码中的一些东西。
首先,我们必须更新sizes
变量:
window.addEventListener('resize', () =>
{
// Update sizes
sizes.width = window.innerWidth
sizes.height = window.innerHeight
})
其次,我们必须camera
通过更改其aspect
属性来更新纵横比:
window.addEventListener('resize', () =>
{
// ...
// Update camera
camera.aspect = sizes.width / sizes.height
})
当您更改相机属性时,aspect
还需要使用camera.updateProjectionMatrix()
更新投影矩阵。稍后我们将讨论矩阵:
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)
})
您可以根据需要调整窗口大小,画布应覆盖视口而没有任何滚动条或溢出。
处理像素比
我们开发中,有些人可能会看到一种模糊的渲染和边缘形状像楼梯的伪影(称为锯齿),但不是所有人都会看到。如果遇到了这样的问题,那是因为您的屏幕像素比大于1。
像素比对应于软件部分的一个像素单元在屏幕上有多少个物理像素。
一些历史
几年前,所有屏幕的像素比都1
,一切都很好。但是当你仔细观察你的屏幕时,你可以看到那些像素,这限制了图像的精确度和字体的细度。
在这方面做得最多的公司是苹果公司。Apple 看到了机会,开始制造像素比为2
Retina 的屏幕。现在,很多建设者都在这样做,你可以看到像素比更高的屏幕。
虽然这对图像质量来说是件好事,但像素比2
意味着要渲染的像素也要多 4 倍。像素比3
意味着要渲染的像素多 9 倍。
你猜怎么着?最高像素比通常出现在屏幕最小的设备上——移动设备。
包括帧速率。
处理像素比
window.devicePixelRatio
获得您可以使用的屏幕像素比,获得像素比后只需调用renderer.setPixelRatio(...)
更新渲染器的像素比。
您可能只想简单地将设备像素比发送到该方法,但最终会在高像素比设备上遇到性能问题。
像素比大于2
主要是出于营销。你的眼睛几乎看不到2
和3
之间的区别,但它会产生性能问题并更快地耗尽电池。可以做的优化是将像素比限制为2
. 为此,您可以使用Math.min()
:
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
当像素比率发生变化时,有一些技术可以通知我们开发者,但它只涉及拥有多个像素比率不同的屏幕的用户,并且他们通常会在从一个屏幕切换到另一个屏幕时调整窗口大小。这就是为什么我们也只需将此方法添加到resize
回调中:
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))
})
处理全屏
现在我们的画布以正确的像素比例占据了所有可用空间,是时候添加对全屏的支持了。
首先,我们需要决定什么动作会触发全屏模式。它可以是一个 HTML 按钮,但我们案例将使用双击触发全屏。
当双击发生时,我们将切换全屏——这意味着如果窗口不是全屏,双击将启用全屏模式,如果窗口已经全屏,双击将退出全屏模式。
首先,我们需要监听双击事件,我们可以通过dblclick
事件来实现:
window.addEventListener('dblclick', () =>
{
console.log('double click')
})
此事件适用于除 Chrome Android 之外的大多数现代浏览器: https: //developer.mozilla.org/docs/Web/API/Element/dblclick_event
现在我们有了我们的双击事件,我们需要三样东西:
- 一种知道它是否已经全屏的方法
- 进入全屏模式的方法
- 一种退出全屏模式的方法
要知道我们是否已经处于全屏模式,我们可以使用document.fullscreenElement
:
window.addEventListener('dblclick', () =>
{
if(!document.fullscreenElement)
{
console.log('go fullscreen')
}
else
{
console.log('leave fullscreen')
}
})
请求全屏的方法与元素相关联。这是因为您可以选择全屏显示的内容。它可以是整个页面、任何 DOM 元素或<canvas>
.
我们将使用<canvas>
并调用requestFullscreen()
它的方法:
window.addEventListener('dblclick', () =>
{
if(!document.fullscreenElement)
{
canvas.requestFullscreen()
}
else
{
console.log('leave fullscreen')
}
})
退出全屏模式的方法可直接在document
:
window.addEventListener('dblclick', () =>
{
if(!document.fullscreenElement)
{
canvas.requestFullscreen()
}
else
{
document.exitFullscreen()
}
})
您可以通过双击任意位置来切换全屏模式来测试结果。不幸的是,这不适用于 Safari
Safari
浏览器正在花时间支持全屏等正式的简单功能,我们需要使用前缀版本使其适用于document.fullscreenElement
、canvas.requestFullscreen
和document.exitFullscreen
:
window.addEventListener('dblclick', () =>
{
const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement
if(!fullscreenElement)
{
if(canvas.requestFullscreen)
{
canvas.requestFullscreen()
}
else if(canvas.webkitRequestFullscreen)
{
canvas.webkitRequestFullscreen()
}
}
else
{
if(document.exitFullscreen)
{
document.exitFullscreen()
}
else if(document.webkitExitFullscreen)
{
document.webkitExitFullscreen()
}
}
})
一切功能都应该在所有现代浏览器上正常工作,兼容所有浏览器。