普通视图

发现新文章,点击刷新页面。
今天 — 2026年1月21日首页

学习Three.js--纹理贴图(Texture)

2026年1月21日 15:01

学习Three.js--纹理贴图(Texture)

前置核心说明

纹理贴图是 Three.js 中让3D模型呈现真实外观的核心手段,本质是将2D图片(纹理)「贴」到3D几何体表面,替代单一的纯色材质,实现照片级的视觉效果(如墙面纹理、地面瓷砖、金属质感、木纹等)。

核心规则

  1. 核心流程加载图片 → 创建纹理对象(Texture) → 绑定到材质.map属性 → 几何体通过UV坐标映射纹理
  2. 颜色空间必设:加载纹理后必须设置 texture.colorSpace = THREE.SRGBColorSpace,否则图片会出现偏色(Three.js r152+ 版本新增,适配真实色彩);
  3. UV坐标是桥梁:UV坐标(2D)关联纹理图片和几何体顶点(3D),是纹理「贴在哪个位置」的核心控制手段;
  4. 材质适配:所有 Mesh 系列材质(MeshBasicMaterial/MeshStandardMaterial 等)都支持 map 纹理属性,仅 Line/Points/Sprite 材质不支持。

一、纹理核心概念与基础加载

1. 核心术语解析

术语 核心说明
纹理对象(Texture) Three.js 对2D图片的封装,包含图片数据、映射规则、重复模式等属性
UV坐标 2D纹理坐标系(U=横向,V=纵向),范围默认0~1,(0,0)=图片左下角,(1,1)=图片右上角
纹理加载器(TextureLoader) Three.js 专门用于加载图片并生成纹理对象的工具类
映射(Mapping) 纹理通过UV坐标与几何体顶点的绑定关系,决定图片哪部分贴在几何体哪个位置

2. 纹理加载(TextureLoader):完整用法与参数

TextureLoader 是加载纹理的核心工具,支持单张加载、批量加载,可处理加载进度/错误/完成回调。

2.1 基础加载
// 1. 创建纹理加载器实例
const texLoader = new THREE.TextureLoader();

// 2. 加载图片并创建纹理对象
// 语法:texLoader.load(图片路径, 加载完成回调, 加载进度回调, 加载错误回调)
const texture = texLoader.load(
  './gravelly_sand_diff_1k.jpg', // 必传:图片路径(本地/CDN)
  (texture) => { // 可选:加载完成回调
    console.log('纹理加载完成', texture);
  },
  (xhr) => { // 可选:加载进度回调(xhr=XMLHttpRequest)
    console.log(`加载进度:${(xhr.loaded / xhr.total) * 100}%`);
  },
  (err) => { // 可选:加载错误回调
    console.error('纹理加载失败', err);
  }
);

// 3. 关键:设置颜色空间(避免图片偏色,r152+必加)
texture.colorSpace = THREE.SRGBColorSpace;
2.2 TextureLoader 核心参数(load方法)
参数名 类型 必填 说明
url String 图片路径(支持本地相对路径、CDN链接、Base64)
onLoad Function 加载完成回调,参数为生成的Texture对象
onProgress Function 加载进度回调,参数为XMLHttpRequest对象
onError Function 加载失败回调,参数为错误对象
2.3 批量加载纹理(TextureLoader+Promise)
// 封装批量加载函数
async function loadTextures(urls) {
  const loader = new THREE.TextureLoader();
  const textures = [];
  for (const url of urls) {
    const texture = await new Promise((resolve, reject) => {
      loader.load(url, resolve, null, reject);
    });
    texture.colorSpace = THREE.SRGBColorSpace;
    textures.push(texture);
  }
  return textures;
}

// 使用:加载多张纹理
const urls = ['./texture1.jpg', './texture2.jpg'];
loadTextures(urls).then(textures => {
  console.log('所有纹理加载完成', textures);
});
2.4 跨域问题解决

加载本地图片或跨域CDN图片时,若出现 THREE.WebGLRenderer: Texture has no image data 错误:

  1. 本地开发:启动HTTP服务(如VSCode的Live Server),不要直接打开HTML文件;
  2. CDN/服务器:配置图片服务器的CORS跨域头(Access-Control-Allow-Origin: *);
  3. 临时方案:将图片转为Base64格式嵌入代码(适合小图片)。

二、UV坐标核心解析(纹理映射的关键)

UV坐标是「2D纹理」和「3D几何体」的桥梁,决定了纹理图片的哪部分会贴在几何体的哪个面上。

1. UV坐标基础规则

UV坐标 对应图片位置 说明
(0, 0) 图片左下角 纹理原点
(1, 0) 图片右下角 U轴(横向)最大值
(0, 1) 图片左上角 V轴(纵向)最大值
(1, 1) 图片右上角 UV坐标最大值
(0.5, 0.5) 图片中心 UV中点

2. 自定义UV坐标(BufferGeometry)

预设几何体(BoxGeometry/SphereGeometry)已内置UV坐标,若使用自定义 BufferGeometry,需手动定义UV属性:

2.1 完整映射(纹理全部显示)
// 步骤1:创建自定义几何体(4个顶点的矩形)
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
  -0.5, -0.5, 0, // 顶点0
   0.5, -0.5, 0, // 顶点1
   0.5,  0.5, 0, // 顶点2
  -0.5,  0.5, 0  // 顶点3
]);
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));

// 步骤2:定义UV坐标(完整映射,4个顶点对应图片4个角)
const uvs = new Float32Array([
  0, 0,  // 顶点0 → 图片左下角
  1, 0,  // 顶点1 → 图片右下角
  1, 1,  // 顶点2 → 图片右上角
  0, 1   // 顶点3 → 图片左上角
]);
// 绑定UV属性:itemSize=2(每2个值为一组UV坐标)
geometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2));
2.2 局部映射(仅显示纹理1/4区域)
// UV坐标范围设为0~0.5,仅映射图片左下角1/4区域
const uvs = new Float32Array([
  0,   0,   // 顶点0 → 图片(0,0)
  0.5, 0,   // 顶点1 → 图片(0.5,0)
  0.5, 0.5, // 顶点2 → 图片(0.5,0.5)
  0,   0.5  // 顶点3 → 图片(0,0.5)
]);
geometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2));
2.3 圆形几何体映射(CircleGeometry)

CircleGeometry 内置了适配圆形的UV坐标,无需自定义,直接绑定纹理即可:

// 创建圆形几何体(半径2,分段数100,越高分段越平滑)
const geometry = new THREE.CircleGeometry(2, 100);

// 加载纹理
const texLoader = new THREE.TextureLoader();
const texture = texLoader.load('./gravelly_sand_diff_1k.jpg');
texture.colorSpace = THREE.SRGBColorSpace;

// 创建材质(双面渲染,避免背面不可见)
const material = new THREE.MeshBasicMaterial({
  map: texture, // 绑定纹理
  side: THREE.DoubleSide
});

// 创建网格对象
const circleMesh = new THREE.Mesh(geometry, material);
scene.add(circleMesh);

3. 预设几何体UV特点

几何体 UV坐标特点 适用场景
BoxGeometry 每个面独立UV,纹理会贴到6个面上 立方体、盒子
SphereGeometry UV按经纬度分布,纹理包裹球体 星球、球体模型
PlaneGeometry 单平面UV,完整映射纹理 地面、墙面
CircleGeometry 圆形UV,纹理适配圆形 圆形地面、雷达图

三、纹理对象核心属性(参数详解+用法)

纹理对象(Texture)的核心属性决定了纹理的显示方式(重复、偏移、旋转等),是实现瓷砖阵列、UV动画的关键,以下是高频使用的属性:

1. 重复模式:wrapS / wrapT

控制纹理在U轴(横向)/V轴(纵向)超出0~1范围时的显示模式,必须配合 repeat 属性使用。

属性值 说明 示例
THREE.ClampToEdgeWrapping(默认) 超出范围时,拉伸纹理最后一行/列像素 纹理只显示一次,边缘拉伸
THREE.RepeatWrapping 超出范围时,重复显示纹理 实现瓷砖、地板阵列效果
THREE.MirroredRepeatWrapping 超出范围时,镜像重复显示纹理 无缝拼接的对称纹理
用法示例(地面瓷砖阵列)
const geometry = new THREE.PlaneGeometry(10, 10); // 10x10的地面
const texLoader = new THREE.TextureLoader();
const texture = texLoader.load('./cizhuang.jpg');
texture.colorSpace = THREE.SRGBColorSpace;

// 1. 设置重复模式(U/V轴都重复)
texture.wrapS = THREE.RepeatWrapping; // U轴(横向)
texture.wrapT = THREE.RepeatWrapping; // V轴(纵向)

// 2. 设置重复数量(U轴10次,V轴10次)
texture.repeat.set(10, 10); // 格式:repeat.set(U重复数, V重复数)

// 3. 创建材质并绑定纹理
const material = new THREE.MeshLambertMaterial({ map: texture });
const groundMesh = new THREE.Mesh(geometry, material);
groundMesh.rotation.x = -Math.PI / 2; // 旋转为地面
scene.add(groundMesh);

2. 重复数量:repeat

  • 类型:THREE.Vector2(包含x/y属性,对应U/V轴);
  • 作用:设置纹理在U/V轴的重复次数,值越大,纹理显示越多块;
  • 用法:
    texture.repeat.x = 10; // U轴重复10次
    texture.repeat.y = 10; // V轴重复10次
    // 或批量设置
    texture.repeat.set(10, 10);
    

3. 偏移:offset

  • 类型:THREE.Vector2(x=U轴偏移,y=V轴偏移);
  • 范围:0~1(偏移1=整个纹理宽度/高度);
  • 作用:控制纹理在几何体上的偏移位置,常用于UV动画;
  • 用法:
    texture.offset.x = 0.5; // U轴向右偏移50%
    texture.offset.y = 0.5; // V轴向上偏移50%
    // 或批量设置
    texture.offset.set(0.5, 0.5);
    

4. 旋转:rotation

  • 类型:Number(弧度);
  • 作用:纹理绕中心点旋转,单位为弧度;
  • 配合属性:center(设置旋转中心,默认(0.5,0.5)即纹理中心);
  • 用法:
    texture.rotation = Math.PI / 4; // 旋转45°
    texture.center.set(0.5, 0.5); // 绕纹理中心旋转(默认值)
    // 绕图片左下角旋转
    texture.center.set(0, 0);
    

5. 纹理过滤:magFilter / minFilter

控制纹理在「放大/缩小」时的显示质量,解决纹理模糊/锯齿问题:

属性 作用 推荐值
magFilter 纹理放大时的过滤方式 THREE.LinearFilter(线性过滤,平滑)
minFilter 纹理缩小时的过滤方式 THREE.LinearMipmapLinearFilter(Mipmap线性过滤,最清晰)
用法:
// 提升纹理显示质量(解决模糊)
texture.magFilter = THREE.LinearFilter;
texture.minFilter = THREE.LinearMipmapLinearFilter;
texture.generateMipmaps = true; // 生成Mipmap(minFilter生效必备)

6. 各向异性过滤:anisotropy

  • 类型:Number;
  • 作用:提升纹理在倾斜视角下的清晰度(如地面纹理斜看时不模糊);
  • 用法:
    // 获取渲染器支持的最大各向异性值
    const maxAnisotropy = renderer.capabilities.getMaxAnisotropy();
    texture.anisotropy = maxAnisotropy; // 设置为最大值,效果最佳
    

四、纹理高级应用场景(完整用法+示例)

1. UV动画(纹理滚动)

通过动态修改 texture.offset 实现纹理滚动(如流水、火焰、移动的地面):

// 加载纹理
const texLoader = new THREE.TextureLoader();
const texture = texLoader.load('./water.jpg');
texture.colorSpace = THREE.SRGBColorSpace;
// 开启重复模式(动画更自然)
texture.wrapS = THREE.RepeatWrapping;
texture.repeat.x = 5; // U轴重复5次

// 动画循环
function animate() {
  requestAnimationFrame(animate);
  // U轴偏移量递增,实现纹理向右滚动
  texture.offset.x += 0.01;
  // 可选:V轴偏移,实现斜向滚动
  // texture.offset.y += 0.005;
  
  controls.update();
  renderer.render(scene, camera);
}
animate();

2. 阵列+UV动画组合(瓷砖地面滚动)

// 加载瓷砖纹理
const texture = texLoader.load('./cizhuang.jpg');
texture.colorSpace = THREE.SRGBColorSpace;

// 1. 设置阵列模式
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set(10, 10); // 10x10瓷砖

// 2. 动画循环(UV滚动)
function animate() {
  requestAnimationFrame(animate);
  texture.offset.x += 0.005; // 缓慢向右滚动
  texture.offset.y += 0.002; // 缓慢向上滚动
  
  controls.update();
  renderer.render(scene, camera);
}
animate();

3. 多纹理叠加(基础色+法线+粗糙度)

PBR材质(MeshStandardMaterial)支持多纹理叠加,实现更真实的质感:

// 加载多组纹理
const texLoader = new THREE.TextureLoader();
const colorMap = texLoader.load('./wood_color.jpg'); // 基础色纹理
const normalMap = texLoader.load('./wood_normal.jpg'); // 法线纹理(凹凸感)
const roughnessMap = texLoader.load('./wood_roughness.jpg'); // 粗糙度纹理

// 设置颜色空间(仅基础色纹理需要)
colorMap.colorSpace = THREE.SRGBColorSpace;

// 创建PBR材质,绑定多纹理
const material = new THREE.MeshStandardMaterial({
  map: colorMap, // 基础色
  normalMap: normalMap, // 法线(凹凸)
  roughnessMap: roughnessMap, // 粗糙度
  roughness: 1.0, // 全局粗糙度(与纹理叠加)
  metalness: 0.1 // 金属度
});

五、完整实战示例(纹理加载+UV自定义+阵列+动画)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>Three.js 纹理贴图完整示例</title>
  <style>body { margin: 0; overflow: hidden; }</style>
</head>
<body>
  <script>
    import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r132/build/three.module.js';
    import { OrbitControls }  from "https://threejsfundamentals.org/threejs/resources/threejs/r132/examples/jsm/controls/OrbitControls.js";

    // 1. 创建三大核心
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    camera.position.set(3, 3, 5);

    // 2. 加载纹理(示例使用CDN纹理,避免本地路径问题)
    const texLoader = new THREE.TextureLoader();
    // 瓷砖纹理(CDN示例)
    const texture = texLoader.load('https://threejs.org/examples/textures/tiles/tiles_diff.jpg', () => {
      renderer.render(scene, camera); // 加载完成后渲染
    });
    // 关键:设置颜色空间,避免偏色
    texture.colorSpace = THREE.SRGBColorSpace;

    // 3. 纹理配置(阵列+过滤优化)
    texture.wrapS = THREE.RepeatWrapping;
    texture.wrapT = THREE.RepeatWrapping;
    texture.repeat.set(8, 8); // 8x8瓷砖阵列
    // 提升纹理质量
    texture.magFilter = THREE.LinearFilter;
    texture.minFilter = THREE.LinearMipmapLinearFilter;
    texture.generateMipmaps = true;
    // 开启各向异性过滤
    texture.anisotropy = renderer.capabilities.getMaxAnisotropy();

    // 4. 创建地面几何体(PlaneGeometry)
    const groundGeo = new THREE.PlaneGeometry(10, 10);
    const groundMat = new THREE.MeshStandardMaterial({
      map: texture,
      side: THREE.DoubleSide
    });
    const groundMesh = new THREE.Mesh(groundGeo, groundMat);
    groundMesh.rotation.x = -Math.PI / 2; // 旋转为地面
    scene.add(groundMesh);

    // 5. 创建立方体(自定义UV示例)
    const cubeGeo = new THREE.BoxGeometry(2, 2, 2);
    // 自定义立方体UV(仅修改正面,其他面默认)
    const uvs = new Float32Array([
      0, 0, 1, 0, 1, 1, 0, 1, // 正面UV(完整映射)
      0, 0, 0.5, 0, 0.5, 0.5, 0, 0.5, // 右侧面UV(1/4映射)
      // 其他面UV省略,使用默认值
    ]);
    cubeGeo.setAttribute('uv', new THREE.BufferAttribute(uvs, 2));
    const cubeMat = new THREE.MeshStandardMaterial({ map: texture });
    const cubeMesh = new THREE.Mesh(cubeGeo, cubeMat);
    cubeMesh.position.y = 1; // 立方体放在地面上
    scene.add(cubeMesh);

    // 6. 添加光源(PBR材质需要光源)
    const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
    const dirLight = new THREE.DirectionalLight(0xffffff, 1);
    dirLight.position.set(5, 8, 5);
    scene.add(ambientLight, dirLight);

    // 7. 轨道控制器
    const controls = new OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.dampingFactor = 0.05;

    // 8. UV动画循环
    function animate() {
      requestAnimationFrame(animate);
      // 纹理缓慢滚动(U轴+V轴)
      texture.offset.x += 0.002;
      texture.offset.y += 0.001;
      // 立方体旋转
      cubeMesh.rotation.x += 0.01;
      cubeMesh.rotation.y += 0.01;
      
      controls.update();
      renderer.render(scene, camera);
    }
    animate();

    // 9. 窗口适配
    window.addEventListener('resize', () => {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(window.innerWidth, window.innerHeight);
    });
  </script>
</body>
</html>

示例效果

e628d623-98ee-42f3-85e8-aa2eb050cd5d.png

  1. 场景包含10x10的瓷砖地面,纹理8x8阵列显示,且缓慢滚动;
  2. 地面上有一个立方体,正面完整映射纹理,右侧面仅显示纹理1/4区域;
  3. 支持鼠标旋转/缩放视角,立方体自动旋转,纹理滚动动画流畅;
  4. 纹理显示清晰,无偏色、无模糊问题。

六、纹理优化与避坑指南

1. 性能优化技巧

  • 图片尺寸优化:纹理图片尺寸建议为2的幂次方(如256x256、512x512、1024x1024),GPU处理更快;
  • 复用纹理对象:多个模型使用同一张纹理时,复用同一个Texture对象,避免重复加载;
  • 关闭不必要的功能:静态纹理关闭generateMipmaps,减少内存占用;
  • 压缩纹理:使用basis Universal等压缩纹理格式,减小图片体积,提升加载速度。

2. 常见坑点与解决

问题 原因 解决方法
纹理偏色 未设置colorSpace 添加texture.colorSpace = THREE.SRGBColorSpace
纹理不显示 跨域问题/图片路径错误 启动HTTP服务/检查路径/配置CORS
纹理模糊 过滤方式未优化 设置magFilter=LinearFilter+minFilter=LinearMipmapLinearFilter
阵列不生效 未设置wrapS/wrapT 开启texture.wrapS/wrapT = THREE.RepeatWrapping
UV动画卡顿 偏移量递增过快 减小offset递增步长(如0.001~0.01)

核心总结

  1. 核心流程TextureLoader加载图片 → 设置colorSpace → 配置纹理属性(wrap/repeat/offset) → 绑定到材质.map → 几何体UV映射
  2. UV坐标:0~1范围,是纹理与几何体的桥梁,自定义几何体需手动设置UV属性;
  3. 关键属性
    • wrapS/wrapT:控制重复模式,实现瓷砖阵列;
    • repeat:设置重复数量;
    • offset:实现UV动画;
    • colorSpace:避免纹理偏色(r152+必加);
  4. 优化原则:图片尺寸为2的幂次方,开启各向异性过滤,复用纹理对象,关闭不必要的Mipmap。

学习Three.js--缓冲类型几何体(BufferGeometry)

2026年1月21日 09:50

学习Three.js--缓冲类型几何体(BufferGeometry)

前置核心说明

BufferGeometry 是 Three.js 中所有几何体的底层核心(BoxGeometry/SphereGeometry 等预设几何体均基于它构建),也是官方唯一推荐使用的几何体类型(旧版 Geometry 已被废弃)。

核心区别与优势(为什么用 BufferGeometry)

类型 核心特点 性能 官方态度
BufferGeometry(缓冲几何体) 顶点数据存储在「类型化数组」(Float32Array 等)中,直接对接 GPU 内存 极高(GPU 直接读取,无数据转换) 主推,唯一维护
Geometry(旧版几何体) 顶点数据存储在普通数组中,需转换后才能给 GPU 使用 较低(多一层数据转换) 废弃,不再维护

核心逻辑

BufferGeometry 本身是「空容器」,没有任何预设形状,你需要通过定义顶点数据(坐标、颜色、纹理坐标等)来「自定义任意几何形状」,核心是:
类型化数组(顶点数据)→ BufferAttribute(属性封装)→ BufferGeometry(绑定属性)→ 渲染对象(Mesh/Line/Points)


一、BufferGeometry 核心概念与基础用法

1. 核心术语解释

  • 顶点(Vertex):3D 空间中的一个点,由 X/Y/Z 三个坐标值组成,是构成几何体的最基本单元;
  • 类型化数组:如 Float32Array(32位浮点数组),专门用于存储顶点数据,比普通数组更节省内存、GPU 读取更快;
  • BufferAttribute:Three.js 对「类型化数组」的封装,告诉 Three.js 「数组中的数据如何分组解析」(比如每3个值为一组表示一个顶点坐标);
  • 属性(Attribute):几何体的「数据维度」,如 position(顶点坐标)、color(顶点颜色)、uv(纹理坐标)、normal(法线)等,一个几何体可绑定多个属性。

2. 基础使用流程

以下是从「创建空几何体」到「渲染自定义形状」的完整流程

步骤1:创建空的 BufferGeometry 容器
// 语法:无参数,创建空的缓冲几何体
const geometry = new THREE.BufferGeometry();
步骤2:定义顶点数据(类型化数组)

顶点数据必须用 类型化数组(不能用普通数组),常用:

  • Float32Array:存储浮点型数据(坐标、颜色、UV 等,最常用);
  • Uint16Array:存储无符号16位整数(索引数据)。
// 顶点坐标数据:每3个值为一组(X,Y,Z),表示一个顶点的3D坐标
// 示例:6个顶点,对应2个三角形(Mesh 默认按三角面渲染)
const vertices = new Float32Array([
  0, 0, 0,   // 顶点1:(0,0,0)
  50, 0, 0,  // 顶点2:(50,0,0)
  0, 100, 0, // 顶点3:(0,100,0) → 第一个三角形(顶点1-2-3)
  0, 0, 10,  // 顶点4:(0,0,10)
  0, 0, 100, // 顶点5:(0,0,100)
  50, 0, 10  // 顶点6:(50,0,10) → 第二个三角形(顶点4-5-6)
]);
步骤3:创建 BufferAttribute
// 语法:new THREE.BufferAttribute(类型化数组, 组内元素数量, 是否归一化)
// 关键:itemSize=3 → 每3个值为一组(对应X/Y/Z坐标)
const positionAttribute = new THREE.BufferAttribute(vertices, 3);
BufferAttribute 参数 类型 默认值 核心说明
array TypedArray 必传,存储顶点数据的类型化数组
itemSize Number 必传,每组的元素数量(坐标=3,颜色=3/4,UV=2)
normalized Boolean false 是否归一化数据(颜色数据常用,将0-255转为0-1)
usage Number THREE.StaticDrawUsage 数据使用方式(静态/动态,默认静态即可)
步骤4:将属性绑定到几何体
// 语法:geometry.setAttribute(属性名, BufferAttribute对象)
// 核心:属性名必须是固定值,如 "position"(坐标)、"color"(颜色)、"uv"(纹理)
geometry.setAttribute('position', positionAttribute);
步骤5:创建材质和渲染对象
// 材质:MeshBasicMaterial 不受光照影响,适合调试
const material = new THREE.MeshBasicMaterial({
  color: 0x00ff00,    // 基础颜色(无顶点颜色时生效)
  wireframe: false,   // 是否显示线框(true=线框,false=实体)
  side: THREE.DoubleSide // 双面渲染(避免背面不可见)
});

// 创建网格对象(将几何体+材质绑定)
const mesh = new THREE.Mesh(geometry, material);

// 添加到场景
scene.add(mesh);

二、BufferGeometry 核心参数与常用属性

1. 构造函数(无参数)

// 始终无参数,创建空几何体,后续通过 setAttribute 绑定数据
const geometry = new THREE.BufferGeometry();

2. 核心属性

属性名 类型 说明 示例
attributes Object 存储所有绑定的属性(position/color/uv 等) geometry.attributes.position → 获取坐标属性
index BufferAttribute 索引缓冲区(优化顶点重复,下文详解) geometry.setIndex(索引数组)
boundingBox Box3 几何体的包围盒(自动计算,用于碰撞检测/裁剪) geometry.computeBoundingBox() → 计算包围盒
boundingSphere Sphere 几何体的包围球 geometry.computeBoundingSphere()
drawRange Object 渲染范围(只渲染部分顶点) geometry.drawRange = { start: 0, count: 3 } → 只渲染前3个顶点

3. 核心方法

方法名 说明 示例
setAttribute(name, attribute) 绑定属性到几何体 geometry.setAttribute('position', attr)
getAttribute(name) 获取已绑定的属性 geometry.getAttribute('position')
removeAttribute(name) 移除属性 geometry.removeAttribute('color')
setIndex(array) 设置索引缓冲区 geometry.setIndex(new Uint16Array([0,1,2]))
computeBoundingBox() 计算几何体包围盒 geometry.computeBoundingBox()
computeBoundingSphere() 计算几何体包围球 geometry.computeBoundingSphere()
computeVertexNormals() 计算顶点法线(让光照生效) geometry.computeVertexNormals()
dispose() 销毁几何体(释放内存) geometry.dispose()

三、BufferGeometry 进阶用法

1. 索引缓冲区(Index):减少顶点重复

问题场景

绘制一个矩形(由两个三角面组成),直接定义顶点需要6个(重复2个):
(0,0,0)、(1,0,0)、(0,1,0)、(1,0,0)、(1,1,0)、(0,1,0)

索引解决方案
  • 定义4个唯一顶点 + 6个索引(指定三角面的顶点顺序),节省内存:
// 步骤1:创建空几何体
const geometry = new THREE.BufferGeometry();

// 步骤2:定义4个唯一顶点(无重复)
const vertices = new Float32Array([
  0, 0, 0,  // 顶点0
  1, 0, 0,  // 顶点1
  0, 1, 0,  // 顶点2
  1, 1, 0   // 顶点3
]);
const posAttr = new THREE.BufferAttribute(vertices, 3);
geometry.setAttribute('position', posAttr);

// 步骤3:定义索引(每3个值为一组,指定三角面的顶点索引)
// 第一个三角面:顶点0→1→2;第二个三角面:顶点1→3→2
const indices = new Uint16Array([
  0, 1, 2, 
  1, 3, 2
]);
// 设置索引缓冲区
geometry.setIndex(new THREE.BufferAttribute(indices, 1));

// 步骤4:创建材质和网格
const material = new THREE.MeshBasicMaterial({ color: 0xff0000, side: THREE.DoubleSide });
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
核心优势
  • 顶点数量从6个减少到4个,数据量降低33%;
  • 复杂几何体(如球体)可减少大量重复顶点,性能提升显著。

2. 顶点颜色(Color Attribute):每个顶点自定义颜色

核心逻辑

给几何体绑定 color 属性,材质开启 vertexColors: true,即可让每个顶点显示自定义颜色,三角面内自动渐变。

// 步骤1:创建空几何体 + 顶点坐标
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
  0, 0, 0,   // 顶点0
  1, 0, 0,   // 顶点1
  0, 1, 0    // 顶点2
]);
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));

// 步骤2:定义顶点颜色(每3个值为一组,RGB,0-1范围)
const colors = new Float32Array([
  1, 0, 0,   // 顶点0:红色
  0, 1, 0,   // 顶点1:绿色
  0, 0, 1    // 顶点2:蓝色
]);
geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));

// 步骤3:材质开启顶点颜色(关键)
const material = new THREE.MeshBasicMaterial({
  vertexColors: true, // 启用顶点颜色(覆盖基础color)
  side: THREE.DoubleSide
});

// 步骤4:创建网格
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
效果

三角面会从红色顶点渐变到绿色,再渐变到蓝色,实现多彩渐变效果。

3. 法线属性(Normal):让光照生效

MeshStandardMaterial 等受光照影响的材质,需要「法线数据」才能计算光影,可手动定义或自动计算:

// 方式1:自动计算法线(推荐,适合简单几何体)
geometry.computeVertexNormals();

// 方式2:手动定义法线(精准控制,复杂几何体)
const normals = new Float32Array([
  0, 0, 1,  // 顶点0:法线朝向Z轴正方向
  0, 0, 1,  // 顶点1:法线朝向Z轴正方向
  0, 0, 1   // 顶点2:法线朝向Z轴正方向
]);
geometry.setAttribute('normal', new THREE.BufferAttribute(normals, 3));

4. UV 纹理坐标:绑定纹理贴图

UV 坐标(0-1范围)用于将2D图片贴到3D几何体上,每2个值为一组(U=横向,V=纵向):

// 定义UV坐标(每2个值为一组)
const uvs = new Float32Array([
  0, 0,  // 顶点0:贴图左下角
  1, 0,  // 顶点1:贴图右下角
  0, 1   // 顶点2:贴图左上角
]);
geometry.setAttribute('uv', new THREE.BufferAttribute(uvs, 2));

// 加载纹理并绑定到材质
const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('texture.jpg');
const material = new THREE.MeshBasicMaterial({ map: texture });

四、完整实战示例(自定义三角面+索引+顶点颜色)

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>BufferGeometry 完整示例</title>
  <style>body { margin: 0; overflow: hidden; }</style>
</head>
<body>
  <script type="module">
    import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r132/build/three.module.js'
    import { OrbitControls }  from "https://threejsfundamentals.org/threejs/resources/threejs/r132/examples/jsm/controls/OrbitControls.js"
    // 1. 创建三大核心
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);
    camera.position.z = 2;

    // 2. 自定义 BufferGeometry(带索引+顶点颜色)
    const geometry = new THREE.BufferGeometry();

    // 2.1 顶点坐标(4个唯一顶点,绘制矩形)
    const vertices = new Float32Array([
      -0.5, -0.5, 0,  // 顶点0
       0.5, -0.5, 0,  // 顶点1
      -0.5,  0.5, 0,  // 顶点2
       0.5,  0.5, 0   // 顶点3
    ]);
    geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));

    // 2.2 顶点颜色(4个顶点对应4组颜色)
    const colors = new Float32Array([
      1, 0, 0,  // 顶点0:红
      0, 1, 0,  // 顶点1:绿
      0, 0, 1,  // 顶点2:蓝
      1, 1, 0   // 顶点3:黄
    ]);
    geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));

    // 2.3 索引缓冲区(指定三角面的顶点顺序)
    const indices = new Uint16Array([
      0, 1, 2,  // 第一个三角面:0→1→2
      1, 3, 2   // 第二个三角面:1→3→2
    ]);
    geometry.setIndex(new THREE.BufferAttribute(indices, 1));

    // 2.4 计算法线(可选,若用受光照材质则需要)
    geometry.computeVertexNormals();

    // 3. 创建材质(启用顶点颜色)
    const material = new THREE.MeshBasicMaterial({
      vertexColors: true, // 启用顶点颜色
      side: THREE.DoubleSide,
      wireframe: false
    });

    // 4. 创建网格并添加到场景
    const mesh = new THREE.Mesh(geometry, material);
    scene.add(mesh);

    // 5. 轨道控制器(交互)
    const controls = new THREE.OrbitControls(camera, renderer.domElement);
    controls.enableDamping = true;
    controls.dampingFactor = 0.05;

    // 6. 动画循环
    function animate() {
      requestAnimationFrame(animate);
      mesh.rotation.x += 0.01;
      mesh.rotation.y += 0.01;
      controls.update();
      renderer.render(scene, camera);
    }
    animate();

    // 7. 窗口适配
    window.addEventListener('resize', () => {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(window.innerWidth, window.innerHeight);
    });
  </script>
</body>
</html>

示例效果

56382a99-8b86-4af3-9b51-172939c77ff5.png

  • 场景中显示一个彩色矩形(由两个三角面组成);
  • 矩形顶点分别为红、绿、蓝、黄,面内自动渐变;
  • 支持鼠标旋转/缩放视角,矩形缓慢旋转。

五、注意事项与性能优化

1. 关键注意点

  • 类型化数组必须正确:顶点坐标用 Float32Array,索引用 Uint16Array/Uint32Array,不能混用;
  • itemSize 必须匹配:坐标=3,颜色=3/4,UV=2,索引=1,错误会导致几何体显示异常;
  • 双面渲染:自定义几何体默认只渲染正面,需设置 side: THREE.DoubleSide 避免背面不可见;
  • 内存释放:不再使用的几何体,必须调用 geometry.dispose() 释放内存,避免内存泄漏。

2. 性能优化技巧

  • 使用索引缓冲区:减少重复顶点,降低数据量;
  • 控制顶点数量:复杂几何体按需分段,避免顶点过多;
  • 静态数据复用:相同形状的几何体复用,无需重复创建;
  • drawRange 局部渲染:只渲染需要显示的顶点范围,减少计算。

核心总结

  1. 核心地位:BufferGeometry 是 Three.js 所有几何体的底层核心,官方唯一推荐使用;
  2. 核心流程:类型化数组→BufferAttribute→setAttribute→绑定到渲染对象;
  3. 核心优化:索引缓冲区可减少顶点重复,是高性能自定义几何体的关键;
  4. 核心属性position(坐标)、color(颜色)、uv(纹理)、normal(法线)是最常用的属性;
  5. 性能原则:用类型化数组、复用几何体、释放无用数据,最大化 GPU 渲染效率。
昨天以前首页

学习Three.js--材质(Material)

2026年1月19日 16:45

学习Three.js--材质(Material)

前置必读:材质通用规则 & 公共核心参数

一、通用规则

  1. 所有网格类材质MeshXXXMaterial)都是 THREE.Material 的子类,共用一套核心公共参数,无需重复记忆;
  2. 材质的参数均为配置对象({})传参,支持创建后通过 material.参数名 = 值 动态修改;
  3. 材质创建后可以复用给多个物体,能极大节省内存(比如100个立方体用同一个材质,只创建1个即可);
  4. 所有颜色值参数:支持16进制0xffffff、RGB字符串#fff/rgb(255,255,255)THREE.Color对象。

二、 所有材质【公共核心参数】

以下参数适用于 90% 的材质(MeshBasic/MeshLambert/MeshPhong/Standard/Physical 全部包含),一次记忆,全部受用!

{
  color: 0xffffff, // 基础颜色,默认白色
  transparent: false, // 是否开启透明效果,默认关闭 ❗开启透明必须设为true,opacity才生效
  opacity: 1, // 透明度,取值范围 0(完全透明) ~ 1(完全不透明),默认1
  visible: true, // 物体是否可见,true显示/false隐藏,默认true
  side: THREE.FrontSide, // 渲染物体的哪个面,核心取值3种:
  // THREE.FrontSide 只渲染正面(默认) | THREE.BackSide 只渲染背面 | THREE.DoubleSide 双面渲染
  depthWrite: true, // 是否写入深度缓冲区,默认true;透明物体建议设为false,避免透明重叠闪烁
  depthTest: true, // 是否开启深度测试,默认true;关闭后物体可能会穿透其他物体
  wireframe: false, // 是否以线框模式渲染物体,默认false(实体),true则只显示几何体的边框线
  wireframeLinewidth: 1, // 线框的线宽,默认1;❗注意:浏览器对WebGL的线宽支持有限,一般只能到1-2px
  alphaTest: 0, // 透明度裁剪阈值,取值0~1;像素透明度低于该值则不渲染,解决透明边缘锯齿问题
  map: null, // 颜色纹理贴图,传 THREE.Texture 纹理对象,用于给物体贴图片(比如木纹、皮肤)
}

一、网格基础材质 THREE.MeshBasicMaterial

核心特点

不受光照影响、无明暗变化,始终纯色/纹理显示,不需要添加光源就能渲染,性能最高

适用场景

调试几何体、UI元素、纯色简单物体、快速原型开发

完整调用语法

const material = new THREE.MeshBasicMaterial({
  // 公共参数 + 自身专属参数(无专属,全是公共参数)
  color: 0x00ff00,
  transparent: false,
  opacity: 1,
  side: THREE.FrontSide,
  wireframe: false,
  map: null,
  alphaTest: 0,
  depthWrite: true
});

专属注意点

  • 该材质无视所有光源,添加AmbientLight/DirectionalLight等都不会有任何效果;
  • wireframe: true 时,能直观看到几何体的顶点和面结构,调试几何体形状的最佳材质

二、网格漫反射材质 THREE.MeshLambertMaterial

核心特点

基于Lambert漫反射光照模型,对光源有响应、有明暗过渡,无高光效果,计算量低

适用场景

哑光粗糙表面(纸张、墙面、布料、水泥、木头、哑光塑料)

完整调用语法

const material = new THREE.MeshLambertMaterial({
  // 公共参数(全部支持)
  color: 0x00ff00,
  transparent: false,
  opacity: 1,
  side: THREE.FrontSide,
  wireframe: false,
  map: null,
  //  自身核心专属参数
  emissive: 0x000000, // 自发光颜色,默认黑色(无自发光)
  emissiveIntensity: 1, // 自发光强度,取值0~∞,默认1
  emissiveMap: null, // 自发光纹理贴图,给物体贴发光纹理
  vertexColors: false, // 是否使用顶点颜色,默认false
  flatShading: false, // 是否使用平面着色,默认false(平滑着色)
});

所有参数详细释义(含公共+专属)

  1. 公共参数同上文,不再重复;
  2. emissive:自发光色,不会照亮其他物体,只是让材质自身显示该颜色,比如设为0xff0000,物体会带红色发光效果;
  3. emissiveIntensity:调节自发光的亮度,值越大发光越明显;
  4. flatShading: true:几何体每个面会显示纯色,无平滑过渡,适合做低多边形风格;
  5. vertexColors: true:如果几何体设置了顶点颜色,材质会渲染顶点的颜色渐变。

注意点

  • 必须添加光源,否则物体会显示纯黑色,完全不可见;
  • 无高光参数,无法实现光泽效果,是哑光质感的最优选择。

三、网格高光材质 THREE.MeshPhongMaterial

核心特点

基于Phong高光光照模型,支持「漫反射+镜面高光」,对光源响应,有明显的高光光斑,计算量略高于MeshLambertMaterial

适用场景

有光泽的物体(漆面塑料、陶瓷、湿润的石头、抛光木头、电镀金属)

完整调用语法

const material = new THREE.MeshPhongMaterial({
  // 公共参数(全部支持)
  color: 0x00ff00,
  transparent: false,
  opacity: 1,
  side: THREE.FrontSide,
  wireframe: false,
  map: null,
  //  继承MeshLambert的自发光参数
  emissive: 0x000000,
  emissiveIntensity: 1,
  emissiveMap: null,
  flatShading: false,
  //  自身核心高光专属参数(重中之重)
  specular: 0x111111, // 高光颜色,默认浅灰色
  shininess: 30, // 高光的「亮度+范围」,取值0~1000+,默认30
});

高光核心参数释义

  1. specular:决定高光光斑的颜色,比如:
    • 塑料材质:设为0xffffff(白色高光),最真实;
    • 金属材质:设为和color相同的颜色,高光和本体同色;
  2. shininess:核心高光参数,值越小 → 高光范围越大、亮度越低值越大 → 高光范围越小、亮度越高
    • 示例:shininess:5 → 大面积柔和高光;shininess:100 → 小面积刺眼高光。

注意点

  1. 同样必须添加光源,无光源则全黑;
  2. Phong的高光效果是模拟的光泽,不是物理真实的,高光光斑略显生硬,但性能不错,适合简单光泽场景;
  3. 该材质的高光计算在顶点上,低面数几何体的高光会有锯齿。

四、物理基础材质 THREE.MeshStandardMaterial 【默认首选】

核心特点

基于 PBR(Physically Based Rendering)物理渲染,完全遵循真实世界的光照规律,参数少但效果极致真实,计算量适中,Three.js官方推荐的默认首选材质,也是目前最常用的材质!

适用场景

99%的现代3D场景:游戏、产品展示、建筑可视化、电商3D商品、写实模型,能替代所有传统材质(Lambert/Phong)

核心优势

  • 传统材质(Phong/Lambert)是「模拟光照」,PBR是「物理光照」,效果真实度天差地别;
  • 参数语义化,无需调复杂的高光/漫反射,通过「粗糙度+金属度」就能实现所有质感。

完整调用语法

const material = new THREE.MeshStandardMaterial({
  // 公共参数(全部支持)
  color: 0x00ff00,
  transparent: false,
  opacity: 1,
  side: THREE.FrontSide,
  wireframe: false,
  map: null,
  alphaTest: 0,
  depthWrite: true,
  //  PBR 核心四大基础参数 (必学!!)
  roughness: 0.5,    // 粗糙度,取值 0(镜面光滑) ~ 1(完全粗糙),默认0.5
  metalness: 0.5,    // 金属度,取值 0(非金属) ~ 1(纯金属),默认0.5
  emissive: 0x000000,// 自发光颜色,默认黑色,无自发光
  emissiveIntensity:1,// 自发光强度,默认1
  //  PBR 进阶纹理贴图(提升真实度)
  roughnessMap: null, // 粗糙度纹理,让物体表面粗糙度有细节变化
  metalnessMap: null, // 金属度纹理,让物体部分区域是金属、部分是非金属
  normalMap: null,    // 法线贴图,模拟物体表面凹凸细节(无需修改几何体)
  aoMap: null,        // 环境遮蔽贴图,模拟物体缝隙/凹陷处的阴影,提升层次感
  displacementMap: null, // 置换贴图,真正修改几何体顶点,实现凹凸效果
  //  特殊物理参数
  clearcoat: 0,       // 清漆层,取值0~1,默认0;模拟车漆/指甲油的表层光泽
  clearcoatRoughness:0,// 清漆层粗糙度,取值0~1,默认0
  transmission: 0,    // 透射率,取值0~1,默认0;模拟玻璃/半透明物体的透光效果
});

PBR 核心参数【必懂必记】(4个)

这是该材质的灵魂,记住取值范围+含义,就能调出所有质感,无任何例外!

  1. roughness (粗糙度) 0~1
    • 0 → 镜面级光滑,反射所有光线,高光极强(比如镜子、抛光金属);
    • 1 → 完全粗糙,无任何高光,纯哑光(比如纸张、水泥);
    • 中间值 → 半光泽(比如塑料、漆面、木头)。
  2. metalness (金属度) 0~1
    • 0 → 非金属材质(塑料、玻璃、石头、布料),反射环境光,高光颜色固定;
    • 1 → 纯金属材质(金、银、铜),反射自身颜色,高光和本体同色;
    • 中间值 → 合金材质(比如不锈钢、黄铜)。
  3. emissive + emissiveIntensity:自发光,不会照亮其他物体,比如霓虹灯、指示灯、发光logo。
  4. 颜色color:金属度0时是「物体本身颜色」;金属度1时,color决定金属的颜色(比如金色0xffd700、银色0xcccccc)。

质感调试万能公式

  • 哑光塑料 → roughness:0.8, metalness:0
  • 镜面塑料 → roughness:0.1, metalness:0
  • 不锈钢 → roughness:0.2, metalness:1, color:0xcccccc
  • 黄金 → roughness:0.1, metalness:1, color:0xffd700
  • 木头 → roughness:0.7, metalness:0, color:0x8b4513
  • 玻璃 → roughness:0, metalness:0, transmission:0.9

五、高级物理材质 THREE.MeshPhysicalMaterial

核心特点

MeshStandardMaterial 的超集,完全兼容其所有参数+方法,在其基础上增加了更精细的物理光学参数,实现极致写实的物理效果,PBR天花板材质!

适用场景

超写实3D场景:汽车车漆、玻璃/水晶、宝石、珍珠、丝绸、拉丝金属、多层镀膜材质

完整调用语法

const material = new THREE.MeshPhysicalMaterial({
  //  完全包含 MeshStandardMaterial 的 所有参数(无需重复写)
  color: 0x00ff00,
  roughness: 0.5,
  metalness: 0.5,
  emissive: 0x000000,
  clearcoat:0,
  transmission:0,
  //  新增的【专属高级参数】(核心!)
  clearcoatRoughness: 0,    // 清漆层粗糙度,0=镜面清漆,1=哑光清漆
  sheen: 0,                 // 光泽层,0~1,默认0;模拟丝绸、天鹅绒、布料的柔和高光
  sheenRoughness: 0.5,      // 光泽层粗糙度,0~1,默认0.5
  sheenColor: 0xffffff,     // 光泽层颜色,默认白色
  iridescence: 0,           // 虹彩/色散,0~1,默认0;模拟珍珠、肥皂泡、CD光盘的彩虹反光
  iridescenceIOR: 1.5,      // 虹彩折射率,默认1.5
  iridescenceThicknessRange: [100, 400], // 虹彩厚度范围,控制彩虹颜色
  anisotropy: 0,            // 各向异性,-1~1,默认0;模拟拉丝金属、头发的方向性高光
  thickness: 0.1,           // 厚度,0~∞,默认0.1;配合transmission使用,模拟玻璃的厚度(厚玻璃颜色更深)
  reflectivity: 1,          // 折射率,1~2.333,默认1;控制玻璃/水的折射效果
});

专属参数核心释义

  1. sheen:丝绸/天鹅绒的核心参数,能实现「反向高光」,布料的质感全靠它;
  2. iridescence:彩虹色散,珍珠、肥皂泡、车漆的金属珠光效果,必调参数;
  3. anisotropy:拉丝金属的核心,比如不锈钢拉丝面板、头发,高光会沿着拉丝方向延伸;
  4. thickness:玻璃厚度,比如厚玻璃杯的边缘会偏绿,薄玻璃则透明,真实度拉满。

注意点

  • 该材质计算量比MeshStandardMaterial略高,但现代浏览器/显卡完全能承载;
  • 能用MeshStandardMaterial实现的效果,就用它;需要极致细节时,再用MeshPhysicalMaterial

六、点材质 THREE.PointsMaterial

核心特点

专门用于 THREE.Points(粒子系统),只能渲染点/粒子,不能渲染网格几何体

适用场景

粒子特效:星空、烟雾、雨滴、雪花、灰尘、点云模型、星空背景

完整调用语法

const material = new THREE.PointsMaterial({
  color: 0xffffff,          // 粒子颜色,默认白色
  size: 1,                  // 粒子大小(像素),默认1
  sizeAttenuation: true,    // 是否开启「近大远小」,默认true;false则所有粒子大小一致
  transparent: true,        // 是否透明,默认false(粒子特效必开)
  opacity: 1,               // 透明度,0~1,默认1
  map: null,                // 粒子纹理贴图,比如用圆形贴图做圆点粒子,用雪花贴图做雪花
  alphaTest: 0.1,           // 透明裁剪,解决粒子边缘锯齿,建议设0.1
  depthWrite: false,        // 关闭深度写入,解决透明粒子重叠时的闪烁问题(必开)
  blending: THREE.AdditiveBlending, // 混合模式,AdditiveBlending=叠加,粒子更亮(适合火焰/星光)
  emissive: 0xffffff,       // 自发光颜色,默认白色
  emissiveIntensity:1,      // 自发光强度
});
// 配套使用:创建粒子系统
const geometry = new THREE.BufferGeometry().setFromPoints( pointsArr ); // 点数组
const points = new THREE.Points( geometry, material );
scene.add(points);

核心参数

  1. size:粒子的像素大小,值越大粒子越大;
  2. sizeAttenuation: true:粒子会像真实物体一样,离相机越近越大,越远越小,必开;
  3. depthWrite: false:透明粒子的必备参数,否则粒子重叠时会出现穿透/闪烁的问题。

七、线材质 「LineBasicMaterial + LineDashedMaterial」

通用特点

专门用于 THREE.Line / THREE.LineSegments(线段/线条几何体),只能渲染线条,不能渲染网格

适用场景

绘制辅助线、坐标轴、边框、电路图、激光线、轨迹线等

7.1 实线材质 THREE.LineBasicMaterial

const material = new THREE.LineBasicMaterial({
  color: 0xffffff,    // 线条颜色,默认白色
  linewidth: 1,       // 线宽(像素),默认1;❗浏览器限制,一般最大只能到2px
  transparent: false, // 是否透明
  opacity: 1,         // 透明度
  dashed: false,      // 是否虚线,默认false(实线)
});

7.2 虚线材质 THREE.LineDashedMaterial【高频使用】

const material = new THREE.LineDashedMaterial({
  color: 0xffffff,    // 线条颜色
  linewidth: 1,       // 线宽
  transparent: false,
  opacity: 1,
  dashSize: 3,        // 【核心】虚线的「实线部分长度」,默认3
  gapSize: 1,         // 【核心】虚线的「空白部分长度」,默认1
  scale: 1,           // 缩放比例,默认1;整体缩放dashSize和gapSize
});
// ❗ 必加:给线段几何体调用 computeLineDistances(),否则虚线不生效!
const lineGeometry = new THREE.BufferGeometry().setFromPoints( pointsArr );
lineGeometry.computeLineDistances(); 
const line = new THREE.Line( lineGeometry, material );
scene.add(line);

注意点

  1. 虚线材质必须调用 geometry.computeLineDistances(),否则会显示为实线,无虚线效果;
  2. linewidth 受WebGL限制,无法设置超大线宽,如需粗线条,建议用网格几何体模拟。

八、精灵材质 THREE.SpriteMaterial

核心特点

专门用于 THREE.Sprite(精灵/广告牌),本质是始终朝向相机的2D平面,不会随视角旋转,永远正面朝向屏幕

适用场景

3D场景中的2D元素:图标、血条、标签、子弹、火焰粒子、雪花粒子、2D精灵特效

完整调用语法

const material = new THREE.SpriteMaterial({
  color: 0xffffff,    // 精灵颜色
  map: null,          // 精灵纹理贴图(核心,一般都用贴图,比如图标图片)
  transparent: true,  // 是否透明,默认false(必开,否则背景是白色)
  opacity: 1,         // 透明度
  rotation: 0,        // 精灵旋转角度(弧度制),默认0;绕中心旋转
  center: new THREE.Vector2(0.5,0.5), // 旋转中心,默认中心(0.5,0.5)
  sizeAttenuation: true, // 是否近大远小,默认true;false则精灵大小固定
  depthWrite: false,  // 关闭深度写入,解决精灵遮挡问题
});
// 配套使用
const sprite = new THREE.Sprite( material );
sprite.scale.set(1,1,1); // 设置精灵大小
scene.add(sprite);

注意点

  • 精灵是2D平面,没有厚度,所以side参数无效;
  • 精灵的大小通过 sprite.scale 控制,不是材质参数。

九、阴影材质 THREE.ShadowMaterial

核心特点

官方正确特性:材质自身完全透明,不接收任何光照,只显示「其他物体投射过来的阴影」

适用场景

地面/平面作为阴影接收器,比如创建一个透明的地面,只显示3D物体的阴影,不显示地面本身,让物体看起来像悬浮在空中,是实现真实阴影的最优方案!

完整调用语法

const material = new THREE.ShadowMaterial({
  opacity: 0.5, // 【唯一核心参数】阴影的透明度,取值0~1,默认0.5
  // 无其他专属参数,公共参数仅支持 transparent/depthWrite
  transparent: true, // 固定为true,无需修改
  depthWrite: false, // 建议关闭,避免阴影闪烁
});

使用注意点

  1. 必须开启光源的阴影投射 + 物体的阴影投射 + 地面的阴影接收
    directionalLight.castShadow = true; // 光源投射阴影
    cube.castShadow = true; // 物体投射阴影
    ground.receiveShadow = true; // 地面接收阴影
    
  2. opacity 越小,阴影越淡;越大,阴影越深。

十、自定义着色器材质 THREE.ShaderMaterial

核心特点

完全自定义顶点着色器(VertexShader)片元着色器(FragmentShader),使用GLSL语言编写,能实现 任何Three.js内置材质做不到的视觉效果,是Three.js的高级核心功能

适用场景

水体、火焰、溶解效果、扭曲变形、玻璃折射、扫描线、像素化、后处理特效等自定义视觉效果

完整调用语法

const material = new THREE.ShaderMaterial({
  //  核心:自定义GLSL着色器代码
  vertexShader: `
    uniform mat4 projectionMatrix;
    uniform mat4 modelViewMatrix;
    attribute vec3 position;
    void main() {
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `, // 顶点着色器:控制物体的顶点位置/变形
  fragmentShader: `
    uniform vec3 uColor;
    void main() {
      gl_FragColor = vec4(uColor, 1.0);
    }
  `, // 片元着色器:控制物体的像素颜色/纹理/特效
  //  自定义全局变量(JS传递数据到GLSL,核心!)
  uniforms: {
    uColor: { value: new THREE.Color(0x00ff00) }, // 颜色变量
    uTime: { value: 0 }, // 时间变量,用于做动画
    uTexture: { value: texture }, // 纹理变量
  },
  //  公共材质参数(全部支持)
  transparent: true,
  opacity: 1,
  side: THREE.DoubleSide,
  depthWrite: false,
  wireframe: false,
});

核心参数释义

  1. vertexShader:顶点着色器,运行在GPU上,控制每个顶点的位置、法线、纹理坐标等;
  2. fragmentShader:片元着色器,运行在GPU上,控制每个像素的最终颜色,所有视觉特效都在这里实现;
  3. uniforms:JS和GLSL之间的数据桥梁,可以在JS中动态修改uniforms.uTime.value,GLSL中就能实时获取,实现动画。

注意点

  • Three.js会自动注入内置变量(比如projectionMatrixmodelViewMatrix),无需手动声明;
  • GLSL语言和JS语法不同,需要单独学习基础,入门简单。

十一、原生着色器材质 THREE.RawShaderMaterial

核心特点

THREE.ShaderMaterial 几乎完全一致,唯一的区别是:不会自动注入Three.js的任何内置变量

适用场景

高级自定义着色器,需要完全掌控GLSL代码的所有变量,比如移植外部WebGL着色器、编写极致优化的着色器、实现底层图形学效果

调用语法

const material = new THREE.RawShaderMaterial({
  vertexShader: `
    // ❗ 必须手动声明所有变量,Three.js不自动注入
    uniform mat4 projectionMatrix;
    uniform mat4 modelViewMatrix;
    attribute vec3 position;
    void main() {
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    uniform vec3 uColor;
    void main() {
      gl_FragColor = vec4(uColor, 1.0);
    }
  `,
  uniforms: { uColor: { value: new THREE.Color(0x00ff00) } },
  transparent: true,
});

核心区别(和ShaderMaterial)

ShaderMaterial:自动注入内置变量,开发效率高,适合绝大多数自定义场景; RawShaderMaterial:无自动注入,完全手动,灵活性最高,适合高级底层开发。


材质学习总结 & 优先级建议(必看)

1. 材质使用优先级(按推荐度排序)

  1. 优先用 MeshStandardMaterial → 99%场景够用,物理真实、参数简单、性能均衡;
  2. 需要极致细节 → 用 MeshPhysicalMaterial
  3. 调试几何体 → 用 MeshBasicMaterial
  4. 简单哑光物体+低性能设备 → 用 MeshLambertMaterial
  5. 简单光泽物体 → 用 MeshPhongMaterial
  6. 粒子/点云 → 用 PointsMaterial
  7. 线条 → 用 LineBasicMaterial/LineDashedMaterial
  8. 2D精灵/图标 → 用 SpriteMaterial
  9. 透明地面+阴影 → 用 ShadowMaterial
  10. 自定义特效 → 用 ShaderMaterial/RawShaderMaterial

2. 核心记忆点

  • 所有网格材质共用一套公共参数,无需重复记忆;
  • PBR材质的核心是「粗糙度+金属度」,记住0~1的取值规则,就能调出所有质感;
  • 材质可以复用,多个物体用同一个材质能极大优化性能;
  • 透明材质建议开启 transparent:true + depthWrite:false,避免闪烁/穿透问题。
❌
❌