第二篇:Three.js核心三要素:场景、相机、渲染器

第二篇:Three.js核心三要素:场景、相机、渲染器

引言

在Three.js的世界里,场景(Scene)、相机(Camera)和渲染器(Renderer)构成了最基础的"铁三角"。它们如同导演、摄像机和放映机,共同决定了3D内容的呈现方式。本篇将深入解析这三个核心组件,并通过Vue3实战案例展示它们的协同工作。


1. 场景(Scene):3D世界的容器
1.1 场景的本质

场景是Three.js的顶级容器,所有3D对象(网格、灯光、相机)都需要加入场景才能被渲染。可以将其理解为:

  • 3D对象的舞台
  • 空间坐标系的管理者
  • 场景图(Scene Graph)的根节点
js 复制代码
// 创建场景
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x87CEEB); // 设置天空蓝背景
1.2 场景层级管理

Three.js使用树状结构管理对象:
Scene Camera Mesh1 Group Mesh2 Mesh3

实战:使用Group组织对象

vue 复制代码
<script setup>
import { ref, onMounted } from 'vue';
import * as THREE from 'three';

const scene = new THREE.Scene();

// 创建汽车组
const carGroup = new THREE.Group();
scene.add(carGroup);

// 车身
const bodyGeo = new THREE.BoxGeometry(2, 0.5, 1);
const bodyMat = new THREE.MeshBasicMaterial({ color: 0xff0000 });
const body = new THREE.Mesh(bodyGeo, bodyMat);
carGroup.add(body);

// 车轮
const wheelGeo = new THREE.CylinderGeometry(0.3, 0.3, 0.2, 16);
wheelGeo.rotateZ(Math.PI/2); // 旋转90度使其立起
const wheelMat = new THREE.MeshBasicMaterial({ color: 0x333333 });

const wheel1 = new THREE.Mesh(wheelGeo, wheelMat);
wheel1.position.set(0.7, -0.3, 0.5);
carGroup.add(wheel1);

const wheel2 = wheel1.clone();
wheel2.position.z = -0.5;
carGroup.add(wheel2);

// 移动整个汽车组
carGroup.position.x = -3;
</script>

关键点Group允许将多个对象作为单一实体操作,大幅简化复杂对象的变换控制。


2. 相机(Camera):观察世界的眼睛
2.1 透视相机(PerspectiveCamera)

模拟人眼视角,近大远小效果:

js 复制代码
const camera = new THREE.PerspectiveCamera(
  75, // 视野角度(FOV)
  window.innerWidth / window.innerHeight, // 宽高比
  0.1, // 近裁剪面(near)
  1000 // 远裁剪面(far)
);
camera.position.set(0, 2, 5); // 设置相机位置
2.2 正交相机(OrthographicCamera)

平行投影,无透视变形:

js 复制代码
const aspect = window.innerWidth / window.innerHeight;
const camera = new THREE.OrthographicCamera(
  -5 * aspect, // left
  5 * aspect,  // right
  5,           // top
  -5,          // bottom
  0.1,         // near
  100          // far
);
2.3 相机类型对比
特性 透视相机 正交相机
投影方式 锥形投影 平行投影
适用场景 真实感场景 技术图纸/2.5D游戏
尺寸感知 近大远小 保持物体原尺寸
参数复杂度 简单(4参数) 复杂(6参数)
典型应用 第一人称游戏 CAD查看器

3. 渲染器(Renderer):将3D转为2D
3.1 渲染器核心配置
vue 复制代码
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';

const canvasRef = ref(null);

onMounted(() => {
  const renderer = new THREE.WebGLRenderer({
    canvas: canvasRef.value,
    antialias: true, // 开启抗锯齿
    alpha: true,     // 允许透明背景
    powerPreference: "high-performance" // 高性能模式
  });
  
  // 设置像素比和尺寸
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
  renderer.setSize(window.innerWidth, window.innerHeight);
  
  // 开启阴影
  renderer.shadowMap.enabled = true;
  renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 柔和阴影
});
</script>
3.2 响应式窗口处理
js 复制代码
// Vue3中使用@vueuse/core监听窗口变化
import { useWindowSize } from '@vueuse/core';

const { width, height } = useWindowSize();

watch([width, height], () => {
  camera.aspect = width.value / height.value;
  camera.updateProjectionMatrix(); // 必须更新相机
  
  renderer.setSize(width.value, height.value);
});

4. 综合实战:多相机切换系统
4.1 项目结构
复制代码
src/
  ├── components/
  │    ├── CameraSystem.vue   // 相机系统组件
  │    └── SceneObjects.vue   // 场景对象组件
  └── App.vue
4.2 相机切换核心代码
vue 复制代码
<!-- CameraSystem.vue -->
<script setup>
import { ref } from 'vue';

// 相机枚举类型
const CameraType = {
  PERSPECTIVE: 0,
  ORTHOGRAPHIC: 1
};

const currentCamera = ref(CameraType.PERSPECTIVE);
const cameras = {
  [CameraType.PERSPECTIVE]: createPerspectiveCamera(),
  [CameraType.ORTHOGRAPHIC]: createOrthographicCamera()
};

function createPerspectiveCamera() {
  const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
  camera.position.set(0, 2, 5);
  return camera;
}

function createOrthographicCamera() {
  const aspect = window.innerWidth / window.innerHeight;
  const camera = new THREE.OrthographicCamera(-5*aspect, 5*aspect, 5, -5, 0.1, 100);
  camera.position.set(0, 2, 5);
  camera.lookAt(0, 0, 0);
  return camera;
}

function toggleCamera() {
  currentCamera.value = currentCamera.value === CameraType.PERSPECTIVE 
    ? CameraType.ORTHOGRAPHIC 
    : CameraType.PERSPECTIVE;
}
</script>

<template>
  <button @click="toggleCamera" class="camera-toggle">
    {{ currentCamera === CameraType.PERSPECTIVE ? '正交视图' : '透视视图' }}
  </button>
</template>
4.3 渲染循环适配多相机
js 复制代码
// 在渲染循环中使用当前相机
function animate() {
  requestAnimationFrame(animate);
  
  // 获取当前激活的相机
  const activeCamera = cameras[currentCamera.value];
  
  // 旋转场景物体
  scene.traverse(obj => {
    if (obj.isMesh) obj.rotation.y += 0.01;
  });
  
  renderer.render(scene, activeCamera);
}
4.4 相机切换效果对比

5. 高级技巧:相机控制器
5.1 引入OrbitControls
bash 复制代码
npm install three-orbitcontrols
vue 复制代码
<script setup>
import { OrbitControls } from 'three-orbitcontrols';

onMounted(() => {
  const controls = new OrbitControls(camera, renderer.domElement);
  
  // 配置控制器参数
  controls.enableDamping = true; // 启用阻尼效果
  controls.dampingFactor = 0.05; // 阻尼系数
  controls.autoRotate = true;    // 自动旋转
  controls.autoRotateSpeed = 1.0;
  
  // 在渲染循环中更新控制器
  function animate() {
    requestAnimationFrame(animate);
    controls.update(); // 必须每帧更新
    renderer.render(scene, camera);
  }
});
</script>
5.2 控制器限制设置
js 复制代码
// 限制垂直旋转角度
controls.minPolarAngle = Math.PI / 6; // 30度
controls.maxPolarAngle = Math.PI / 2; // 90度

// 禁用平移
controls.enablePan = false;

// 缩放限制
controls.minDistance = 3;
controls.maxDistance = 15;

6. 常见问题解答

Q1:物体在场景中不可见怎么办?

  1. 检查物体是否添加到场景 scene.add(mesh)
  2. 确认相机位置是否在物体前方
  3. 验证物体是否在相机裁剪范围内

Q2:如何实现画布透明背景?

js 复制代码
const renderer = new THREE.WebGLRenderer({
  alpha: true, // 开启透明度
  premultipliedAlpha: false // 避免颜色预乘
});
scene.background = null; // 清除场景背景

Q3:为什么正交相机看到的物体是扁平的?

  • 调整正交相机参数范围:
js 复制代码
// 正确设置左右上下参数的比例关系
const aspect = window.innerWidth / window.innerHeight;
const height = 10;
const width = height * aspect;

const camera = new THREE.OrthographicCamera(
  -width/2, width/2, // left, right
  height/2, -height/2, // top, bottom
  1, 1000
);

7. 总结

通过本篇学习,你已掌握:

  1. 场景的层级管理技巧(使用Group组织对象)
  2. 透视相机与正交相机的核心区别及适用场景
  3. 渲染器的关键配置项(抗锯齿/阴影/响应式)
  4. Vue3中实现多相机切换系统
  5. 使用OrbitControls实现交互控制

核心原理:Three.js的渲染流程本质上是将场景中的3D对象,通过相机的视角转换,最终由渲染器投影到2D画布上的过程。


下一篇预告

第三篇:几何体入门:内置几何体全解析

你将学习:

  • 12种基础几何体的创建与参数调整
  • 几何体顶点(Vertex)与面(Face)的底层原理
  • 动态生成参数化几何体(如可调节分段数的球体)
  • 几何体性能优化技巧(BufferGeometry详解)
  • Vue3实现几何体参数实时调节面板

准备好探索Three.js的几何世界了吗?让我们从最简单的立方体开始,逐步揭开3D建模的神秘面纱!

相关推荐
新手小新12 分钟前
C++游戏开发(2)
开发语言·前端·c++
你的电影很有趣42 分钟前
lesson30:Python迭代三剑客:可迭代对象、迭代器与生成器深度解析
开发语言·python
程序员编程指南2 小时前
Qt 嵌入式界面优化技术
c语言·开发语言·c++·qt
q__y__L2 小时前
C#线程同步(二)锁
开发语言·性能优化·c#
星月心城3 小时前
Promise之什么是promise?(01)
javascript
云泽8083 小时前
数据结构前篇 - 深入解析数据结构之复杂度
c语言·开发语言·数据结构
Mintopia3 小时前
🧱 用三维点亮前端宇宙:构建你自己的 Three.js 组件库
前端·javascript·three.js
卷卷的小趴菜学编程3 小时前
Qt-----初识
开发语言·c++·qt·sdk·qt介绍
天天进步20153 小时前
Python游戏开发引擎设计与实现
开发语言·python·pygame