第一章 几何体与材质:从零搭建你的第一个3D世界

大家好,我是老张。做3D可视化这些年,我见过太多新手一上来就怼着复杂模型搞,结果连个立方体都渲染不出来。今天咱们就从最基础的几何体和材质聊起。说白了,这就是3D世界的「砖块」和「涂料」。

1.1 内置几何体:Three.js给你的「乐高积木」

Three.js内置了十几种基础几何体。我个人习惯把它们分成三类:

  • 基础体:BoxGeometry(立方体)、SphereGeometry(球体)、CylinderGeometry(圆柱体)
  • 扩展体:ConeGeometry(圆锥体)、TorusGeometry(圆环体)、TorusKnotGeometry(环面结)
  • 平面类:PlaneGeometry(平面)、CircleGeometry(圆形)、RingGeometry(环形)

每个几何体都有自己的一套参数。拿BoxGeometry举例,它的构造函数长这样:

const geometry = new THREE.BoxGeometry(width, height, depth, widthSegments, heightSegments, depthSegments);

前三个参数控制尺寸,后三个控制细分段数。我在项目中遇到过一个问题:默认的立方体只有6个面,每个面2个三角形。如果你要做地形变形,就得增加细分段数。比如:

// 一个细分后的立方体,可以用于顶点动画
const geometry = new THREE.BoxGeometry(2, 2, 2, 10, 10, 10);
我的小技巧:调试几何体时,可以临时把材质改成线框模式。这样能直观看到顶点分布和三角形结构。

1.2 材质系统:给几何体「穿衣服」

材质决定了物体看起来是什么样子。Three.js的材质系统分两大类:

材质类型 特点 适用场景
MeshBasicMaterial 不受光照影响,纯色显示 调试、UI元素、低多边形风格
MeshStandardMaterial 基于物理渲染,支持光照 真实感场景、产品展示
MeshPhongMaterial 经典高光材质,性能较好 老项目兼容、中等画质
MeshLambertMaterial 漫反射材质,无高光 快速预览、低配设备

你想想看,如果场景里没有光源,用MeshStandardMaterial就是一片漆黑。这时候MeshBasicMaterial就派上用场了。我记得刚学Three.js时,死活看不到球体,折腾了半天才发现是忘了加光源。

1.3 颜色与纹理贴图:让物体「活」起来

颜色是最直接的视觉属性。Three.js支持三种颜色表示法:

// 十六进制(最常用)
const color = 0xff0000;

// 字符串
const color = 'red';

// Color对象
const color = new THREE.Color(1, 0, 0);

纹理贴图就更有意思了。说白了就是把一张图片「贴」到几何体表面。加载纹理的代码很简单:

const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('path/to/texture.jpg');

const material = new THREE.MeshStandardMaterial({
  map: texture
});
曾经踩过的坑:纹理图片的尺寸最好是2的幂次方(256、512、1024)。否则在某些显卡上会出现奇怪的拉伸或性能问题。我曾经用了一张800x600的图片,结果在移动端直接卡成PPT。

1.4 实战:组合一个彩色立方体

光说不练假把式。咱们来写一个完整的示例:

// 1. 创建场景、相机、渲染器
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);

// 2. 创建几何体
const geometry = new THREE.BoxGeometry(1, 1, 1);

// 3. 创建材质(带纹理)
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('wood.jpg');
const material = new THREE.MeshStandardMaterial({
  map: texture,
  color: 0x8B4513,  // 叠加棕色
  roughness: 0.7,
  metalness: 0.1
});

// 4. 组合成网格对象
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

// 5. 添加光源
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 5, 5);
scene.add(light);

// 6. 渲染循环
function animate() {
  requestAnimationFrame(animate);
  cube.rotation.x += 0.01;
  cube.rotation.y += 0.01;
  renderer.render(scene, camera);
}
animate();

这段代码里,我用了MeshStandardMaterial配合纹理贴图。roughness控制粗糙度,metalness控制金属感。这两个参数配合好了,木头、石头、金属都能模拟出来。

1.5 材质属性的「调色盘」

除了map纹理,材质还有很多可调属性。我整理了一份常用清单:

  • color:基础颜色,与纹理混合
  • map:漫反射纹理
  • normalMap:法线贴图,制造凹凸感
  • roughness:粗糙度(0-1),0最光滑
  • metalness:金属度(0-1),1最像金属
  • emissive:自发光颜色
  • transparent:是否透明
  • opacity:透明度(0-1)

核心要点:几何体决定形状,材质决定外观。两者组合起来,就是3D世界的基本单元。别小看这些基础东西,我见过很多高级可视化项目,底层就是这些几何体堆出来的。

1.6 本章小结

嗯,到这里第一章就差不多了。咱们聊了内置几何体的参数、材质系统的分类、颜色和纹理的使用。最后还手写了一个完整的示例。下一章我会讲光源和阴影,到时候这些材质才能真正发挥威力。

对了,有个小建议:别光看代码,自己动手改改参数。把BoxGeometry改成SphereGeometry,把纹理换成纯色,看看效果有什么不同。实践出真知嘛。

公众号:蓝海资料掘金营,微信deep3321