第二篇:Three.js核心三要素:场景、相机、渲染器
引言
在Three.js的世界里,场景(Scene)、相机(Camera)和渲染器(Renderer)构成了最基础的"铁三角"。它们如同导演、摄像机和放映机,共同决定了3D内容的呈现方式。本篇将深入解析这三个核心组件,并通过Vue3实战案例展示它们的协同工作。
1. 场景(Scene):3D世界的容器
1.1 场景的本质
场景是Three.js的顶级容器,所有3D对象(网格、灯光、相机)都需要加入场景才能被渲染。可以将其理解为:
- 3D对象的舞台
- 空间坐标系的管理者
- 场景图(Scene Graph)的根节点
// 创建场景
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x87CEEB); // 设置天空蓝背景
1.2 场景层级管理
Three.js使用树状结构管理对象:
实战:使用Group组织对象
<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)
模拟人眼视角,近大远小效果:
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)
平行投影,无透视变形:
const aspect = window.innerWidth / window.innerHeight;
const camera = new THREE.OrthographicCamera(-5 * aspect, // left5 * aspect, // right5, // top-5, // bottom0.1, // near100 // far
);
2.3 相机类型对比
特性 | 透视相机 | 正交相机 |
---|---|---|
投影方式 | 锥形投影 | 平行投影 |
适用场景 | 真实感场景 | 技术图纸/2.5D游戏 |
尺寸感知 | 近大远小 | 保持物体原尺寸 |
参数复杂度 | 简单(4参数) | 复杂(6参数) |
典型应用 | 第一人称游戏 | CAD查看器 |
3. 渲染器(Renderer):将3D转为2D
3.1 渲染器核心配置
<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 响应式窗口处理
// 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 相机切换核心代码
<!-- 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 渲染循环适配多相机
// 在渲染循环中使用当前相机
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
npm install three-orbitcontrols
<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 控制器限制设置
// 限制垂直旋转角度
controls.minPolarAngle = Math.PI / 6; // 30度
controls.maxPolarAngle = Math.PI / 2; // 90度// 禁用平移
controls.enablePan = false;// 缩放限制
controls.minDistance = 3;
controls.maxDistance = 15;
6. 常见问题解答
Q1:物体在场景中不可见怎么办?
- 检查物体是否添加到场景
scene.add(mesh)
- 确认相机位置是否在物体前方
- 验证物体是否在相机裁剪范围内
Q2:如何实现画布透明背景?
const renderer = new THREE.WebGLRenderer({alpha: true, // 开启透明度premultipliedAlpha: false // 避免颜色预乘
});
scene.background = null; // 清除场景背景
Q3:为什么正交相机看到的物体是扁平的?
- 调整正交相机参数范围:
// 正确设置左右上下参数的比例关系
const aspect = window.innerWidth / window.innerHeight;
const height = 10;
const width = height * aspect;const camera = new THREE.OrthographicCamera(-width/2, width/2, // left, rightheight/2, -height/2, // top, bottom1, 1000
);
7. 总结
通过本篇学习,你已掌握:
- 场景的层级管理技巧(使用Group组织对象)
- 透视相机与正交相机的核心区别及适用场景
- 渲染器的关键配置项(抗锯齿/阴影/响应式)
- Vue3中实现多相机切换系统
- 使用OrbitControls实现交互控制
核心原理:Three.js的渲染流程本质上是将场景中的3D对象,通过相机的视角转换,最终由渲染器投影到2D画布上的过程。
下一篇预告
第三篇:几何体入门:内置几何体全解析
你将学习:
- 12种基础几何体的创建与参数调整
- 几何体顶点(Vertex)与面(Face)的底层原理
- 动态生成参数化几何体(如可调节分段数的球体)
- 几何体性能优化技巧(BufferGeometry详解)
- Vue3实现几何体参数实时调节面板
准备好探索Three.js的几何世界了吗?让我们从最简单的立方体开始,逐步揭开3D建模的神秘面纱!