Three.js 快速入门教程【三】渲染器
系列文章目录
Three.js 快速入门教程【一】开启你的 3D Web 开发之旅
Three.js 快速入门教程【二】透视投影相机
Three.js 快速入门教程【三】渲染器
Three.js 快速入门教程【四】三维坐标系
Three.js 快速入门教程【五】动画渲染循环
Three.js 快速入门教程【六】相机控件 OrbitControls
Three.js 快速入门教程【七】常见几何体类型
文章目录
- 系列文章目录
- 一、前言
- 二、创建渲染器(WebGLRenderer)
- 三、设置背景色和透明度
- 四、设置渲染器的像素比
- 五、设置渲染区域尺寸
- 六、渲染器渲染生成画布(canvas)
- 七、画布添加到页面
- 八、响应式处理
- 九、释放资源
- 十、截屏
- 十一、牛刀小试
- 总结
一、前言
在Three.js的世界里,渲染器(Renderer)就像一位技艺高超的魔术师,负责将抽象的3D数据转化为屏幕上跃动的视觉盛宴。其中,WebGLRenderer 是 Three.js 中用于在网页上渲染 3D 场景最常用渲染器,本文将带你逐步了解如何使用 WebGLRenderer。
二、创建渲染器(WebGLRenderer)
new THREE.WebGLRenderer(parameters)
其中,parameters 是一个可选的配置对象,包含了渲染器的各种配置选项。
省略参数:
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();
设置参数:
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer({
alpha: true,//开启渲染器画布的透明度通道
antialias: true, //启用抗锯齿功能
powerPreference: "high-performance" // 高性能模式
});
parameters 常用参数:
参数名 | 类型 | 说明 | 默认值 |
---|---|---|---|
alpha | Boolean | 渲染器的画布是否包含一个透明度通道。如果设置true这意味着你可以将渲染器的背景设置为透明,从而使网页的背景透过画布显示出来 | false |
antialias | Boolean | 是否启用抗锯齿功能。抗锯齿可以使渲染的图形边缘更加平滑,减少锯齿状的外观,但可能会降低一些性能。 | false |
canvas | HTMLCanvasElement | 指定渲染器使用的 元素。如果不提供该参数,渲染器会自动创建一个新的 元素 | _ |
powerPreference | String | 指定渲染器的性能偏好,“default”:默认设置,由浏览器决定使用何种性能模式。“high-performance”:优先使用高性能模式,适合需要处理复杂场景的情况,但可能会消耗更多的电量。“low-power”:优先使用低功耗模式,适合对性能要求不高的场景,以节省电量。 | default |
precision | String | 指定着色器的精度,“highp”:高精度,适合大多数情况,但在一些旧设备上可能不支持。“mediump”:中精度,在大多数设备上都能正常工作。“lowp”:低精度,可能会导致颜色和位置的计算出现误差,但可以提高性能。 | highp |
preserveDrawingBuffer | Boolean | 是否保留画布的绘制缓冲区,如果设置为true允许你使用 canvas.toDataURL() 等方法将画布内容保存为图像。但这可能会降低性能,因为需要额外的内存来保存缓冲区。 | false |
不通过构造函数传入配置,也可以通过渲染器属性设置
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();
//启用抗锯齿功能
renderer.antialias = true,
三、设置背景色和透明度
renderer.setClearColor(color:Integer|String|THREE.Color,alpha: Float )
设置渲染器颜色和透明度,第一个参数颜色值,第二个参数透明度
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer({
alpha: true,//开启渲染器画布的透明度通道
});
//设置黑色背景和透明度0.6
renderer.setClearColor(0x000000, 0.6);
四、设置渲染器的像素比
renderer.setPixelRatio(devicePixelRatio:Number )
renderer.setPixelRatio() 方法用于设置渲染器的像素比,像素比决定了渲染的分辨率。在不同设备上,屏幕的物理像素和 CSS 像素的比例可能不同。例如,在视网膜屏幕(如苹果的 Retina 显示屏)上,一个 CSS 像素可能对应多个物理像素。通过设置合适的像素比,可以让渲染的 3D 场景在高分辨率屏幕上显示得更加清晰和锐利。
// 设置渲染器的像素比为设备的像素比
renderer.setPixelRatio(window.devicePixelRatio);
五、设置渲染区域尺寸
renderer.setSize(width:Number, height:Number);
//设置three.js渲染区域的尺寸宽1000px,高600px
renderer.setSize(1000, 600);
一般设置为窗口宽高
// 设置画布尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
六、渲染器渲染生成画布(canvas)
renderer.render()
调用render()方法将生成一个canvas画布并把3d场景渲染到画布中
//执行渲染操作
renderer.render(scene, camera);
七、画布添加到页面
render.domElement 获取canvas元素
上一步生成的canvas是一个HTML元素,需要插入到页面dom才能显示3D场景
通过render.domElement属性可获取到canvas
1、canvas插入页面body上(整个页面显示3D)
document.body.appendChild(renderer.domElement);
2、也可以插入任意HTML元素中 (局部显示3D)
<div id="container"></div>
document.getElementById('container').appendChild(renderer.domElement);
八、响应式处理
当窗口尺寸变化需要同步改变渲染区域大小从而保持3D场景响应式,同时不要忘记重新设置相机的宽高比
window.addEventListener('resize', () => {
//重新设置渲染区域大小
renderer.setSize(window.innerWidth, window.innerHeight);
//重新设置相机宽高比
camera.aspect = window.innerWidth / window.innerHeight;
//更新相机投影矩阵,改变相机参数需要调用才能生效
camera.updateProjectionMatrix();
});
性能优化建议:可以加个防抖处理,防止频繁调用
九、释放资源
离开页面,销毁渲染器释放资源
// 销毁时释放资源
renderer.dispose();
renderer.forceContextLoss();
renderer.domElement = null;
十、截屏
由上述我们知道3D渲染区域实际上是一个画布(canvas),而画布toDataURL方法可以把页面内容生成图片导出。
//导出前需要重新渲染,防止导出空白图片
renderer.render(scene, camera);
//截屏
renderer.domElement.toDataURL('image/png');
十一、牛刀小试
实现一个3D场景小案例:要求渲染层透明可看见页面底部背景图,支持窗口响应式、支持截屏功能。
以vue3为代码示例:
<template>
<div class="container">
<!-- 工具栏 -->
<div class="toolbar">
<button class="screenshot" @click="handleScreenshot">截图</button>
</div>
<!-- 3D区域 -->
<div ref="threeViewRef" class="three-view"></div>
</div>
</template>
<script setup>
import { nextTick, onMounted, ref } from "vue";
import * as THREE from "three";
//引入相机控制器
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
//3d区域容器
const threeViewRef = ref();
//3d区域宽
const width = ref();
//3d区域高
const height = ref();
onMounted(() => {
//设置宽高
width.value = threeViewRef.value.clientWidth;
height.value = threeViewRef.value.clientHeight;
//初始化three.js
init();
});
onUnmounted(() => {
// 离开页面释放资源
if (renderer) {
renderer.dispose();
renderer.forceContextLoss();
renderer.domElement = null;
}
});
//渲染器
let renderer = null;
//场景
let scene = null;
//相机
let camera = null;
//初始化
const init = () => {
//创建场景
scene = new THREE.Scene();
//创建一个正方体
const geometry = new THREE.BoxGeometry(10, 10, 10);
//创建一个基础材质
const material = new THREE.MeshBasicMaterial({ color: "#409EFF" });
//创建一个网格对象
const mesh = new THREE.Mesh(geometry, material);
//设置网格对象位置
mesh.position.set(0, 0, 0);
//添加到场景中
scene.add(mesh);
//创建相机
camera = new THREE.PerspectiveCamera(
75,
width.value / height.value,
0.1,
1000
);
//设置相机位置
camera.position.set(0, 10, 30);
//相机默认看向网格对象
camera.lookAt(mesh.position);
//创建渲染器
renderer = new THREE.WebGLRenderer({
alpha: true, //开启渲染器画布的透明度通道
});
//设置黑色背景和透明度0.6
renderer.setClearColor(0x000000, 0.6);
//设置渲染器尺寸为父元素宽高
renderer.setSize(width.value, height.value);
// 设置渲染器的像素比为设备的像素比
renderer.setPixelRatio(window.devicePixelRatio);
//将渲染器的 DOM 元素添加到父元素中
threeViewRef.value.appendChild(renderer.domElement);
// 新建一个相机控件
const controls = new OrbitControls(camera, renderer.domElement);
// 启用阻尼(惯性效果)
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// 动画循环
function animate() {
// 定时刷新
requestAnimationFrame(animate);
// 更新控制器,必须调用以应用阻尼效果
controls.update();
//重新渲染
renderer.render(scene, camera);
}
// 执行动画
animate();
//响应式处理
window.addEventListener("resize", () => {
nextTick(() => {
if (threeViewRef.value) {
width.value = threeViewRef.value.clientWidth;
height.value = threeViewRef.value.clientHeight;
//重新设置渲染区域大小
renderer.setSize(width.value, height.value);
//重新设置相机宽高比
camera.aspect = width.value / height.value;
//更新相机投影矩阵,改变相机参数需要调用才能生效
camera.updateProjectionMatrix();
}
});
});
};
//截屏
const handleScreenshot = () => {
//导出前需要重新渲染,防止导出空白图片
renderer.render(scene, camera);
// 将 canvas 内容转换为 Base64 编码的图片数据
const dataURL = renderer.domElement.toDataURL("image/png");
// 创建一个链接元素
const link = document.createElement("a");
link.href = dataURL;
link.download = "threejs_scene.png";
// 模拟点击链接进行下载
link.click();
};
</script>
<style scoped>
.container {
width: 100vw;
height: 100vh;
display: flex;
flex-direction: column;
background-color: #f2f2f2;
padding: 10px;
box-sizing: border-box;
}
.toolbar {
height: 60px;
background-color: #fff;
display: flex;
align-items: center;
border-radius: 10px;
padding-left: 10px;
box-sizing: border-box;
}
.screenshot {
background-color: rgb(35, 119, 230);
color: #fff;
}
.three-view {
margin-top: 12px;
flex: 1;
height: 0;
background: url("https://img0.baidu.com/it/u=1288055865,1854912761&fm=253&fmt=auto&app=138&f=JPEG?w=1204&h=800")
no-repeat center/100% 100%;
border-radius: 10px;
}
</style>
运行效果:
需要注意的是:截屏前必须重新调用renderer.render(scene, camera)更新画布内容,防止导出空白图片。
总结
通过本文的学习,相信你已经掌握了Three.js渲染器的核心用法。要记住,优秀的渲染配置需要在画面质量与性能之间找到最佳平衡点。建议在实际项目中通过Chrome Performance面板进行实时性能分析,找到最适合你项目的配置方案。
更多three.js入门知识点请关注该系列教程后续的更新。