Three.js加载三维(.gbl)模型
近期有个项目中需要实现在页面中加载出三维模型并有旋转的动画展示 ,毫无疑问,当谈到在Web上呈现引人入胜的三维体验时,Three.js是一个无可替代的工具。接下来就用three.js来简单的实现下加载三维模型的需求。
-
- 安装three.js
npm install three
-
- 创建场景
const planeBox = document.querySelector('.planeBox')!;
const {w, h} = getSize(planeBox);
const scene = new THREE.Scene();
-
- 创建相机
const camera = new THREE.PerspectiveCamera(45, w / h, 0.1, 20);
camera.position.set(0, 0, 1);
-
- 创建渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(w, h);
planeBox.appendChild(renderer.domElement);
-
- 创建控制器
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.minDistance = 1;
controls.maxDistance = 10;
-
- 加载三维模型
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
new GLTFLoader().load("/B2.glb", (gltf) => {
gltfs = gltf;
gltfs.scene.scale.set(0.02, 0.02, 0.02);
gltfs.scene.position.set(0, 0, 0);
gltfs.scene.rotation.x += 0.5;
scene.add(gltfs.scene);
animate();
});
- 7.动画函数
const animate = () => {
loopId = requestAnimationFrame(animate);
gltfs.scene.rotation.y -= 0.01;
renderer.render(scene, camera);
};
-
- 完整代码
<script setup lang="ts">
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import { RoomEnvironment } from "three/addons/environments/RoomEnvironment.js";
import { onMounted } from "vue";
const initGlb = () => {
let camera, scene, renderer, controls, loopId, gltfs;
// 创建场景
scene = new THREE.Scene();
const planeBox: HTMLElement = document.querySelector(".planeBox")!;
const { w, h } = getSize(planeBox);
// 创建相机, 在这里,使用的是PerspectiveCamera(透视摄像机),
// 第一个参数是视野角度(FOV)。 视野角度就是无论在什么时候,你所能在显示器上看到的场景的范围,它的单位是角度(与弧度区分开)。
// 第二个参数是长宽比(aspect ratio)。也就是用一个物体的宽除以它的高的值。比如说,在一个宽屏电视上播放老电影时,可以看到图像仿佛是被压扁的。
// 接下来的两个参数是近截面(near)和远截面(far)。物体某些部分比摄像机的远截面远或者比近截面近的时候,该这些部分将不会被渲染到场景中。或许现在你不用担心这个值的影响,但未来为了获得更好的渲染性能,你将可以在你的应用程序里去设置它。
camera = new THREE.PerspectiveCamera(45, w / h, 0.1, 20);
// 设置相机位置 三个参数分别为x轴坐标,y轴坐标,z轴坐标
camera.position.set(0, 0, 1);
// 创建渲染器
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
// 将渲染器的像素比例(pixel ratio)设置为与当前设备的物理像素比率(device pixel ratio)相匹配。这是为了确保渲染的内容在高DPI(像素密度)屏幕上呈现得更清晰,而不会出现模糊的情况。
// window.devicePixelRatio返回当前设备的像素比率,通常是1或更高。如果设备的像素比率为1,表示标准DPI屏幕,而如果像素比率高于1,表示高DPI或Retina屏幕,其显示的像素密度更高。
renderer.setPixelRatio(window.devicePixelRatio);
// 设置渲染器的渲染区域大小
renderer.setSize(w, h);
// 设置了Three.js渲染器(renderer)的色调映射(Tone Mapping)方式为 THREE.ACESFilmicToneMapping。
// THREE.ACESFilmicToneMapping 是一种现代色调映射算法,旨在提供更真实的颜色和光照效果,以模拟电影摄影中的感觉。这种算法通常用于渲染引擎中,以确保渲染的图像在不同光照条件下看起来更自然和逼真。
renderer.toneMapping = THREE.ACESFilmicToneMapping;
// 设置了Three.js渲染器(renderer)的曝光值(Exposure)。曝光值是用于控制图像的亮度的参数,它影响了图像的整体明亮度。
// renderer.toneMappingExposure 设置为1,表示没有明显的曝光修正。当曝光值为1时,图像的亮度不会发生明显的变化,即图像保持原始的亮度。如果曝光值小于1,图像会变得较暗;如果曝光值大于1,图像会变得较亮。
renderer.toneMappingExposure = 1;
// 是否启用旧版的光照系统
// 当 useLegacyLights 设置为 false 时,表示使用现代的光照系统,而不使用旧版的光照系统。这意味着Three.js将采用更现代、更高质量的光照和阴影计算方法,以获得更逼真的渲染效果。
renderer.useLegacyLights = false;
// 将Three.js渲染器(renderer)的渲染元素(canvas元素)添加到HTML的指定容器中。
planeBox.appendChild(renderer.domElement);
// 创建RoomEnvironment 对象,用于创建一种模拟室内环境的光照和背景效果。主要目的是增强3D场景的视觉效果,使渲染的内容看起来更加逼真。
const environment = new RoomEnvironment(renderer);
// 创建了 PMREMGenerator 对象,用于预计算环境贴图,以提高渲染效果的质量和性能。
const pmremGenerator = new THREE.PMREMGenerator(renderer);
// 设置背景颜色透明
scene.background = null;
// 以模拟更逼真的光照和反射效果。这有助于提高渲染场景的视觉质量,特别是在处理材质的反射效果时。
scene.environment = pmremGenerator.fromScene(environment).texture;
// 创建控制器
controls = new OrbitControls(camera, renderer.domElement);
// 启用 Three.js 中的 OrbitControls 控制器的阻尼效果(damping)。阻尼效果是一种平滑过渡的效果,它可以使控制器在用户交互停止后平稳减速,而不是突然停止。这可以使控制器的移动更加自然和平滑
controls.enableDamping = true;
// 设置摄像机视角能够缩放到的最小距离
controls.minDistance = 1;
// 设置摄像机视角能够缩放到的最大距离
controls.maxDistance = 10;
// 设置控制器目标位置
controls.target.set(0, 0, 0);
// 更新控制器状态
controls.update();
// 加载模型
new GLTFLoader().load("/B2.glb", (gltf) => {
gltfs = gltf;
// 设置加载模型的缩放比例
gltfs.scene.scale.set(0.02, 0.02, 0.02);
// 置加载的模型的位置
gltfs.scene.position.set(0, 0, 0);
// 旋转加载的模型
gltfs.scene.rotation.x += 0.5;
// 加载的模型的场景对象添加到 Three.js 的主场景中,以便在渲染中显示模型
scene.add(gltfs.scene);
// 调用animate函数,开始渲染循环,进行动画。
animate();
});
const animate = () => {
// requestAnimationFrame 是浏览器提供的一个用于执行动画的函数,它会在每一帧中自动调用指定的函数,通常用于制作流畅的动画效果
loopId = requestAnimationFrame(animate);
gltfs.scene.rotation.y -= 0.01;
renderer.render(scene, camera);
};
// 自适应窗口变化
const onWindowResize = () => {
camera.aspect = w / h;
camera.updateProjectionMatrix();
renderer.setSize(w, h);
};
window.addEventListener("resize", onWindowResize);
};
// 获取标签的宽高
const getSize = (ele: HTMLElement) => {
return {
w: Number(
window
.getComputedStyle(ele, null)
.width.substring(0, window.getComputedStyle(ele, null).width.length - 2)
),
h: Number(
window
.getComputedStyle(ele, null)
.height.substring(
0,
window.getComputedStyle(ele, null).height.length - 2
)
),
};
};
onMounted(() => {
initGlb();
});
</script>
<template>
<div class="threeBox">
<div class="planeBox"></div>
</div>
</template>
<style lang="less" scoped>
.threeBox {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
.planeBox {
width: 300px;
height: 300px;
border: 1px solid red;
}
}
</style>
-
- 展示效果
加载三维模型