前端技术 - 3D 图形基础

引言

随着 Web 技术的飞速发展,3D 图形在前端领域的应用越来越广泛。从产品展示到数据可视化,从游戏开发到虚拟现实,3D 技术正在重塑我们的数字体验。本文将带你入门 Three.js,这个最流行的 WebGL 库,让你快速掌握创建 3D 场景的核心技能。

什么是 Three.js?

Three.js 是一个基于 WebGL 的 JavaScript 3D 库,它简化了 WebGL 的复杂 API,让开发者能够用更少的代码创建令人惊叹的 3D 场景。

核心优势:

  • 简洁的 API 设计
  • 丰富的内置几何体和材质
  • 强大的光照系统
  • 完善的动画支持
  • 活跃的社区生态

快速开始

1. 基础场景搭建

xml 复制代码
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Three.js 入门</title>
  <style>
    body { margin: 0; }
    canvas { display: block; }
  </style>
</head>
<body>
  <script type="module">
    import * as THREE from 'https://unpkg.com/three@0.160.0/build/three.module.js';
    
    // 创建场景
    const scene = new THREE.Scene();
    scene.background = new THREE.Color(0x87CEEB); // 天空蓝背景
    
    // 创建相机
    const camera = new THREE.PerspectiveCamera(
      75, // 视野角度
      window.innerWidth / window.innerHeight, // 宽高比
      0.1, // 近裁剪面
      1000 // 远裁剪面
    );
    camera.position.z = 5;
    
    // 创建渲染器
    const renderer = new THREE.WebGLRenderer({ antialias: true });
    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);
    
    // 动画循环
    function animate() {
      requestAnimationFrame(animate);
      cube.rotation.x += 0.01;
      cube.rotation.y += 0.01;
      renderer.render(scene, camera);
    }
    
    animate();
    
    // 响应窗口大小变化
    window.addEventListener('resize', () => {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(window.innerWidth, window.innerHeight);
    });
  </script>
</body>
</html>

2. 核心概念解析

场景 (Scene)

场景是 3D 世界的容器,所有物体、灯光、相机都放在场景中。

ini 复制代码
const scene = new THREE.Scene();
// 添加雾效果
scene.fog = new THREE.Fog(0x87CEEB, 1, 10);

相机 (Camera)

相机决定了我们如何观察 3D 世界。

arduino 复制代码
// 透视相机 - 最常用
const perspectiveCamera = new THREE.PerspectiveCamera(
  fov, aspect, near, far
);

// 正交相机 - 用于 2D 或技术图纸
const orthoCamera = new THREE.OrthographicCamera(
  left, right, top, bottom, near, far
);

渲染器 (Renderer)

渲染器负责将场景绘制到屏幕上。

php 复制代码
const renderer = new THREE.WebGLRenderer({
  antialias: true,      // 抗锯齿
  alpha: true,          // 支持透明背景
  powerPreference: 'high-performance'
});

3. 几何体与材质

常用几何体

arduino 复制代码
// 立方体
const box = new THREE.BoxGeometry(width, height, depth);

// 球体
const sphere = new THREE.SphereGeometry(radius, widthSegments, heightSegments);

// 圆柱体
const cylinder = new THREE.CylinderGeometry(radiusTop, radiusBottom, height);

// 圆环
const torus = new THREE.TorusGeometry(radius, tube, radialSegments, tubularSegments);

// 平面
const plane = new THREE.PlaneGeometry(width, height);

材质类型

php 复制代码
// 基础材质 - 不受光照影响
const basicMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });

// 标准材质 - 物理光照
const standardMaterial = new THREE.MeshStandardMaterial({
  color: 0x00ff00,
  roughness: 0.5,      // 粗糙度
  metalness: 0.1       // 金属度
});

// 网格材质 - 线框模式
const meshMaterial = new THREE.MeshBasicMaterial({
  color: 0x0000ff,
  wireframe: true
});

// Phong 材质 - 光滑表面
const phongMaterial = new THREE.MeshPhongMaterial({
  color: 0xffff00,
  shininess: 100       // 高光强度
});

4. 光照系统

ini 复制代码
// 环境光 - 全局照明
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);

// 平行光 - 模拟太阳光
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(5, 10, 5);
scene.add(directionalLight);

// 点光源 - 类似灯泡
const pointLight = new THREE.PointLight(0xff0000, 1, 100);
pointLight.position.set(0, 5, 0);
scene.add(pointLight);

// 聚光灯 - 舞台灯光效果
const spotLight = new THREE.SpotLight(0x00ff00, 1);
spotLight.position.set(0, 10, 0);
spotLight.angle = Math.PI / 4;
spotLight.penumbra = 0.1;
scene.add(spotLight);

5. 动画与交互

基础动画

ini 复制代码
const clock = new THREE.Clock();

function animate() {
  requestAnimationFrame(animate);
  
  const delta = clock.getDelta();
  
  // 旋转
  cube.rotation.y += delta;
  
  // 缩放
  sphere.scale.x = Math.sin(Date.now() * 0.001);
  sphere.scale.y = Math.sin(Date.now() * 0.001);
  
  // 位移
  torus.position.x = Math.sin(Date.now() * 0.0005) * 2;
  
  renderer.render(scene, camera);
}

鼠标交互

ini 复制代码
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();

window.addEventListener('click', (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);
  
  if (intersects.length > 0) {
    // 点击到了物体
    intersects[0].object.material.color.set(0xff0000);
  }
});

// 鼠标移动
window.addEventListener('mousemove', (event) => {
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
});

6. 加载外部模型

ini 复制代码
import { GLTFLoader } from 'https://unpkg.com/three@0.160.0/examples/jsm/loaders/GLTFLoader.js';

const loader = new GLTFLoader();

loader.load('path/to/model.glb', (gltf) => {
  const model = gltf.scene;
  
  // 调整位置和缩放
  model.position.set(0, 0, 0);
  model.scale.set(1, 1, 1);
  
  // 添加动画
  const mixer = new THREE.AnimationMixer(model);
  const action = mixer.clipAction(gltf.animations[0]);
  action.play();
  
  scene.add(model);
  
  // 在动画循环中更新
  function animate() {
    requestAnimationFrame(animate);
    mixer.update(clock.getDelta());
    renderer.render(scene, camera);
  }
});

实战案例:创建 3D 产品展示

ini 复制代码
// 创建产品展示场景
function createProductShowcase() {
  const scene = new THREE.Scene();
  
  // 添加网格地面
  const gridHelper = new THREE.GridHelper(20, 20);
  scene.add(gridHelper);
  
  // 添加多个物体
  const objects = [];
  const geometries = [
    new THREE.BoxGeometry(1, 1, 1),
    new THREE.SphereGeometry(0.5, 32, 32),
    new THREE.TorusGeometry(0.5, 0.2, 16, 100)
  ];
  
  geometries.forEach((geo, index) => {
    const material = new THREE.MeshStandardMaterial({
      color: new THREE.Color().setHSL(index / geometries.length, 1, 0.5),
      roughness: 0.3,
      metalness: 0.7
    });
    
    const mesh = new THREE.Mesh(geo, material);
    mesh.position.x = (index - 1) * 2;
    mesh.position.y = 0.5;
    scene.add(mesh);
    objects.push(mesh);
  });
  
  // 添加灯光
  const light = new THREE.DirectionalLight(0xffffff, 1);
  light.position.set(5, 10, 5);
  scene.add(light);
  
  return { scene, objects };
}

性能优化建议

  1. 使用几何体复用:多个相同物体共享同一个几何体和材质
  2. 实例化渲染 :使用 InstancedMesh 渲染大量相同物体
  3. 纹理压缩:使用压缩纹理格式(如 DDS、KTX2)
  4. LOD 技术:根据距离使用不同精度的模型
  5. 裁剪不必要的物体:使用视锥体裁剪

总结

Three.js 为前端开发者提供了强大的 3D 创作能力。通过本文的介绍,你已经掌握了:

  • 场景、相机、渲染器的基础搭建
  • 几何体和材质的使用
  • 光照系统的配置
  • 动画和交互的实现
  • 外部模型的加载
相关推荐
狼丶宇先森12 小时前
vue-sign-canvas v2 重构复盘:从 Vue 2 签名板到 Vue 3 + TypeScript 组件库
前端·vue.js·重构·typescript·开源软件·canvas
迁旭12 小时前
Claude Code 项目 /init 命令详解
前端·javascript·chrome·机器学习·语言模型·gpt-3
ZC跨境爬虫12 小时前
跟着 MDN 学CSS day_9:(深入掌握CSS选择器核心技能测试)
前端·css·ui·html
Daybreak12 小时前
Convex + Next.js + Clerk 上线求生指南:六个坑,一个比一个离谱
前端
marsh020612 小时前
53 openclaw插件市场:开发与发布自己的插件
开发语言·前端·javascript
Daybreak12 小时前
AI Chat 重构:从全屏页面到右侧可折叠侧边栏,7 个 Zustand Store 合并为 1 个 Hook
前端
Daybreak12 小时前
从硬编码路由到 ReAct Agent Loop:AI Chat 的工具调用重构
前端
用户329104422504113 小时前
基于 Claude Code 实现 CI/CD 完整流程
前端·后端
星栈13 小时前
别让 API 跳去登录页:我在 Axum 里做了认证失败双通道
前端·后端·开源