Appearance
三维可视化应用
概述
三维可视化处理立体数据,如 3D 模型、地球、建筑、游戏场景等。
Three.js 基础
1. 创建场景
javascript
import * as THREE from 'three'
class ThreeScene {
constructor(container) {
this.container = container
this.scene = new THREE.Scene()
this.camera = null
this.renderer = null
this.controls = null
this.init()
}
init() {
// 创建相机
const width = this.container.clientWidth
const height = this.container.clientHeight
this.camera = new THREE.PerspectiveCamera(
75,
width / height,
0.1,
1000
)
this.camera.position.set(0, 0, 5)
// 创建渲染器
this.renderer = new THREE.WebGLRenderer({ antialias: true })
this.renderer.setSize(width, height)
this.renderer.setPixelRatio(window.devicePixelRatio)
this.renderer.setClearColor(0x000000)
this.container.appendChild(this.renderer.domElement)
// 添加控制器
this.controls = new OrbitControls(this.camera, this.renderer.domElement)
this.controls.enableDamping = true
this.controls.dampingFactor = 0.05
// 添加光源
const ambientLight = new THREE.AmbientLight(0x404040)
this.scene.add(ambientLight)
const directionalLight = new THREE.DirectionalLight(0xffffff, 1)
directionalLight.position.set(1, 1, 1)
this.scene.add(directionalLight)
// 窗口大小调整
window.addEventListener('resize', () => this.onResize())
// 开始渲染
this.animate()
}
onResize() {
const width = this.container.clientWidth
const height = this.container.clientHeight
this.camera.aspect = width / height
this.camera.updateProjectionMatrix()
this.renderer.setSize(width, height)
}
animate() {
requestAnimationFrame(() => this.animate())
this.controls.update()
this.renderer.render(this.scene, this.camera)
}
}2. 创建几何体
javascript
// 立方体
const geometry = new THREE.BoxGeometry(1, 1, 1)
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 })
const cube = new THREE.Mesh(geometry, material)
scene.add(cube)
// 球体
const sphereGeometry = new THREE.SphereGeometry(1, 32, 32)
const sphereMaterial = new THREE.MeshStandardMaterial({ color: 0xff0000 })
const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial)
scene.add(sphere)
// 圆柱体
const cylinderGeometry = new THREE.CylinderGeometry(1, 1, 2, 32)
const cylinderMaterial = new THREE.MeshStandardMaterial({ color: 0x0000ff })
const cylinder = new THREE.Mesh(cylinderGeometry, cylinderMaterial)
scene.add(cylinder)3. 加载模型
javascript
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
const loader = new GLTFLoader()
loader.load(
'/models/scene.gltf',
(gltf) => {
const model = gltf.scene
model.scale.set(1, 1, 1)
model.position.set(0, 0, 0)
scene.add(model)
},
(progress) => {
console.log('Loading:', (progress.loaded / progress.total * 100) + '%')
},
(error) => {
console.error('Error:', error)
}
)地球可视化
1. 创建地球
javascript
class Earth {
constructor(scene) {
this.scene = scene
this.earth = null
this.clouds = null
this.create()
}
async create() {
// 地球
const earthGeometry = new THREE.SphereGeometry(5, 64, 64)
const earthTexture = await this.loadTexture('/textures/earth.jpg')
const earthMaterial = new THREE.MeshPhongMaterial({
map: earthTexture,
bumpScale: 0.05,
specular: new THREE.Color('grey'),
shininess: 10
})
this.earth = new THREE.Mesh(earthGeometry, earthMaterial)
this.scene.add(this.earth)
// 云层
const cloudsGeometry = new THREE.SphereGeometry(5.1, 64, 64)
const cloudsTexture = await this.loadTexture('/textures/clouds.jpg')
const cloudsMaterial = new THREE.MeshPhongMaterial({
map: cloudsTexture,
transparent: true,
opacity: 0.4
})
this.clouds = new THREE.Mesh(cloudsGeometry, cloudsMaterial)
this.scene.add(this.clouds)
}
loadTexture(url) {
return new Promise((resolve, reject) => {
const loader = new THREE.TextureLoader()
loader.load(url, resolve, undefined, reject)
})
}
rotate() {
this.earth.rotation.y += 0.001
this.clouds.rotation.y += 0.0015
}
}2. 添加标记点
javascript
function addMarker(scene, lat, lng, color = 0xff0000) {
// 转换坐标
const phi = (90 - lat) * (Math.PI / 180)
const theta = (lng + 180) * (Math.PI / 180)
const x = -5 * Math.sin(phi) * Math.cos(theta)
const y = 5 * Math.cos(phi)
const z = 5 * Math.sin(phi) * Math.sin(theta)
// 创建标记点
const geometry = new THREE.SphereGeometry(0.1, 16, 16)
const material = new THREE.MeshBasicMaterial({ color })
const marker = new THREE.Mesh(geometry, material)
marker.position.set(x, y, z)
scene.add(marker)
return marker
}建筑可视化
1. 创建建筑
javascript
class Building {
constructor(scene, config) {
this.scene = scene
this.config = config
this.floors = []
this.create()
}
create() {
const { width, depth, floors, floorHeight } = this.config
for (let i = 0; i < floors; i++) {
const floor = this.createFloor(i, width, depth, floorHeight)
this.floors.push(floor)
this.scene.add(floor)
}
}
createFloor(index, width, depth, height) {
const group = new THREE.Group()
// 地板
const floorGeometry = new THREE.BoxGeometry(width, 0.2, depth)
const floorMaterial = new THREE.MeshStandardMaterial({ color: 0xcccccc })
const floor = new THREE.Mesh(floorGeometry, floorMaterial)
floor.position.y = index * height
group.add(floor)
// 墙壁
const wallMaterial = new THREE.MeshStandardMaterial({
color: 0xffffff,
transparent: true,
opacity: 0.5
})
// 前墙
const frontWall = new THREE.Mesh(
new THREE.BoxGeometry(width, height, 0.1),
wallMaterial
)
frontWall.position.set(0, index * height + height / 2, depth / 2)
group.add(frontWall)
// 后墙
const backWall = new THREE.Mesh(
new THREE.BoxGeometry(width, height, 0.1),
wallMaterial
)
backWall.position.set(0, index * height + height / 2, -depth / 2)
group.add(backWall)
// 左墙
const leftWall = new THREE.Mesh(
new THREE.BoxGeometry(0.1, height, depth),
wallMaterial
)
leftWall.position.set(-width / 2, index * height + height / 2, 0)
group.add(leftWall)
// 右墙
const rightWall = new THREE.Mesh(
new THREE.BoxGeometry(0.1, height, depth),
wallMaterial
)
rightWall.position.set(width / 2, index * height + height / 2, 0)
group.add(rightWall)
return group
}
}性能优化
1. LOD (Level of Detail)
javascript
const lod = new THREE.LOD()
// 高精度模型
const highDetail = new THREE.Mesh(geometry, material)
lod.addLevel(highDetail, 0)
// 中精度模型
const mediumDetail = new THREE.Mesh(geometryMedium, material)
lod.addLevel(mediumDetail, 50)
// 低精度模型
const lowDetail = new THREE.Mesh(geometryLow, material)
lod.addLevel(lowDetail, 100)
scene.add(lod)2. 实例化
javascript
const geometry = new THREE.BoxGeometry(1, 1, 1)
const material = new THREE.MeshStandardMaterial({ color: 0x00ff00 })
const mesh = new THREE.InstancedMesh(geometry, material, 1000)
const matrix = new THREE.Matrix4()
for (let i = 0; i < 1000; i++) {
matrix.setPosition(
Math.random() * 100 - 50,
Math.random() * 100 - 50,
Math.random() * 100 - 50
)
mesh.setMatrixAt(i, matrix)
}
scene.add(mesh)最佳实践
1. 性能优化
- 使用 LOD 降低远处模型精度
- 实例化相同几何体
- 合并几何体减少 draw call
2. 用户体验
- 提供加载进度
- 支持触摸操作
- 添加交互提示
3. 视觉效果
- 合理的光照设置
- 后期处理效果
- 环境贴图