9.项目实践与案例分析 项目实践与案例分析:深入Three.js应用 9.1 交互式3D模型展示:汽车模型配置器 项目描述: 创建一个Web应用,允许用户交互式地查看和配置汽车模型。用户可以旋转、缩放模型,并选择不同的颜色、轮毂等配置选项。 技术栈: Three.js:用于3D模型渲染和交互 GLTFLoader:加载GLTF格式的模型文件 OrbitControls:实现相机控制 HTML/CSS/JavaScript:构建用户界面和事件处理 实现思路: 模型加载: 使用GLTFLoader加载汽车模型的GLTF文件。GLTF是一种专门为3D场景传输设计的格式,体积小、加载速度快,非常适合Web应用。 场景搭建: 创建Three.js场景、相机和渲染器。将加载的汽车模型添加到场景中。
项目描述:
创建一个Web应用,允许用户交互式地查看和配置汽车模型。用户可以旋转、缩放模型,并选择不同的颜色、轮毂等配置选项。
技术栈:
Three.js:用于3D模型渲染和交互
GLTFLoader:加载GLTF格式的模型文件
OrbitControls:实现相机控制
HTML/CSS/JavaScript:构建用户界面和事件处理
实现思路:
模型加载: 使用GLTFLoader加载汽车模型的GLTF文件。GLTF是一种专门为3D场景传输设计的格式,体积小、加载速度快,非常适合Web应用。
场景搭建: 创建Three.js场景、相机和渲染器。将加载的汽车模型添加到场景中。
相机控制: 使用OrbitControls实现相机围绕模型旋转、缩放和平移的功能。
配置选项: 创建用户界面,允许用户选择不同的颜色、轮毂等配置选项。
事件处理: 监听用户界面的事件,根据用户的选择修改模型的材质和外观。
核心代码片段:
import * as THREE from 'three'; import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; // 场景、相机、渲染器 const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 光源 const ambientLight = new THREE.AmbientLight(0x404040); // 柔和的环境光 scene.add(ambientLight); const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5); // 平行光 directionalLight.position.set(1, 1, 1); scene.add(directionalLight); // 相机位置 camera.position.z = 5; // 控制器 const controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; // 启用阻尼,使旋转更平滑 controls.dampingFactor = 0.05; // 加载模型 const loader = new GLTFLoader(); let carModel; loader.load( 'path/to/your/car.gltf', // 替换为你的模型路径 function (gltf) { carModel = gltf.scene; scene.add(carModel); }, undefined, function (error) { console.error('An error happened', error); } ); // 渲染循环 function animate() { requestAnimationFrame(animate); controls.update(); // 更新控制器 renderer.render(scene, camera); } animate(); // 颜色修改函数 (示例) function changeColor(color) { if (carModel) { // 假设车身材质名为 'body' const bodyMaterial = carModel.getObjectByName('body').material; bodyMaterial.color.set(color); } } // 监听颜色选择器 (示例) const colorPicker = document.getElementById('colorPicker'); colorPicker.addEventListener('input', (event) => { changeColor(event.target.value); }); // 窗口大小调整 window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); });
代码详解:
import 语句: 导入必要的 Three.js 模块,包括核心模块、GLTFLoader 和 OrbitControls。
场景、相机、渲染器: 创建 Three.js 的核心组件,设置渲染器的大小和抗锯齿。
光源: 添加环境光和方向光,使模型更清晰可见。
OrbitControls: 初始化 OrbitControls,允许用户使用鼠标控制相机。enableDamping 和 dampingFactor 用于实现平滑的旋转效果。
GLTFLoader: 使用 GLTFLoader 加载 GLTF 模型。加载完成后,将模型添加到场景中。
animate() 函数: 渲染循环,不断更新 OrbitControls 并渲染场景。
changeColor() 函数 (示例): 根据用户选择的颜色,修改模型中指定材质的颜色。 需要根据你的模型结构进行调整,找到对应的材质名称。
事件监听器 (示例): 监听颜色选择器的事件,调用 changeColor() 函数更新模型颜色。 你需要根据你的用户界面元素进行调整。
窗口大小调整: 监听窗口大小变化,更新相机和渲染器尺寸,保证画面比例正确。
mermaid 图示:
关键点:
模型优化: 使用优化过的模型可以提高加载速度和渲染性能。
材质管理: 合理管理模型的材质,方便修改和控制。
用户体验: 提供流畅的交互体验,例如平滑的相机控制和快速的配置切换。
项目描述:
创建一个Web应用,使用Three.js将数据可视化为3D柱状图。
技术栈:
Three.js:用于3D图形渲染
JavaScript:用于数据处理和界面交互
实现思路:
数据准备: 准备要可视化的数据,例如每个柱状图的高度和位置。
场景搭建: 创建Three.js场景、相机和渲染器。
创建柱状图: 使用THREE.BoxGeometry创建柱状图的几何体,并使用THREE.MeshBasicMaterial或THREE.MeshPhongMaterial创建材质。
位置和缩放: 根据数据设置每个柱状图的位置和缩放。
坐标轴: 创建坐标轴,方便用户理解数据。
相机控制: 使用OrbitControls或自定义的相机控制,允许用户旋转和缩放视图。
核心代码片段:
import * as THREE from 'three'; import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'; // 数据 (示例) const data = [ { x: 0, y: 0, z: 0, height: 5 }, { x: 1, y: 0, z: 0, height: 8 }, { x: 2, y: 0, z: 0, height: 3 }, { x: 0, y: 1, z: 0, height: 7 }, { x: 1, y: 1, z: 0, height: 2 }, { x: 2, y: 1, z: 0, height: 9 }, ]; // 场景、相机、渲染器 const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 相机位置 camera.position.set(2, 2, 5); // 控制器 const controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; controls.dampingFactor = 0.05; // 光源 const ambientLight = new THREE.AmbientLight(0x404040); scene.add(ambientLight); const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5); directionalLight.position.set(1, 1, 1); scene.add(directionalLight); // 创建柱状图 data.forEach(item => { const geometry = new THREE.BoxGeometry(0.5, item.height, 0.5); const material = new THREE.MeshPhongMaterial({ color: 0x00ff00 }); const cube = new THREE.Mesh(geometry, material); cube.position.set(item.x, item.height / 2, item.y); // 调整位置,使底部在原点 scene.add(cube); }); // 创建坐标轴 (简化示例) const axesHelper = new THREE.AxesHelper( 5 ); scene.add( axesHelper ); // 渲染循环 function animate() { requestAnimationFrame(animate); controls.update(); renderer.render(scene, camera); } animate(); // 窗口大小调整 window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); });
代码详解:
data 数组: 包含要可视化的数据,每个对象包含 x, y 坐标和高度。
THREE.BoxGeometry: 创建立方体几何体,作为柱状图的基础。
THREE.MeshPhongMaterial: 创建材质,设置柱状图的颜色。MeshPhongMaterial 对光照有反应,效果更好。
cube.position.set(): 设置柱状图的位置。 注意 item.height / 2 的使用,确保柱状图的底部在原点。
THREE.AxesHelper: 创建坐标轴,方便观察数据分布。
mermaid 图示:
关键点:
数据处理: 根据数据的范围和类型,调整柱状图的缩放和位置。
颜色编码: 使用不同的颜色来区分不同的数据类别。
交互性: 添加交互功能,例如鼠标悬停时显示数据详情。
项目描述:
创建一个简单的3D迷宫游戏,玩家控制一个角色在迷宫中移动,找到出口。
技术栈:
Three.js:用于3D场景渲染和碰撞检测
Cannon.js (可选):用于物理引擎,实现更真实的碰撞效果
JavaScript:用于游戏逻辑和用户输入
实现思路:
迷宫生成: 使用算法生成迷宫的地图数据。
场景搭建: 创建Three.js场景、相机和渲染器。
创建迷宫墙壁: 根据迷宫地图数据,使用THREE.BoxGeometry创建迷宫的墙壁。
创建玩家角色: 使用THREE.SphereGeometry或自定义模型创建玩家角色。
用户输入: 监听键盘或鼠标事件,控制玩家角色的移动。
碰撞检测: 检测玩家角色与迷宫墙壁的碰撞。可以使用Three.js自带的Raycaster进行简单的碰撞检测,也可以使用Cannon.js等物理引擎实现更真实的碰撞效果。
游戏逻辑: 实现游戏逻辑,例如判断玩家是否到达出口,以及游戏结束时的处理。
核心代码片段 (简化示例,不包含迷宫生成和物理引擎):
import * as THREE from 'three'; // 场景、相机、渲染器 const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 光源 const ambientLight = new THREE.AmbientLight(0x404040); scene.add(ambientLight); const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5); directionalLight.position.set(1, 1, 1); scene.add(directionalLight); // 玩家角色 const playerGeometry = new THREE.SphereGeometry(0.5, 32, 32); const playerMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 }); const player = new THREE.Mesh(playerGeometry, playerMaterial); scene.add(player); player.position.y = 0.5; // 放置在地面上 // 迷宫墙壁 (简化示例) const wallGeometry = new THREE.BoxGeometry(1, 2, 1); const wallMaterial = new THREE.MeshBasicMaterial({ color: 0x0000ff }); const wall1 = new THREE.Mesh(wallGeometry, wallMaterial); wall1.position.set(2, 1, 0); scene.add(wall1); const wall2 = new THREE.Mesh(wallGeometry, wallMaterial); wall2.position.set(0, 1, 2); scene.add(wall2); // 相机位置 camera.position.set(0, 3, 5); camera.lookAt(0,0,0); // 移动速度 const moveSpeed = 0.1; // 用户输入 const keys = {}; document.addEventListener('keydown', (event) => { keys[event.code] = true; }); document.addEventListener('keyup', (event) => { keys[event.code] = false; }); // 碰撞检测 (简化示例) function checkCollision(object1, object2) { const distance = object1.position.distanceTo(object2.position); // 假设碰撞半径为 0.5 + 0.5 = 1 return distance < 1; } // 渲染循环 function animate() { requestAnimationFrame(animate); // 玩家移动 if (keys['KeyW']) { player.position.z -= moveSpeed; } if (keys['KeyS']) { player.position.z += moveSpeed; } if (keys['KeyA']) { player.position.x -= moveSpeed; } if (keys['KeyD']) { player.position.x += moveSpeed; } // 碰撞检测 (简化示例) if (checkCollision(player, wall1)) { // 处理碰撞 (简单地阻止移动) player.position.x += moveSpeed; // 反向移动 console.log("碰撞!"); } if (checkCollision(player, wall2)) { // 处理碰撞 (简单地阻止移动) player.position.z += moveSpeed; // 反向移动 console.log("碰撞!"); } renderer.render(scene, camera); } animate(); // 窗口大小调整 window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); });
代码详解:
玩家角色: 使用 THREE.SphereGeometry 创建一个球体作为玩家角色。
迷宫墙壁: 使用 THREE.BoxGeometry 创建简单的墙壁。 实际游戏中,需要根据迷宫地图数据动态生成墙壁。
用户输入: 监听键盘事件,使用 keys 对象记录按键状态。
checkCollision() 函数: 一个简化的碰撞检测函数,检查两个物体之间的距离是否小于碰撞半径。 实际游戏中,需要更精确的碰撞检测方法,例如使用 Raycaster 或物理引擎。
玩家移动: 根据按键状态,更新玩家角色的位置。
碰撞处理: 如果发生碰撞,简单地阻止玩家移动。 实际游戏中,需要更复杂的碰撞处理逻辑。
mermaid 图示:
关键点:
迷宫生成算法: 选择合适的迷宫生成算法,例如递归分割、Prim算法或Kruskal算法。
碰撞检测: 使用高效的碰撞检测方法,例如Raycaster或物理引擎。
物理引擎: 使用物理引擎可以实现更真实的碰撞效果和角色控制。
游戏逻辑: 设计完善的游戏逻辑,例如判断玩家是否到达出口,以及游戏结束时的处理。