Community编程与开发github.com

UtkarshBirla28/threejs-materials

选择并配置 Three.js 材质 - 无光、漫反射、高光、PBR、卡通、点和线材质 - 以及混合、模板、环境响应等共享属性和 WebGPU 节点材质与 TSL 等效项。适用于设置网格样式或调整材质行为。

threejs-materials 是什么?

该技能提供了关于 Three.js 材质系统的全面指南,涵盖了从基础无光材质到高级 PBR 物理材质、卡通材质及点和线材质的各种类型。它详细解释了每种材质的使用场景、关键属性配置(如颜色、纹理、透明度、粗糙度、金属感等),并提供了可直接运行的代码示例。技能还特别处理了 UV 通道映射(aoMap 和 lightMap 支持单/多 UV 通道),以及玻璃(透射)和衣料(绒面)等高级物理效果。对于 WebGL 渲染器,它讲解了 ShaderMaterial 和 RawShaderMaterial 的自定义 GLSL 编写;对于 WebGPU,则介绍了节点材质和 TSL 的等效实现。此外,该技能包含一个重要的本地覆盖说明,专门针对使用 three.js r175 + Remotion 4.0.290 并依赖 pmndrs 后期处理库的动画短片流水线,提供了版本兼容性警告和特定 API 调整建议,避免在使用过时 API 或错误后期处理流程时出错。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/UtkarshBirla28/animated-shorts-pipeline/tree/HEAD/.claude/skills/threejs-materials

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Three.js 材质

目标版本: three.js r186。示例使用 WebGLRenderer;WebGPU 和 TSL 部分使用 WebGPURenderer。

本地覆盖(2026-11-10 由 Claude 为此 PC 添加;非原始技能的一部分)。我们的动画短片流水线 (<ROOT>\studio,源自 mromidev/claude-animated-shorts) 固定使用 three 0.175 (r175)

  • Remotion 4.0.290 + @react-three/fiber 9.1.2 + pmndrs postprocessing 6.37.2。保持 three 固定:shade.ts/cardshade.ts 对 three 着色器代码块进行字符串补丁。在处理该流水线时:
  • 忽略需要 r176+ 的“常见错误”/API 建议(HDRLoader、Timer、PCFSoftShadowMap 弃用、setEffects、 RenderPipeline、outputBufferType、mesh.pivot、Capsule height、TSL/WebGPU)。首先检查 API 是否存在于 r175 中。
  • 切勿使用 useFrame、Clock、Timer、delta time、setAnimationLoop 或 requestAnimationFrame 进行动画。Remotion 逐帧 渲染:每个值都从 useCurrentFrame() / fps 推导(对于剪辑,使用 mixer.setTime(frame / fps))。
  • 后期处理使用 pmndrs postprocessing,而不是 three/addons 的 EffectComposer:不要添加 OutputPass(会导致双重 sRGB 编码)。
  • 卡通颜色:我们的合成器中的色调映射是 NEUTRAL;注意 ACES 默认值和 tonemapping_fragment 的颜色偏差。
  • 对于其他 three.js 项目,以下原始 r186 指南按原样适用。

快速开始

import * as THREE from "three";

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const scene = new THREE.Scene();

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(0, 0, 3);

// PBR 材质 - 有光照、逼真表面的默认选择
const material = new THREE.MeshStandardMaterial({
  color: 0x00aaff,
  roughness: 0.35,
  metalness: 0.1,
});
const mesh = new THREE.Mesh(new THREE.SphereGeometry(1, 48, 32), material);
scene.add(mesh);
scene.add(new THREE.HemisphereLight(0xffffff, 0x444444, 1)); // 有光照的材质没有灯光渲染为黑色
const light = new THREE.DirectionalLight(0xffffff, 2);
light.position.set(3, 3, 3);
scene.add(light);

function animate() {
  mesh.rotation.y += 0.01;
  renderer.render(scene, camera);
}

renderer.setAnimationLoop(animate);

材质类型概览

材质使用场景光照
MeshBasicMaterial无光颜色、纹理、线框无
MeshLambertMaterial哑光漫射表面漫反射
MeshPhongMaterial光泽塑料、廉价高光漫反射 + 高光
MeshStandardMaterialPBR 金属/粗糙度工作流PBR
MeshPhysicalMaterialPBR 加上清漆、透射、绒面、彩虹色PBR
MeshToonMaterial卡通着色卡通阶梯
MeshMatcapMaterial将光照效果烘焙到 matcap 纹理中,无需灯光已烘焙
ShadowMaterial仅显示接收到的阴影的透明表面仅阴影
PointsMaterial点云无
LineBasicMaterial / LineDashedMaterial线条无
ShaderMaterial / RawShaderMaterial自定义 GLSL,仅限 WebGLRenderer自定义

颜色数据纹理(map、emissiveMap、specularMap、sheenColorMap、specularColorMap、LDR matcap、用作颜色的画布或视频)需要 texture.colorSpace = THREE.SRGBColorSpace,否则颜色会显得发白。标量贴图(normal、bump、displacement、roughness、metalness、ao、alpha、toon gradientMap)保留默认设置。HDR 加载器会自行设置色彩空间。

MeshBasicMaterial

无光照计算。速度快,始终可见。支持包含 reflectivity(0 到 1)和 combine(THREE.MultiplyOperation、THREE.MixOperation、THREE.AddOperation)的 envMap;specularMap(sRGB)遮盖环境贴图的贡献。

const map = await new THREE.TextureLoader().loadAsync("color.jpg");
map.colorSpace = THREE.SRGBColorSpace;

const material = new THREE.MeshBasicMaterial({
  color: 0xffffff, // 与贴图相乘
  map,
  transparent: true,
  opacity: 0.5,
  side: THREE.DoubleSide, // FrontSide(默认)、BackSide、DoubleSide
  fog: true, // 受场景雾效影响
});

MeshLambertMaterial 和 MeshPhongMaterial

Lambert 仅支持漫反射。Phong 添加了高光;当 Standard 过于繁重时,它是廉价的替代方案。

const lambert = new THREE.MeshLambertMaterial({
  color: 0x00ff00,
  emissive: 0x111111, // 自发光颜色
  emissiveIntensity: 1,
});

const phong = new THREE.MeshPhongMaterial({
  color: 0x0000ff,
  specular: 0x111111, // 高光颜色
  shininess: 30, // 越高 = 高光越锐利
  flatShading: false, // 平面与平滑法线
});

两者还支持 map、emissiveMap、specularMap(sRGB;遮盖环境贴图反射以及 Phong 的高光)、normalMap、bumpMap、displacementMap、aoMap、envMap、envMapIntensity 和 envMapRotation。

MeshStandardMaterial (PBR)

基于物理的渲染。推荐用于逼真效果。

const map = await new THREE.TextureLoader().loadAsync("color.jpg");
map.colorSpace = THREE.SRGBColorSpace;
const ormMap = await new THREE.TextureLoader().loadAsync("orm.jpg"); // glTF ORM:ao 红色通道,roughness 绿色通道,metalness 蓝色通道;标量:保留默认设置

const material = new THREE.MeshStandardMaterial({
  color: 0xffffff, // 与贴图相乘
  roughness: 1.0, // 0 = 镜面,1 = 完全漫反射;与 roughnessMap(绿色通道)相乘
  metalness: 1.0, // 0 = 电介质,1 = 金属;与 metalnessMap(蓝色通道)相乘,因此使用贴图时保留为 1
  map,
  roughnessMap: ormMap,
  metalnessMap: ormMap,
  normalMap: null, // 表面细节;通过 normalScale(一个 Vector2)缩放
  aoMap: ormMap, // 环境光遮蔽(红色通道);强度通过 aoMapIntensity 控制
  displacementMap: null, // 顶点位移;通过 displacementScale 缩放,通过 displacementBias 偏移
  emissive: 0x000000,
  emissiveIntensity: 1,
  emissiveMap: null, // sRGB
  envMap: null, // 或依赖 scene.environment(见下文)
  fog: true,
});

lightMap(与 lightMapIntensity 一起)烘焙间接光照的方式与 aoMap 烘焙遮挡相同;HDR 或 EXR 格式的 lightMap 是 LinearSRGBColorSpace,加载器会设置它。

UV 通道:aoMap 和 lightMap 读取您选择的通道

每个使用 UV 映射的纹理都会采样由 texture.channel 选择的属性:0 读取 uv(默认),1 读取 uv1,2 读取 uv2,3 读取 uv3。aoMap 和 lightMap 不需要第二组 UV 坐标 —— 除非您更改 channel,否则它们采样 uv。GLTFLoader 将 TEXCOORD_1 加载为 uv1 并自行设置 channel。

const aoMap = await new THREE.TextureLoader().loadAsync("ao.jpg"); // 标量:保留默认设置
const material = new THREE.MeshStandardMaterial({ aoMap }); // 采样 uv:不需要额外属性

// 针对单独展开(烘焙的 AO 或光照贴图)的替代方案:将烘焙器的 u、v 对复制到 uv1
const bakedUv = new THREE.Float32BufferAttribute(mesh.geometry.attributes.position.count * 2, 2); // 在复制之前用零填充
mesh.geometry.setAttribute("uv1", bakedUv); mesh.material = material;
aoMap.channel = 1; // 此材质现在采样 uv1 而不是 uv

MeshPhysicalMaterial (高级 PBR)

扩展 MeshStandardMaterial,增加层和体积特性。其中大多数都有纹理变体:clearcoatMap、clearcoatRoughnessMap、clearcoatNormalMap、transmissionMap、thicknessMap、iridescenceMap、iridescenceThicknessMap、sheenColorMap、sheenRoughnessMap、anisotropyMap、specularIntensityMap、specularColorMap。

const material = new THREE.MeshPhysicalMaterial({
  // 清漆(车漆、漆器)
  clearcoat: 1.0, // 0 = 无,1 = 完全覆盖
  clearcoatRoughness: 0.1,
  // 透射(玻璃、水) - 折射其后的不透明物体和 scene.background
  transmission: 1.0, // 0 = 不透明,1 = 完全透射
  thickness: 0.5, // 用于折射的体积厚度
  attenuationDistance: 1, // 世界单位;Infinity(默认)= 无吸收
  attenuationColor: new THREE.Color(0xffaa66), // 白光在穿过 attenuationDistance 后变为此颜色
  ior: 1.5, // 折射率,1 到 2.333
  // 绒面(织物、天鹅绒)
  sheen: 1.0,
  sheenColor: new THREE.Color(0xffffff),
  sheenRoughness: 0.5,
  // 彩虹色(肥皂泡、油膜)
  iridescence: 1.0,
  iridescenceIOR: 1.3,
  iridescenceThicknessRange: [100, 400], // 纳米
  // 各向异性(拉丝金属);方向由 anisotropyRotation 控制
  anisotropy: 1.0,
  // 色散(棱镜玻璃);后向反射(路标、安全设备)
  dispersion: 0.0,
  retroreflectivity: 0.0,
  // 高光覆盖:specularIntensity、specularColor(以及它们的贴图)
});

玻璃——具有光滑表面和后方可折射物体的透射材质:

const glass = new THREE.MeshPhysicalMaterial({
  color: 0xffffff,
  metalness: 0,
  roughness: 0,
  transmission: 1,
  thickness: 0.5,
  ior: 1.5,
});
// transmission 折射其后方的物体和背景;scene.environment 添加其反射

MeshToonMaterial

卡通着色。渐变贴图是非颜色数据——保留其默认色彩空间。

const steps = new Uint8Array([120, 200]); // 两个着色阶梯
const gradientMap = new THREE.DataTexture(steps, 2, 1, THREE.RedFormat);
gradientMap.minFilter = THREE.NearestFilter; // 硬边缘;LinearFilter 会混合它们
gradientMap.magFilter = THREE.NearestFilter;
gradientMap.needsUpdate = true;

const material = new THREE.MeshToonMaterial({ color: 0x00ff00, gradientMap });

MeshNormalMaterial 和 MeshDepthMaterial

// 法线编码为 RGB - 用于调试和平坦示意效果
const normals = new THREE.MeshNormalMaterial({ flatShading: false, wireframe: false });

// 深度编码为灰度(BasicDepthPacking,默认);RGBADepthPacking 将其打包以便在着色器中读取
const depth = new THREE.MeshDepthMaterial();

PointsMaterial

用于点云。size 以像素为单位;启用 sizeAttenuation(默认,仅限透视相机)时,它乘以画布高度的一半并除以点在视图空间中的深度。

const geometry = new THREE.BufferGeometry();
geometry.setAttribute("position", new THREE.Float32BufferAttribute([0, 0, 0, 1, 0.5, 0, 0.5, 1, 0], 3));

const material = new THREE.PointsMaterial({
  color: 0xffffff,
  size: 0.1,
  sizeAttenuation: true, // 随距离缩放
  alphaTest: 0.5, // 与贴图或 alphaMap 一起使用:丢弃低于此 alpha 值的片段
});

const points = new THREE.Points(geometry, material);
scene.add(points);

LineBasicMaterial 和 LineDashedMaterial

WebGL 和 WebGPU 始终绘制 1 像素宽的线条图元;linewidth、linecap 和 linejoin 仅影响 SVGRenderer。要在 WebGLRenderer 下绘制粗线,请使用 three/addons/lines/ 中的 Line2、LineGeometry 和 LineMaterial(linewidth 以像素为单位);LineMaterial 是一个 ShaderMaterial,因此 WebGPURenderer 需要使用 three/addons/lines/webgpu/Line2.js 中的 Line2,它使用 Line2NodeMaterial。

const geometry = new THREE.BufferGeometry();
geometry.setAttribute("position", new THREE.Float32BufferAttribute([-1, 0, 0, 1, 0, 0], 3));

const solid = new THREE.LineBasicMaterial({ color: 0xffffff }); // 始终 1 像素

const dashed = new THREE.LineDashedMaterial({ color: 0xffffff, dashSize: 0.5, gapSize: 0.25 });
const line = new THREE.Line(geometry, dashed);
line.computeLineDistances(); // 必需,否则线条绘制为实线
scene.add(line);

ShaderMaterial (仅限 WebGLRenderer)

使用 Three.js 为您注入 uniform 的自定义 GLSL。它始终编译为 GLSL ES 3.00:texture()、textureLod() 和 dFdx 正常工作,texture2D / gl_FragColor 作为别名保留——让 glslVersion 保持未设置状态。ShaderMaterial、RawShaderMaterial 和 onBeforeCompile 没有 WebGPURenderer 路径;在那里,请使用节点材质和 TSL。

const timer = new THREE.Timer();
timer.connect(document); // 标签页隐藏时暂停

const material = new THREE.ShaderMaterial({
  uniforms: { time: { value: 0 } },
  vertexShader: `
    varying vec2 vUv;
    uniform float time;
    void main() {
      vUv = uv;
      vec3 pos = position;
      pos.z += sin(pos.x * 10.0 + time) * 0.1;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
    }
  `,
  fragmentShader: `
    varying vec2 vUv;
    uniform float time;
    void main() {
      vec3 col = 0.5 + 0.5 * cos(time + vUv.xyx * 3.0);
      gl_FragColor = vec4(col, 1.0);
    }
  `,
});

function animate() {
  timer.update(); // 每帧第一件事,无参数
  material.uniforms.time.value = timer.getElapsed();
  renderer.render(scene, camera);
}

为您在着色器中声明的变量:modelMatrix、modelViewMatrix、projectionMatrix、viewMatrix、normalMatrix、cameraPosition,以及属性 position、normal、uv(此外,对于 InstancedMesh,还有 instanceMatrix,您需要自行应用:projectionMatrix * modelViewMatrix * instanceMatrix * vec4(pos, 1.0),以及与 vertexColors 一起的 color)。额外的 UV 集合和 tangent 未声明——请自行添加 in vec2 uv1;。

RawShaderMaterial (仅限 WebGLRenderer)

不会预先添加任何声明(仅从 glslVersion 添加 #version、SHADER_TYPE 和 SHADER_NAME 定义以及您的 defines),但渲染器仍然会设置 projectionMatrix、modelViewMatrix、viewMatrix、normalMatrix、modelMatrix 和 cameraPosition——在着色器中声明它们,切勿在 uniforms 中传递:同名的条目会在每次绘制时被覆盖(modelMatrix、modelViewMatrix、normalMatrix)或替换相机的值(projectionMatrix、viewMatrix、cameraPosition)。

const material = new THREE.RawShaderMaterial({
  glslVersion: THREE.GLSL3, // 没有它,着色器是 GLSL ES 1.00,不支持 texture()
  vertexShader: `
    precision highp float;
    precision highp int;
    uniform mat4 modelViewMatrix;
    uniform mat4 projectionMatrix;
    in vec3 position;
    void main() {
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    precision highp float;
    precision highp int;
    out vec4 fragColor;
    void main() {
      fragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }
  `,
});

共享属性

跨越多种材质类型生效:

  • 混合模式:transparent: true 启用透明度;blending: THREE.NormalBlending(默认)、AdditiveBlending、SubtractiveBlending、MultiplyBlending、CustomBlending(与 blendSrc、blendDst、blendEquation 一起使用)。
  • 模板测试:stencilWrite: true 结合 stencilRef、stencilFunc、stencilFail、stencilZFail、stencilZPass。
  • 剔除模式:side: THREE.FrontSide(默认)、BackSide、DoubleSide。
  • 深度测试:depthTest: true、depthWrite: true、depthFunc: THREE.LessEqualDepth。
  • 多边形偏移:polygonOffset: true、polygonOffsetFactor、polygonOffsetUnits(用于修复 z-fighting)。
  • 渲染顺序:renderOrder(整数)控制绘制顺序
  • 强制单面:forceSinglePass: true(用于双面渲染只是复制几何体的情况)。
  • 片段丢弃:alphaTest: 0.5 丢弃低于此 alpha 值的片段。

环境响应

scene.environment 是一个 PMREMGenerator 生成的纹理立方体贴图,为场景中的所有标准/物理材质提供间接镜面反射和漫反射光照。遮罩:

  • 材质 < 标准材质忽略 scene.environment
  • envMap 属性显式设置环境贴图;设置了它之后,材质会忽略 scene.environment
  • envMapIntensity(默认为 1)缩放反射贡献;设置为 0 可移除镜面反射
import { RGBELoader } from "three/addons/loaders/RGBELoader.js";

const rgbeLoader = new RGBELoader();
const texture = await rgbeLoader.loadAsync("environment.hdr");
const pmremGenerator = new THREE.PMREMGenerator(renderer);
const envMap = pmremGenerator.fromEquirectangular(texture).texture;
// 为所有 PBR 材质设置:
scene.environment = envMap;
// 或逐个材质显式设置:
const material = new THREE.MeshStandardMaterial({ envMap, envMapIntensity: 0.5 });
texture.dispose(); // PMREMGenerator 复制了数据;原始纹理不再需要
pmremGenerator.dispose();

对于局部光照贴图,specularMap(sRGB)控制哪些区域接收环境贴图反射(sRGB)。

WebGPU 节点材质和 TSL

当使用 WebGPURenderer 时,所有基于 ShaderMaterial 的材质(包括 Line2NodeMaterial)都更倾向于使用节点 / TSL API。编译后的着色器输出 WGSL,而不是 GLSL。标准材质(MeshBasicNodeMaterial、MeshStandardNodeMaterial 等)在内部使用节点。您可以直接使用节点和 TSL 来构建自定义着色器:

import { MeshBasicNodeMaterial, uv, texture, mix, timerLocal } from "three/tsl";

const map = await new THREE.TextureLoader().loadAsync("color.jpg");
map.colorSpace = THREE.SRGBColorSpace;

const material = new MeshBasicNodeMaterial();
material.colorNode = mix(
  texture(map, uv().scale(2.0)),    // 采样的颜色
  texture(map, uv().scale(0.5)),    // 较小的缩放
  timerLocal().mul(0.5).sin()       // 随时间淡入淡出
);

const mesh = new THREE.Mesh(new THREE.SphereGeometry(1, 48, 32), material);

raw 材质(例如 PointsNodeMaterial、SpriteNodeMaterial、VolumeNodeMaterial、Line2NodeMaterial)也可用。您可以使用节点构建自定义 effect:创建一个 MeshBasicNodeMaterial,设置 colorNode、opacityNode、positionNode,然后将它用作自定义 ShaderMaterial 的替代方案。

常见错误

  • 贴图在材质上显得发白或褪色:检查颜色纹理(map、emissiveMap、specularMap)是否设置了 texture.colorSpace = THREE.SRGBColorSpace。标量纹理(roughness、metalness、normal、ao、displacement、toon gradientMap)保留默认的 texture.colorSpace(通常是 THREE.LinearSRGBColorSpace)。光线贴图(用于烘焙间接光)是 HDR 或 EXR,应由加载器设置为 LinearSRGBColorSpace。
  • 标准/物理材质渲染为黑色:检查场景中是否有灯光(定向光、点光、环境光、半球光)或有效的 scene.environment。
  • 深度问题:检查 depthWrite 和 depthTest 设置,尤其是在使用透明或混合材质时。
  • 线宽无效:linewidth 仅适用于 SVGRenderer;对于 WebGLRenderer 中的粗线,使用 Line2 / LineMaterial。
  • ShaderMaterial 的 texture2D 错误:如果显式设置 glslVersion 导致 GLSL ES 1.00,则 texture2D 会失败。将其保持未设置状态以获得 GLSL ES 3.00。
  • 残留的 outputBuffer 引用:outputBuffer(通常用于 OnBeforeCompile 补丁着色器)在 r186+ 中已弃用——使用 renderer.outputBufferType。

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

相关技能