云图三维 连接你·创造的世界 致力于打造国内第一家集查看、建模、装配和渲染于一体的“云端CAD”协作设计平台。
应读者的要求,希望我们成立一个专业的、面向成渝地区的前端开发人员的webgl、Threejs行业QQ交流群,便于大家讨论问题。群里有研究webgl、Threejs大佬哦,欢迎大家加入!——点击链接加入群聊【three.js/webgl重庆联盟群】:jq.qq.com/?_wv=1027&k…
截屏
在浏览器中,有两个有效的功能可以截取屏幕。旧的 canvas.toDataURL
和新的的 canvas.toBlob
很容易想到的一种截取屏幕截图方式
<canvas id="c"></canvas>
<button id="screenshot" type="button">Save...</button>
const elem = document.querySelector('#screenshot');
elem.addEventListener('click', () => {
canvas.toBlob((blob) => {
saveBlob(blob, `screencapture-${canvas.width}x${canvas.height}.png`);
});
});
const saveBlob = (function() {
const a = document.createElement('a');
document.body.appendChild(a);
a.style.display = 'none';
return function saveData(blob, fileName) {
const url = window.URL.createObjectURL(blob);
a.href = url;
a.download = fileName;
a.click();
};
}());
实际测试下来是一张全黑的截图
问题在于,出于性能和兼容性原因,默认情况下,浏览器会在您绘制完 WebGL 画布的绘图缓冲区后清除它。
解决方案是在捕获之前调用渲染代码。
在代码中需要调整一些东西。先分离出渲染代码。
const state = {
time: 0,
};
function render(time) {
time *= 0.001;
function render() {
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
camera.updateProjectionMatrix();
}
cubes.forEach((cube, ndx) => {
const speed = 1 + ndx * .1;
const rot = time * speed;
const rot = state.time * speed;
cube.rotation.x = rot;
cube.rotation.y = rot;
});
renderer.render(scene, camera);
requestAnimationFrame(render);
}
function animate(time) {
state.time = time * 0.001;
render();
requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
现在render
只关心实际渲染,我们可以在捕获画布之前调用它。
const elem = document.querySelector('#screenshot');
elem.addEventListener('click', () => {
render();
canvas.toBlob((blob) => {
saveBlob(blob, `screencapture-${canvas.width}x${canvas.height}.png`);
});
});
效果就正常了
详情案例请参阅threejsfundamentals.org/threejs/thr…
防止画布被清除
假设您想让用户使用动画对象进行绘画。你需要通过preserveDrawingBuffer: true
创建时WebGLRenderer
。这可以防止浏览器清除画布,除此之外three.js 不应该清除画布。
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const renderer = new THREE.WebGLRenderer({
canvas,
preserveDrawingBuffer: true,
alpha: true,
});
renderer.autoClearColor = false;
具体事例可参考:threejsfundamentals.org/threejs/thr…
如果认真地制作绘图程序,这将不是一个解决方案,因为浏览器仍会在我们更改分辨率时清除画布。我们正在根据其显示尺寸更改分辨率。当窗口改变大小时,它的显示大小也会改变。这包括当用户下载文件时,即使在另一个选项卡中,浏览器会添加一个状态栏。它还包括用户转动手机和浏览器从纵向切换到横向的时间。
使画布透明
默认情况下,Three.js 使画布不透明。如果您希望画布在alpha:true
创建时透明WebGLRenderer
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({canvas});
const renderer = new THREE.WebGLRenderer({
canvas,
alpha: true,
});
可以设置premultipliedAlpha,预乘 alpha
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({
canvas,
alpha: true,
premultipliedAlpha: false,
});
Three.js 默认为画布 using premultipliedAlpha: true
但默认为材质输出premultipliedAlpha: false
。
如果您想更好地了解何时以及何时不使用预乘 alpha,
用透明画布设置一个简单的例子。
function makeInstance(geometry, color, x) {
const material = new THREE.MeshPhongMaterial({color});
const material = new THREE.MeshPhongMaterial({
color,
opacity: 0.5,
});
...
添加一些 HTML 内容
<body>
<canvas id="c"></canvas>
<div id="content">
<div>
<h1>Cubes-R-Us!</h1>
<p>We make the best cubes!</p>
</div>
</div>
</body>
以及一些 CSS 将画布放在前面
body {
margin: 0;
}
#C {
width: 100%;
height: 100%;
display: block;
position: fixed;
left: 0;
top: 0;
z-index: 2;
pointer-events: none;
}
#内容 {
font-size: 7vw;
font-family: sans-serif;
text-align: center;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
效果图如下
使您的背景成为three.js 动画
一个常见的问题是如何让一个three.js动画作为网页的背景。
有2个明显的方法。
- 将画布 CSS
position
设置fixed
为 in
#C {
position: fixed;
left: 0;
top: 0;
...
}
基本上可以在前面的示例中看到这个确切的解决方案。只需设置z-index
为 -1,立方体就会出现在文本后面。
这个解决方案的一个小缺点是你的 JavaScript 必须与页面集成,如果你有一个复杂的页面,那么你需要确保你的 Three.js 可视化中的 JavaScript 没有与在页面中做其他事情的 JavaScript 冲突。
- 使用
iframe
例如,在您的网页中插入一个 iframe
<iframe id="background" src="threejs-responsive.html">
<div>
Your content goes here.
</div>
然后设置 iframe 的样式以填充窗口并位于背景中,这与我们上面用于画布的代码基本相同,但我们还需要设置border
为 ,none
因为 iframe 默认具有边框。
#背景 {
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
z-index: -1;
border: none;
pointer-events: none;
}
效果图如下
翻译来源:threejsfundamentals.org/threejs/les…
写在最后
本文介绍了Three.js的截屏相关的内容,截屏在日常工作中是非常常见的需求,希望对你有帮助。
本文发布自 云图三维大前端团队,文章未经授权禁止任何形式的转载。