1、3D网页基础:什么是3D网页、WebGL与Three.js简介、3D坐标系与相机概念

各位同学,咱们今天正式开讲。做3D网页开发这些年,我见过太多人一上来就怼着Three.js的API猛学,结果连最基本的坐标系都没搞明白。嗯,这就像你还没学会走路就想跑马拉松——摔得鼻青脸肿是必然的。

所以这一章,咱们先把地基打牢。我会用最直白的方式,带你搞懂三个核心问题:3D网页到底是什么?WebGL和Three.js是什么关系?3D空间里的坐标和相机到底怎么玩?

1.1 什么是3D网页?

说白了,3D网页就是能在浏览器里展示三维立体内容的页面。你平时刷的淘宝商品360度旋转展示、那些炫酷的汽车配置器、甚至是一些在线游戏,背后都是3D网页技术。

我刚开始接触这个领域时,有个误区特别普遍——很多人以为3D网页就是放个3D模型进去就完事了。其实远不止这么简单。真正的3D网页,要处理的是三维空间中的物体、光照、阴影、材质、交互等一系列问题。

核心要点:3D网页 ≠ 3D模型展示。它是一个完整的3D交互环境,用户可以在其中旋转、缩放、点击、拖拽,甚至进行复杂的物理模拟。

你想想看,一个普通的网页,元素都是平面的,上下左右移动。但3D网页多了一个维度——深度。这就带来了完全不同的体验。我记得有一次给客户做产品展示,他们要求「让用户能像把玩实物一样在网页上旋转产品」。这就是3D网页的典型应用场景。

1.2 WebGL与Three.js简介

好,现在问题来了:浏览器本身是不懂3D的。那怎么让它在网页上渲染出3D画面呢?

答案就是WebGL

WebGL(Web Graphics Library)是浏览器内置的一个底层图形API。它直接跟显卡打交道,告诉显卡「这里画个三角形,那里打个光」。但问题是,WebGL的API非常底层,写起来极其繁琐。我早期做过一个项目,用原生WebGL画一个旋转的立方体,光着色器代码就写了200多行。说实话,那感觉就像用螺丝刀和锤子造一辆汽车——能造出来,但效率太低了。

这时候,Three.js就登场了。

Three.js是一个基于WebGL封装的高级3D库。它把WebGL那些复杂的底层操作,封装成了简单易用的API。你只需要几行代码,就能创建一个3D场景。

我的个人经验:如果你不是要开发一个全新的3D引擎,或者对底层图形学有特殊需求,直接用Three.js就好。我见过太多人试图「从零造轮子」,结果项目周期拖了半年还没上线。用Three.js,一周就能出原型。

来看个最简单的例子,感受一下Three.js的简洁:

// 创建场景
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(1, 1, 1);
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();

看到了吗?不到20行代码,一个旋转的绿色立方体就出来了。如果用原生WebGL写,这个量级的代码至少要翻5倍。

对比项 原生WebGL Three.js
学习曲线 陡峭(需要懂着色器、矩阵运算) 平缓(面向对象,API友好)
开发效率 低(手写大量底层代码) 高(封装了常用功能)
灵活性 极高(可以控制每一个像素) 较高(可扩展,但受限于框架)
适用场景 引擎开发、特殊效果 绝大多数3D网页应用

避坑指南:我曾经犯过一个错误——在移动端项目里直接用了Three.js的默认配置,结果页面卡成PPT。后来才发现,Three.js默认开启了抗锯齿和阴影,这对移动端GPU是巨大的负担。记住:移动端开发一定要做性能优化,关闭不必要的特效。

1.3 3D坐标系与相机概念

搞清楚了工具,接下来咱们聊聊3D空间里的「规矩」。

1.3.1 3D坐标系

在Three.js中,默认使用的是右手坐标系。什么意思呢?

  • X轴:向右为正方向
  • Y轴:向上为正方向
  • Z轴:朝向屏幕外为正方向(也就是从屏幕指向你)

我刚开始学的时候,总把Z轴的方向搞反。后来想了个笨办法:伸出右手,拇指指向X轴正方向(右),食指指向Y轴正方向(上),中指指向自己——这就是Z轴正方向。嗯,这招挺管用,你可以试试。

每个3D物体在场景中都有一个位置(position),由三个数值组成:(x, y, z)。比如:

cube.position.set(2, 1, -3);  // 把立方体放在x=2, y=1, z=-3的位置

除了位置,物体还有旋转(rotation)缩放(scale)。这三个属性共同决定了物体在3D空间中的状态。

1.3.2 相机概念

相机,说白了就是你观察3D世界的「眼睛」。在Three.js中,有两种最常用的相机:

1. 透视相机(PerspectiveCamera)

这是最接近人眼视觉的相机。它有近大远小的效果,适合做游戏、产品展示等需要真实感的场景。

const camera = new THREE.PerspectiveCamera(
    75,                     // 视野角度(FOV),类似人眼的视角范围
    width / height,         // 宽高比,通常用窗口宽高比
    0.1,                    // 近裁剪面,相机能看到的最远距离
    1000                    // 远裁剪面,相机能看到的最远距离
);

这里有个坑,我踩过好几次:近裁剪面和远裁剪面的值设置不当。如果近裁剪面设得太大,靠近相机的物体会被「切掉」;如果远裁剪面设得太小,远处的物体会突然消失。我建议近裁剪面设0.1,远裁剪面根据场景大小来定,一般1000够用。

2. 正交相机(OrthographicCamera)

这种相机没有近大远小的效果,物体无论远近看起来都一样大。适合做2.5D游戏、UI界面、技术图纸等。

const camera = new THREE.OrthographicCamera(
    -width / 2,   // 左边界
    width / 2,    // 右边界
    height / 2,   // 上边界
    -height / 2,  // 下边界
    0.1,          // 近裁剪面
    1000          // 远裁剪面
);

核心区别:透视相机模拟人眼,有景深感;正交相机保持物体真实比例,无透视变形。选哪个?看你的应用场景。我做产品展示时用透视相机,做数据可视化时用正交相机。

1.3.3 相机控制

光有相机还不够,你还得能控制它。Three.js提供了OrbitControls,让你可以用鼠标拖拽旋转视角、滚轮缩放:

import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;  // 开启惯性效果,让操作更平滑
controls.dampingFactor = 0.05; // 惯性系数
controls.autoRotate = false;   // 是否自动旋转

我个人习惯在开发阶段一直开着OrbitControls,方便调试。但生产环境里,要根据需求决定是否开放给用户。

小技巧:如果你想让相机围绕某个物体旋转,可以设置controls.target。比如让相机围绕一个模型旋转:controls.target.copy(model.position)。这样用户旋转视角时,始终以模型为中心。

本章小结

好了,这一章的内容就到这里。咱们回顾一下:

  • 3D网页是在浏览器中展示三维交互内容的技术,不仅仅是放个模型那么简单
  • WebGL是底层图形API,Three.js是它的高级封装,建议初学者直接上手Three.js
  • 3D坐标系使用右手坐标系,X右、Y上、Z外
  • 相机分为透视相机和正交相机,前者有近大远小效果,后者保持比例不变

下一章,咱们会动手搭建第一个完整的3D场景。到时候你会发现,有了这些基础,写代码就像搭积木一样简单。

记住:地基打得牢,房子才盖得高。别急着炫技,先把这些概念吃透。