Three.js实战3D数据可视化入门与实践前言大家好我是前端老炮儿。今天咱们来聊聊Three.js在数据可视化领域3D可视化正变得越来越重要。Three.js作为一个强大的3D库可以帮助我们轻松创建各种3D效果。今天我就带大家一起学习Three.js从基础到实战Three.js简介Three.js是一个基于WebGL的3D JavaScript库它简化了WebGL的复杂API让我们可以轻松创建3D场景、相机、灯光和几何体。核心特点简化WebGL提供简洁的API丰富的几何体内置多种3D几何体材质系统支持多种材质类型动画支持内置动画系统扩展丰富支持多种加载器和插件基础使用安装npm install three创建第一个3D场景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() renderer.setSize(window.innerWidth, window.innerHeight) document.body.appendChild(renderer.domElement) 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 function animate() { requestAnimationFrame(animate) cube.rotation.x 0.01 cube.rotation.y 0.01 renderer.render(scene, camera) } animate()核心概念1. 场景 (Scene)const scene new THREE.Scene() scene.background new THREE.Color(0xf0f0f0)2. 相机 (Camera)// 透视相机 const camera new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ) // 正交相机 const camera new THREE.OrthographicCamera( -width / 2, width / 2, height / 2, -height / 2, 0.1, 1000 )3. 渲染器 (Renderer)const renderer new THREE.WebGLRenderer({ antialias: true }) renderer.setSize(window.innerWidth, window.innerHeight) renderer.setPixelRatio(window.devicePixelRatio) document.body.appendChild(renderer.domElement)4. 几何体 (Geometry)// 立方体 const geometry new THREE.BoxGeometry(1, 1, 1) // 球体 const geometry new THREE.SphereGeometry(1, 32, 32) // 圆柱体 const geometry new THREE.CylinderGeometry(1, 1, 2, 32) // 自定义几何体 const geometry new THREE.BufferGeometry() const positions new Float32Array([ 0, 1, 0, -1, -1, 0, 1, -1, 0 ]) geometry.setAttribute(position, new THREE.BufferAttribute(positions, 3))5. 材质 (Material)// 基础材质 const material new THREE.MeshBasicMaterial({ color: 0x00ff00 }) // 兰伯特材质 const material new THREE.MeshLambertMaterial({ color: 0x00ff00 }) // 金属材质 const material new THREE.MeshMetalnessMaterial({ color: 0x00ff00, metalness: 0.8, roughness: 0.2 }) // 着色器材质 const material new THREE.ShaderMaterial({ vertexShader: void main() { gl_Position projectionMatrix * modelViewMatrix * vec4(position, 1.0); } , fragmentShader: void main() { gl_FragColor vec4(1.0, 0.0, 0.0, 1.0); } })6. 灯光 (Light)// 环境光 const light new THREE.AmbientLight(0xffffff, 0.5) scene.add(light) // 点光源 const light new THREE.PointLight(0xffffff, 1) light.position.set(5, 5, 5) scene.add(light) // 平行光 const light new THREE.DirectionalLight(0xffffff, 1) light.position.set(5, 5, 5) scene.add(light) // 聚光灯 const light new THREE.SpotLight(0xffffff, 1) light.position.set(5, 5, 5) scene.add(light)3D数据可视化实战案例13D柱状图function create3DBarChart(data) { const group new THREE.Group() const maxValue Math.max(...data) const spacing 2 const startX -(data.length - 1) * spacing / 2 data.forEach((value, index) { const height (value / maxValue) * 5 const geometry new THREE.BoxGeometry(1, height, 1) const material new THREE.MeshLambertMaterial({ color: new THREE.Color().setHSL(index / data.length, 0.7, 0.5) }) const cube new THREE.Mesh(geometry, material) cube.position.x startX index * spacing cube.position.y height / 2 cube.position.z 0 group.add(cube) }) return group } const data [10, 20, 30, 25, 15] const chart create3DBarChart(data) scene.add(chart)案例23D散点图function create3DScatterPlot(data) { const group new THREE.Group() data.forEach((point) { const geometry new THREE.SphereGeometry(0.1, 16, 16) const material new THREE.MeshLambertMaterial({ color: 0x3498db }) const sphere new THREE.Mesh(geometry, material) sphere.position.set(point.x, point.y, point.z) group.add(sphere) }) return group } const data [ { x: 1, y: 2, z: 3 }, { x: 2, y: 3, z: 1 }, { x: 3, y: 1, z: 2 } ] const plot create3DScatterPlot(data) scene.add(plot)案例33D曲面图function createSurfacePlot(width, height, func) { const geometry new THREE.ParametricGeometry(func, width, height) const material new THREE.MeshLambertMaterial({ color: 0x3498db, side: THREE.DoubleSide }) const mesh new THREE.Mesh(geometry, material) return mesh } function surfaceFunction(u, v, target) { const x (u - 0.5) * 10 const y Math.sin(x) * Math.cos(v * Math.PI * 2) * 2 const z (v - 0.5) * 10 target.set(x, y, z) } const surface createSurfacePlot(50, 50, surfaceFunction) scene.add(surface)动画与交互使用动画循环function animate() { requestAnimationFrame(animate) // 更新场景 scene.rotation.y 0.01 renderer.render(scene, camera) } animate()使用GSAP动画import gsap from gsap gsap.to(cube.rotation, { x: Math.PI * 2, y: Math.PI * 2, duration: 2, repeat: -1, ease: none })鼠标交互const raycaster new THREE.Raycaster() const mouse new THREE.Vector2() function onMouseClick(event) { mouse.x (event.clientX / window.innerWidth) * 2 - 1 mouse.y -(event.clientY / window.innerHeight) * 2 1 raycaster.setFromCamera(mouse, camera) const intersects raycaster.intersectObjects(scene.children, true) if (intersects.length 0) { const material new THREE.MeshLambertMaterial({ color: 0xff0000 }) intersects[0].object.material material } } window.addEventListener(click, onMouseClick)加载外部模型加载GLB/GLTF模型import { GLTFLoader } from three/addons/loaders/GLTFLoader.js const loader new GLTFLoader() loader.load(model.glb, (gltf) { scene.add(gltf.scene) }, (xhr) { console.log(${(xhr.loaded / xhr.total * 100)}% loaded) }, (error) { console.error(An error happened, error) })加载OBJ模型import { OBJLoader } from three/addons/loaders/OBJLoader.js const loader new OBJLoader() loader.load(model.obj, (object) { scene.add(object) })性能优化1. 使用实例化渲染const geometry new THREE.BoxGeometry(0.1, 0.1, 0.1) const material new THREE.MeshLambertMaterial({ color: 0x3498db }) const instancedMesh new THREE.InstancedMesh(geometry, material, 1000) const matrix new THREE.Matrix4() const color new THREE.Color() for (let i 0; i 1000; i) { matrix.setPosition( (Math.random() - 0.5) * 10, (Math.random() - 0.5) * 10, (Math.random() - 0.5) * 10 ) instancedMesh.setMatrixAt(i, matrix) color.setHSL(Math.random(), 0.7, 0.5) instancedMesh.setColorAt(i, color) } scene.add(instancedMesh)2. 使用LODconst lod new THREE.LOD() const geometry1 new THREE.BoxGeometry(1, 1, 1) const geometry2 new THREE.BoxGeometry(0.5, 0.5, 0.5) const geometry3 new THREE.BoxGeometry(0.25, 0.25, 0.25) const material new THREE.MeshLambertMaterial({ color: 0x3498db }) lod.addLevel(new THREE.Mesh(geometry1, material), 0) lod.addLevel(new THREE.Mesh(geometry2, material), 50) lod.addLevel(new THREE.Mesh(geometry3, material), 100) scene.add(lod)3. 启用阴影优化renderer.shadowMap.enabled true renderer.shadowMap.type THREE.PCFSoftShadowMap mesh.castShadow true mesh.receiveShadow true总结通过今天的学习我们了解了Three.js的基础和进阶用法核心概念场景、相机、渲染器、几何体、材质、灯光实战案例3D柱状图、散点图、曲面图动画交互动画循环、GSAP、鼠标交互模型加载GLB、OBJ模型加载性能优化实例化渲染、LOD、阴影优化Three.js是一个非常强大的3D库可以帮助我们创建各种精彩的3D数据可视化效果。希望今天的分享能帮助你入门Three.js最后给大家留个思考题在你的项目中如何使用Three.js实现复杂的3D数据可视化欢迎在评论区留言讨论
Three.js实战:3D数据可视化入门与实践
Three.js实战3D数据可视化入门与实践前言大家好我是前端老炮儿。今天咱们来聊聊Three.js在数据可视化领域3D可视化正变得越来越重要。Three.js作为一个强大的3D库可以帮助我们轻松创建各种3D效果。今天我就带大家一起学习Three.js从基础到实战Three.js简介Three.js是一个基于WebGL的3D JavaScript库它简化了WebGL的复杂API让我们可以轻松创建3D场景、相机、灯光和几何体。核心特点简化WebGL提供简洁的API丰富的几何体内置多种3D几何体材质系统支持多种材质类型动画支持内置动画系统扩展丰富支持多种加载器和插件基础使用安装npm install three创建第一个3D场景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() renderer.setSize(window.innerWidth, window.innerHeight) document.body.appendChild(renderer.domElement) 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 function animate() { requestAnimationFrame(animate) cube.rotation.x 0.01 cube.rotation.y 0.01 renderer.render(scene, camera) } animate()核心概念1. 场景 (Scene)const scene new THREE.Scene() scene.background new THREE.Color(0xf0f0f0)2. 相机 (Camera)// 透视相机 const camera new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ) // 正交相机 const camera new THREE.OrthographicCamera( -width / 2, width / 2, height / 2, -height / 2, 0.1, 1000 )3. 渲染器 (Renderer)const renderer new THREE.WebGLRenderer({ antialias: true }) renderer.setSize(window.innerWidth, window.innerHeight) renderer.setPixelRatio(window.devicePixelRatio) document.body.appendChild(renderer.domElement)4. 几何体 (Geometry)// 立方体 const geometry new THREE.BoxGeometry(1, 1, 1) // 球体 const geometry new THREE.SphereGeometry(1, 32, 32) // 圆柱体 const geometry new THREE.CylinderGeometry(1, 1, 2, 32) // 自定义几何体 const geometry new THREE.BufferGeometry() const positions new Float32Array([ 0, 1, 0, -1, -1, 0, 1, -1, 0 ]) geometry.setAttribute(position, new THREE.BufferAttribute(positions, 3))5. 材质 (Material)// 基础材质 const material new THREE.MeshBasicMaterial({ color: 0x00ff00 }) // 兰伯特材质 const material new THREE.MeshLambertMaterial({ color: 0x00ff00 }) // 金属材质 const material new THREE.MeshMetalnessMaterial({ color: 0x00ff00, metalness: 0.8, roughness: 0.2 }) // 着色器材质 const material new THREE.ShaderMaterial({ vertexShader: void main() { gl_Position projectionMatrix * modelViewMatrix * vec4(position, 1.0); } , fragmentShader: void main() { gl_FragColor vec4(1.0, 0.0, 0.0, 1.0); } })6. 灯光 (Light)// 环境光 const light new THREE.AmbientLight(0xffffff, 0.5) scene.add(light) // 点光源 const light new THREE.PointLight(0xffffff, 1) light.position.set(5, 5, 5) scene.add(light) // 平行光 const light new THREE.DirectionalLight(0xffffff, 1) light.position.set(5, 5, 5) scene.add(light) // 聚光灯 const light new THREE.SpotLight(0xffffff, 1) light.position.set(5, 5, 5) scene.add(light)3D数据可视化实战案例13D柱状图function create3DBarChart(data) { const group new THREE.Group() const maxValue Math.max(...data) const spacing 2 const startX -(data.length - 1) * spacing / 2 data.forEach((value, index) { const height (value / maxValue) * 5 const geometry new THREE.BoxGeometry(1, height, 1) const material new THREE.MeshLambertMaterial({ color: new THREE.Color().setHSL(index / data.length, 0.7, 0.5) }) const cube new THREE.Mesh(geometry, material) cube.position.x startX index * spacing cube.position.y height / 2 cube.position.z 0 group.add(cube) }) return group } const data [10, 20, 30, 25, 15] const chart create3DBarChart(data) scene.add(chart)案例23D散点图function create3DScatterPlot(data) { const group new THREE.Group() data.forEach((point) { const geometry new THREE.SphereGeometry(0.1, 16, 16) const material new THREE.MeshLambertMaterial({ color: 0x3498db }) const sphere new THREE.Mesh(geometry, material) sphere.position.set(point.x, point.y, point.z) group.add(sphere) }) return group } const data [ { x: 1, y: 2, z: 3 }, { x: 2, y: 3, z: 1 }, { x: 3, y: 1, z: 2 } ] const plot create3DScatterPlot(data) scene.add(plot)案例33D曲面图function createSurfacePlot(width, height, func) { const geometry new THREE.ParametricGeometry(func, width, height) const material new THREE.MeshLambertMaterial({ color: 0x3498db, side: THREE.DoubleSide }) const mesh new THREE.Mesh(geometry, material) return mesh } function surfaceFunction(u, v, target) { const x (u - 0.5) * 10 const y Math.sin(x) * Math.cos(v * Math.PI * 2) * 2 const z (v - 0.5) * 10 target.set(x, y, z) } const surface createSurfacePlot(50, 50, surfaceFunction) scene.add(surface)动画与交互使用动画循环function animate() { requestAnimationFrame(animate) // 更新场景 scene.rotation.y 0.01 renderer.render(scene, camera) } animate()使用GSAP动画import gsap from gsap gsap.to(cube.rotation, { x: Math.PI * 2, y: Math.PI * 2, duration: 2, repeat: -1, ease: none })鼠标交互const raycaster new THREE.Raycaster() const mouse new THREE.Vector2() function onMouseClick(event) { mouse.x (event.clientX / window.innerWidth) * 2 - 1 mouse.y -(event.clientY / window.innerHeight) * 2 1 raycaster.setFromCamera(mouse, camera) const intersects raycaster.intersectObjects(scene.children, true) if (intersects.length 0) { const material new THREE.MeshLambertMaterial({ color: 0xff0000 }) intersects[0].object.material material } } window.addEventListener(click, onMouseClick)加载外部模型加载GLB/GLTF模型import { GLTFLoader } from three/addons/loaders/GLTFLoader.js const loader new GLTFLoader() loader.load(model.glb, (gltf) { scene.add(gltf.scene) }, (xhr) { console.log(${(xhr.loaded / xhr.total * 100)}% loaded) }, (error) { console.error(An error happened, error) })加载OBJ模型import { OBJLoader } from three/addons/loaders/OBJLoader.js const loader new OBJLoader() loader.load(model.obj, (object) { scene.add(object) })性能优化1. 使用实例化渲染const geometry new THREE.BoxGeometry(0.1, 0.1, 0.1) const material new THREE.MeshLambertMaterial({ color: 0x3498db }) const instancedMesh new THREE.InstancedMesh(geometry, material, 1000) const matrix new THREE.Matrix4() const color new THREE.Color() for (let i 0; i 1000; i) { matrix.setPosition( (Math.random() - 0.5) * 10, (Math.random() - 0.5) * 10, (Math.random() - 0.5) * 10 ) instancedMesh.setMatrixAt(i, matrix) color.setHSL(Math.random(), 0.7, 0.5) instancedMesh.setColorAt(i, color) } scene.add(instancedMesh)2. 使用LODconst lod new THREE.LOD() const geometry1 new THREE.BoxGeometry(1, 1, 1) const geometry2 new THREE.BoxGeometry(0.5, 0.5, 0.5) const geometry3 new THREE.BoxGeometry(0.25, 0.25, 0.25) const material new THREE.MeshLambertMaterial({ color: 0x3498db }) lod.addLevel(new THREE.Mesh(geometry1, material), 0) lod.addLevel(new THREE.Mesh(geometry2, material), 50) lod.addLevel(new THREE.Mesh(geometry3, material), 100) scene.add(lod)3. 启用阴影优化renderer.shadowMap.enabled true renderer.shadowMap.type THREE.PCFSoftShadowMap mesh.castShadow true mesh.receiveShadow true总结通过今天的学习我们了解了Three.js的基础和进阶用法核心概念场景、相机、渲染器、几何体、材质、灯光实战案例3D柱状图、散点图、曲面图动画交互动画循环、GSAP、鼠标交互模型加载GLB、OBJ模型加载性能优化实例化渲染、LOD、阴影优化Three.js是一个非常强大的3D库可以帮助我们创建各种精彩的3D数据可视化效果。希望今天的分享能帮助你入门Three.js最后给大家留个思考题在你的项目中如何使用Three.js实现复杂的3D数据可视化欢迎在评论区留言讨论