政府的
新基建项目
(如数字孪生
、智慧城市
、室内设计
)广泛应用3D可视化
。对于开发者,可以Three.js
库入手,它简化了WebGL
的底层开发,适合快速入门。
学习基础概念:
几何体 (Geometry):基本形状如 Box
、Sphere
,自定义顶点结构
材质 (Material):基础材质
、纹理贴图
、透明度等属性
场景 (Scene):创建三维世界,管理物体
、光照
和相机
相机 (Camera):透视相机与正交相机,视角控制
和位置调整
掌握 PBR(基于物理的渲染)光照体系:
-> 理解 PBR 渲染的原理:金属度、粗糙度、能量守恒
-> 使用标准材质:MeshStandardMaterial
和 MeshPhysicalMaterial
-> 加载环境贴图 (IBL):实现真实反射与高光 -> 应用贴图通道:法线贴图 、金属贴图 、AO贴图 等
-> 配置光源类型与参数:点光源、环境光、平行光等实现立体感
-> 引入HDR、色调映射与 Gamma 校正优化真实感
进阶阶段需要掌握交互设计
、物理引擎
(如重力、摩擦力)和着色器编程
(如顶点着色器、片元着色器),以实现动态效果(如旗帜飘扬、烟雾模拟)。
后期处理可打造特殊视觉(如雪花屏、水下视角),而Blender
等建模工具能优化复杂模型和动画。最终,结合CSS3D渲染器
和地理信息数据
。
可以构建逼真的智慧园区
、数字城市
,实现3D
与网页元素的深度互动。
1. 基础Three.js应用搭建
首先我们来创建一个最基础的Three.js
应用,展示一个旋转的立方体
。
javascript
// 引入Three.js库
import * as THREE from 'three';
// 1. 创建场景 - 相当于一个3D世界容器
const scene = new THREE.Scene();
// 2. 创建相机 - 决定我们能看到什么
// 参数分别是:视野角度(FOV)、宽高比、近裁剪面、远裁剪面
const camera = new THREE.PerspectiveCamera(
75, // 视野角度,越大看到范围越广
window.innerWidth / window.innerHeight, // 相机宽高比
0.1, // 近裁剪面,小于此距离的物体不显示
1000 // 远裁剪面,大于此距离的物体不显示
);
// 3. 创建渲染器 - 负责将3D场景渲染到2D屏幕上
const renderer = new THREE.WebGLRenderer();
// 设置渲染器大小为窗口尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
// 将渲染器的canvas元素(画布)添加到HTML文档中
document.body.appendChild(renderer.domElement);
// 4. 创建立方体几何体
const geometry = new THREE.BoxGeometry(1, 1, 1); // 长宽高各为1的立方体
// 创建材质 - 决定物体外观
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }); // 绿色
// 创建网格物体 = 几何体 + 材质
const cube = new THREE.Mesh(geometry, material);
// 将立方体添加到场景中
scene.add(cube);
// 设置相机位置,默认在(0,0,0),需要向后移动才能看到物体
camera.position.z = 5;
// 5. 动画循环函数
function animate() {
requestAnimationFrame(animate); // 请求下一帧动画
// 旋转立方体
cube.rotation.x += 0.01; // 绕X轴旋转
cube.rotation.y += 0.01; // 绕Y轴旋转
// 渲染场景
renderer.render(scene, camera);
}
// 启动动画循环
animate();
// 6. 响应窗口大小变化
window.addEventListener('resize', () => {
// 更新相机宽高比
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
// 更新渲染器大小
renderer.setSize(window.innerWidth, window.innerHeight);
});
关键点说明:
🔥场景(Scene) : 所有3D
对象的容器,相当于一个虚拟世界
🔥相机(Camera) : 决定我们能看到的视角
和范围
,常用的是透视相机
(PerspectiveCamera)
🔥渲染器(Renderer) : 负责将3D
场景渲染到2D
屏幕上
🔥几何体(Geometry) : 定义物体的形状
🔥材质(Material) : 定义物体的外观
(颜色
、纹理
等)
🔥网格(Mesh) : 几何体
和材质
的结合体,构成可渲染的物体
2. 结合Vue框架写Three.js
Vue
项目中用Three.js
的代码。
javascript
<template>
<!-- 空的div容器,Three.js会自动添加canvas元素 -->
<div ref="threeContainer"></div>
</template>
<script setup>
import * as THREE from 'three';
import { onMounted, onUnmounted, ref } from 'vue';
const threeContainer = ref(null);
// 定义响应式变量存储Three.js实例
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
const renderer = new THREE.WebGLRenderer();
const cube = ref(null);
// 动画循环ID
let animationId = null;
// 初始化Three.js场景
const initThreeScene = () => {
// 设置渲染器大小并添加到DOM
renderer.setSize(window.innerWidth, window.innerHeight);
threeContainer.value.appendChild(renderer.domElement);
// 创建立方体
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
cube.value = new THREE.Mesh(geometry, material);
scene.add(cube.value);
camera.position.z = 5;
};
// 动画循环
const animate = () => {
cube.value.rotation.x += 0.01;
cube.value.rotation.y += 0.01;
renderer.render(scene, camera);
animationId = requestAnimationFrame(animate);
};
// 响应式调整大小
const handleResize = () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
};
onMounted(() => {
initThreeScene();
animate();
window.addEventListener('resize', handleResize);
});
// 组件卸载时清理
onUnmounted(() => {
cancelAnimationFrame(animationId);
window.removeEventListener('resize', handleResize);
threeContainer.value?.removeChild(renderer.domElement);
});
</script>
<style scoped>
/* 确保canvas填满整个屏幕 */
:root, body, html {
margin: 0;
padding: 0;
overflow: hidden;
width: 100%;
height: 100%;
}
div {
width: 100%;
height: 100%;
}
</style>
Vue整合要点:
- 使用
ref
获取DOM容器 - 在
onMounted
生命周期钩子中初始化 - 组件卸载时记得
清理
资源和卸掉
事件监听 - 动画循环依然使用
requestAnimationFrame
3. 结合React框架写Three.js
React中用Three.js,提供函数组件
和类组件
两种写法。
函数组件写法:
jsx
import React, { useEffect, useRef } from 'react';
import * as THREE from 'three';
function ThreeScene() {
const mountRef = useRef(null);
useEffect(() => {
// 1. 初始化场景
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
// 设置渲染器并添加到DOM
renderer.setSize(window.innerWidth, window.innerHeight);
mountRef.current.appendChild(renderer.domElement);
// 2. 创建立方体
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
camera.position.z = 5;
// 3. 动画循环
const animate = () => {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
};
animate();
// 4. 响应式调整
const handleResize = () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
};
window.addEventListener('resize', handleResize);
// 清理函数
return () => {
window.removeEventListener('resize', handleResize);
mountRef.current?.removeChild(renderer.domElement);
};
}, []);
return <div ref={mountRef} />;
}
export default ThreeScene;
类组件写法:
jsx
import React, { Component } from 'react';
import * as THREE from 'three';
class ThreeScene extends Component {
componentDidMount() {
// 1. 初始化场景
this.scene = new THREE.Scene();
this.camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
this.renderer = new THREE.WebGLRenderer();
// 设置渲染器并添加到DOM
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.mount.appendChild(this.renderer.domElement);
// 2. 创建立方体
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
this.cube = new THREE.Mesh(geometry, material);
this.scene.add(this.cube);
this.camera.position.z = 5;
// 启动动画循环
this.startAnimationLoop();
// 3. 添加窗口大小变化监听
window.addEventListener('resize', this.handleResize);
}
componentWillUnmount() {
// 清理资源
window.removeEventListener('resize', this.handleResize);
this.mount.removeChild(this.renderer.domElement);
cancelAnimationFrame(this.requestId);
}
startAnimationLoop = () => {
this.requestId = requestAnimationFrame(this.startAnimationLoop);
this.cube.rotation.x += 0.01;
this.cube.rotation.y += 0.01;
this.renderer.render(this.scene, this.camera);
};
handleResize = () => {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight);
};
render() {
return <div ref={ref => (this.mount = ref)} />;
}
}
export default ThreeScene;
React整合要点:
- 使用
useRef
(函数组件)或实例属性(类组件)获取DOM容器 - 在
useEffect
(函数组件)或componentDidMount
(类组件)中初始化Three.js
- 在清理函数或
componentWillUnmount
中释放资源 - 动画循环依然使用
requestAnimationFrame
总结
用Vue和React框架整合开发3D可视化threejs应用,注意的点:
- Three.js核心概念:场景、相机、渲染器三位一体构成基础框架
- 动画原理 :使用
requestAnimationFrame
实现平滑动画 - 响应式设计:监听窗口大小变化并调整相机和渲染器
- 框架整合 :
- Vue中使用组合式API和生命周期钩子
- React中使用hooks或类组件生命周期
- 资源管理:组件卸载时remove和cancel掉动画frame