mcpField
T
threejs-materials

threejs-materials

github.com/cloudai-x创意与媒体3.8k15.3k 次安装1 周前更新
代码仓库

关于 threejs-materials

面向 three.js r186 开发者的材质参考技能,涵盖材质选择、纹理处理,以及 WebGL 和 WebGPU 渲染细节。

主要功能

  1. 01内置材质类型概览
  2. 02PBR 与分层材质配置
  3. 03纹理色彩空间和 UV 指南
  4. 04WebGLRenderer 的 GLSL 着色器
  5. 05WebGPU 与 TSL 材质说明

适用场景

  1. 01为 three.js 场景选择材质
  2. 02配置 PBR 纹理与 UV 通道
  3. 03创建玻璃等分层表面
  4. 04编写自定义 WebGL 着色器

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/cloudai-x/threejs-skills --skill threejs-materials

安装后在 Claude Code 中输入/threejs-materials确认已加载。

详细介绍

Three.js 材质

适用于 three.js r186。示例使用 WebGLRenderer;WebGPU 和 TSL 部分使用 WebGPURenderer。

快速开始

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 material - the default choice for lit, realistic surfaces
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)); // lit materials render black without lights
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,以及用作颜色的 canvas 或 video)需要设置 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, // multiplied with the map
  map,
  transparent: true,
  opacity: 0.5,
  side: THREE.DoubleSide, // FrontSide (default), BackSide, DoubleSide
  fog: true, // affected by scene fog
});

MeshLambertMaterial 和 MeshPhongMaterial

Lambert 仅支持漫反射。Phong 会添加高光;当 Standard 开销太大时,它是更廉价的替代方案。

const lambert = new THREE.MeshLambertMaterial({
  color: 0x00ff00,
  emissive: 0x111111, // self-illumination color
  emissiveIntensity: 1,
});

const phong = new THREE.MeshPhongMaterial({
  color: 0x0000ff,
  specular: 0x111111, // highlight color
  shininess: 30, // higher = sharper highlight
  flatShading: false, // flat vs smooth normals
});

二者也支持 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 red, roughness green, metalness blue; scalar: keep default

const material = new THREE.MeshStandardMaterial({
  color: 0xffffff, // multiplied with the map
  roughness: 1.0, // 0 = mirror, 1 = fully diffuse; multiplied by roughnessMap (green)
  metalness: 1.0, // 0 = dielectric, 1 = metal; multiplied by metalnessMap (blue), so keep 1 with a map
  map,
  roughnessMap: ormMap,
  metalnessMap: ormMap,
  normalMap: null, // surface detail; scale with normalScale (a Vector2)
  aoMap: ormMap, // ambient occlusion (red); intensity with aoMapIntensity
  displacementMap: null, // vertex displacement; scale with displacementScale, offset with displacementBias
  emissive: 0x000000,
  emissiveIntensity: 1,
  emissiveMap: null, // sRGB
  envMap: null, // or rely on scene.environment (see below)
  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"); // scalar: keep default
const material = new THREE.MeshStandardMaterial({ aoMap }); // samples uv: no extra attribute needed

// Alternative for a separate unwrap (a baked AO or light map): copy your baker's u,v pairs into uv1
const bakedUv = new THREE.Float32BufferAttribute(mesh.geometry.attributes.position.count * 2, 2); // zero-filled until you copy them in
mesh.geometry.setAttribute("uv1", bakedUv); mesh.material = material;
aoMap.channel = 1; // this material now samples uv1 instead of uv

MeshPhysicalMaterial(高级 PBR)

扩展 MeshStandardMaterial,添加了图层和体积特性。大多数特性都有对应的纹理变体:clearcoatMap、clearcoatRoughnessMap、clearcoatNormalMap、transmissionMap、thicknessMap、iridescenceMap、iridescenceThicknessMap、sheenColorMap、sheenRoughnessMap、anisotropyMap、specularIntensityMap、specularColorMap。

const material = new THREE.MeshPhysicalMaterial({
  // Clearcoat (car paint, lacquer)
  clearcoat: 1.0, // 0 = none, 1 = full coat
  clearcoatRoughness: 0.1,
  // Transmission (glass, water) - refracts the opaque objects and scene.background behind it
  transmission: 1.0, // 0 = opaque, 1 = fully transmissive
  thickness: 0.5, // volume thickness for refraction
  attenuationDistance: 1, // world units; Infinity (the default) = no absorption
  attenuationColor: new THREE.Color(0xffaa66), // white light turns this color after attenuationDistance
  ior: 1.5, // index of refraction, 1 to 2.333
  // Sheen (fabric, velvet)
  sheen: 1.0,
  sheenColor: new THREE.Color(0xffffff),
  sheenRoughness: 0.5,
  // Iridescence (soap bubbles, oil slicks)
  iridescence: 1.0,
  iridescenceIOR: 1.3,
  iridescenceThicknessRange: [100, 400], // nanometers
  // Anisotropy (brushed metal); direction with anisotropyRotation
  anisotropy: 1.0,
  // Dispersion (prismatic glass); retroreflectivity (road signs, safety gear)
  dispersion: 0.0,
  retroreflectivity: 0.0,
  // Specular overrides: specularIntensity, specularColor (plus their maps)
});

玻璃——使用透射和光滑表面,并在后方放置可供折射的物体:

const glass = new THREE.MeshPhysicalMaterial({
  color: 0xffffff,
  metalness: 0,
  roughness: 0,
  transmission: 1,
  thickness: 0.5,
  ior: 1.5,
});
// transmission refracts the opaque objects and background behind it; scene.environment adds its reflections

MeshToonMaterial

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

const steps = new Uint8Array([120, 200]); // two shading steps
const gradientMap = new THREE.DataTexture(steps, 2, 1, THREE.RedFormat);
gradientMap.minFilter = THREE.NearestFilter; // hard steps; LinearFilter blends them
gradientMap.magFilter = THREE.NearestFilter;
gradientMap.needsUpdate = true;

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

MeshNormalMaterial 和 MeshDepthMaterial

// Normals encoded as RGB - debugging and flat illustrative looks
const normals = new THREE.MeshNormalMaterial({ flatShading: false, wireframe: false });

// Depth as grayscale (BasicDepthPacking, the default); RGBADepthPacking packs it for reading back in a shader
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, // scale with distance
  alphaTest: 0.5, // with a map or alphaMap: discard fragments below this alpha
});

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

LineBasicMaterial 和 LineDashedMaterial

WebGL 和 WebGPU 始终以 1 px 宽度绘制线图元;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 }); // always 1 px

const dashed = new THREE.LineDashedMaterial({ color: 0xffffff, dashSize: 0.5, gapSize: 0.25 });
const line = new THREE.Line(geometry, dashed);
line.computeLineDistances(); // required, or the line draws solid
scene.add(line);

ShaderMaterial(仅限 WebGLRenderer)

自定义 GLSL,three.js 会为你注入 uniforms。它始终编译为 GLSL ES 3.00:texture()、textureLod() 和 dFdx 均可使用,texture2D / gl_FragColor 仍作为别名保留——请勿设置 glslVersion。ShaderMaterial、RawShaderMaterial 和 onBeforeCompile 均无法用于 WebGPURenderer;在 WebGPURenderer 中,请使用节点材质和 TSL。

const timer = new THREE.Timer();
timer.connect(document); // pause when the tab is hidden

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(); // first thing every frame, no argument
  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, // without it the shader is GLSL ES 1.00, which has no texture()
  vertexShader: `
    precision highp float;
    in vec3 position;
    uniform mat4 projectionMatrix;
    uniform mat4 modelViewMatrix;
    void main() {
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  fragmentShader: `
    precision highp float;
    out highp vec4 fragColor; // your own output variable
    void main() {
      fragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }
  `,
});

常用属性

const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });

material.visible = true;
material.transparent = false; // true for opacity below 1; toggling it after the first render needs needsUpdate
material.opacity = 1.0;
material.alphaTest = 0; // discard fragments with alpha below the value
material.side = THREE.FrontSide; // FrontSide, BackSide, DoubleSide
material.depthTest = true;
material.depthWrite = true;
material.blending = THREE.NormalBlending; // or AdditiveBlending, CustomBlending
material.polygonOffset = false; // with the two values below, fixes z-fighting
material.polygonOffsetFactor = 0;
material.polygonOffsetUnits = 0;
material.toneMapped = true; // false keeps exact colors (UI overlays)
material.dithering = false; // true reduces banding in gradients
material.vertexColors = false;
// Multiply and subtractive blending require premultiplied alpha (both renderers)
const material = new THREE.MeshBasicMaterial({ color: 0x8844ff });
material.blending = THREE.SubtractiveBlending; // same for THREE.MultiplyBlending
material.premultipliedAlpha = true; // without it the renderer logs an error and sets no blend function

// Stencil is off by default in both renderers: create the renderer with { stencil: true }
const maskMaterial = new THREE.MeshBasicMaterial({ colorWrite: false, depthWrite: false });
maskMaterial.stencilWrite = true; // master switch for the stencil test and write
maskMaterial.stencilRef = 1;
maskMaterial.stencilZPass = THREE.ReplaceStencilOp; // writes 1 where the mask draws; also stencilFail, stencilZFail
const contentMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000, stencilWrite: true, stencilRef: 1 });
contentMaterial.stencilFunc = THREE.EqualStencilFunc; // draws only where the mask wrote 1
contentMaterial.stencilFuncMask = 0xff; // compare mask; stencilWriteMask masks the write (both default 0xff)
// draw the mask first: give its mesh a lower renderOrder than the content mesh

一个 Mesh 使用多种材质

// One material per geometry group; BoxGeometry has six, in the order +x, -x, +y, -y, +z, -z
const geometry = new THREE.BoxGeometry(1, 1, 1);
const colors = [0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff];
const mesh = new THREE.Mesh(geometry, colors.map((color) => new THREE.MeshBasicMaterial({ color })));

// Custom groups: start, count, material index. Indexed geometry counts indices (BoxGeometry has 36),
// non-indexed geometry counts vertices; ranges outside every group are not drawn
geometry.clearGroups();
geometry.addGroup(0, 18, 0);
geometry.addGroup(18, 18, 1);

环境贴图

等距柱状 HDR 文件可以照亮场景中所有 PBR 材质并在其上产生反射。两个渲染器都会自行预过滤,无需 PMREM 步骤。

import { HDRLoader } from "three/addons/loaders/HDRLoader.js";

const env = await new HDRLoader().loadAsync("environment.hdr");
env.mapping = THREE.EquirectangularReflectionMapping; // without it a background draws as a flat quad
scene.environment = env; // lights and reflects PBR materials
scene.background = env;
scene.environmentIntensity = 0.8; // scene-wide dimmer; scene.environmentRotation tilts it
const cubeEnv = new THREE.CubeTextureLoader().load([
  "px.jpg", "nx.jpg", "py.jpg", "ny.jpg", "pz.jpg", "nz.jpg",
]);

const material = new THREE.MeshStandardMaterial({ envMap: cubeEnv });
material.envMapIntensity = 1.5; // scales only this material's own envMap
material.envMapRotation = new THREE.Euler(0, Math.PI / 4, 0);

scene.environment 可在两个渲染器中为 MeshStandardMaterial 和 MeshPhysicalMaterial 提供照明。使用 WebGLRenderer 时,它也能为 MeshLambertMaterial 和 MeshPhongMaterial 提供照明;WebGPURenderer 则不支持。

运行时更改、克隆与释放

mesh.material.color.set(0xff0000); // uniform values: no recompile needed
mesh.material.roughness = 0.8;

// material.needsUpdate = true after changing a setting compiled into the shader:
// transparent, side, blending, flatShading, vertexColors, dithering, premultipliedAlpha, alphaHash,
// adding or removing a map slot, or shader source (alphaTest and envMap recompile by themselves)

const clone = mesh.material.clone(); // copies values; map slots share their textures, ShaderMaterial uniforms are cloned

当材质不再被其他对象使用时,调用 material.dispose() 释放其 GPU 程序;只有在没有其他材质使用这些程序后,它们才会被删除。纹理需要单独调用 texture.dispose()。

性能优化,按影响从大到小排列:

  1. 多个网格共享同一个材质实例——连续绘制切换材质时,渲染器会重新上传材质 uniforms(设置相同的材质已共享同一个已编译程序)。
  2. 优先使用不透明材质:透明材质按对象从后向前排序,并在不透明材质之后绘制;除非设置 depthWrite: false,否则仍会写入深度,因此堆叠的图层会产生过度绘制,彼此相交的图层则可能排序错误。对于镂空效果,alphaTest 会使材质保持不透明,因此它会在不透明渲染阶段绘制,且无论顺序如何都能正确显示。
  3. 选择满足视觉效果的最低成本材质:Basic,其次是 Lambert、Phong、Standard、Physical。

WebGPU 和 TSL

MeshStandardMaterial 和其他内置类无需更改即可用于 WebGPURenderer——渲染器会自动将它们转换为节点材质;ShaderMaterial、RawShaderMaterial、MeshDepthMaterial 和 MeshDistanceMaterial 没有对应的节点材质,会记录 Material "..." is not compatible。要进行自定义着色,请使用 three/webgpu 中的节点材质类和 three/tsl 中的 TSL 节点;它们面向 WebGPURenderer,而 WebGLRenderer 只能通过 WebGLNodesHandler 插件(three/addons/tsl/WebGLNodesHandler.js,传入 renderer.setNodesHandler())来绘制这些材质。这是一种迁移辅助方案,不支持 VSM 阴影、MRT、透射效果或 WebGPU 后期处理堆栈。

import * as THREE from "three/webgpu";

const renderer = new THREE.WebGPURenderer({ antialias: true });
await renderer.init(); // before any other use of the renderer
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const scene = new THREE.Scene();
scene.background = new THREE.Color(0x111111); // the WebGPU canvas is transparent by default
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 100);
camera.position.set(0, 0, 3);

function animate() {
  renderer.render(scene, camera);
}

renderer.setAnimationLoop(animate);
import * as THREE from "three/webgpu";
import { texture, mix, color, float, time, positionLocal, normalLocal, sin } from "three/tsl";

// Unlit: the node equivalent of a color ShaderMaterial
const unlit = new THREE.MeshBasicNodeMaterial();
unlit.colorNode = mix(color(0x0066ff), color(0xff0066), sin(time.mul(0.5)).mul(0.5).add(0.5));

// Lit: node slots replace the fixed properties; needs lights or scene.environment
const map = await new THREE.TextureLoader().loadAsync("color.jpg");
map.colorSpace = THREE.SRGBColorSpace;
const lit = new THREE.MeshStandardNodeMaterial();
lit.colorNode = texture(map);
lit.roughnessNode = float(0.2);

// Vertex displacement on positionLocal, which already carries skinning, morphs, instancing
const shell = new THREE.MeshStandardNodeMaterial();
shell.positionNode = positionLocal.add(normalLocal.mul(sin(positionLocal.y.mul(6))).mul(0.05));
import * as THREE from "three/webgpu";
import { instancedBufferAttribute } from "three/tsl";

// The WebGPU backend draws Points at 1 px whatever the size; draw larger points as quads
const positions = new THREE.InstancedBufferAttribute(new Float32Array(1500), 3); // fill with x, y, z per point
const points = new THREE.Sprite(
  new THREE.PointsNodeMaterial({ positionNode: instancedBufferAttribute(positions), size: 4, sizeAttenuation: false }) // 4 px squares
);
points.count = 500; points.frustumCulled = false; // one quad per point; culling would test only a 0.7-unit sphere at the sprite origin
scene.add(points);

常见错误

  • geometry.setAttribute("uv2", geometry.attributes.uv) → const material = new THREE.MeshStandardMaterial({ aoMap });:aoMap 会采样 aoMap.channel 指定的属性,默认值为 0(uv),因此无需额外属性;只有设置 aoMap.channel = 2 时才会读取 uv2;只有单独展开的 UV 才放入 uv1,并设置 aoMap.channel = 1。
  • new RGBELoader() → new HDRLoader():HDRLoader 在 r180 中由 RGBELoader 更名而来;RGBELoader 已弃用,但仍可加载,只会发出警告——从 "three/addons/loaders/HDRLoader.js" 导入 HDRLoader。
  • "three/examples/jsm/loaders/HDRLoader.js" → "three/addons/loaders/HDRLoader.js":浏览器导入映射将 three/addons/ 映射到 examples/jsm/,且没有定义 three/examples/ 键,因此 examples 路径会失败。
  • material.blending = THREE.MultiplyBlending; → material.blending = THREE.MultiplyBlending; material.premultipliedAlpha = true;:相乘和相减混合需要预乘 Alpha,否则渲染器会记录错误,且不会设置混合函数。
  • material.stencilMask = 0xff; → material.stencilFuncMask = 0xff; material.stencilWriteMask = 0xff;:stencilMask 不存在;给它赋值只会创建一个未使用的字段。
  • new THREE.WebGLRenderer({ antialias: true }) → new THREE.WebGLRenderer({ antialias: true, stencil: true }):模板缓冲区默认关闭,因此未启用时,材质的模板设置会被静默忽略。
  • material.envMapIntensity = 0.5; → scene.environmentIntensity = 0.5;:要调暗 scene.environment,请使用 scene 属性;envMapIntensity 只会减弱材质自身的 envMap。
  • material.uniforms.time.value = clock.getElapsedTime(); → material.uniforms.time.value = timer.getElapsed();:Clock 在 r183 中已弃用——创建一个 THREE.Timer,调用一次 timer.connect(document),并在循环中先调用不带参数的 timer.update()。
  • new THREE.ShaderMaterial({ glslVersion: THREE.GLSL3, fragmentShader }) → new THREE.ShaderMaterial({ fragmentShader }):ShaderMaterial 已使用 GLSL ES 3.00 编译,因此即使 glslVersion 未设置,texture() 也能正常使用;而 GLSL3 会移除 gl_FragColor 别名,使用该别名的着色器将无法编译。
  • uniforms: { modelViewMatrix: { value: new THREE.Matrix4() } } → uniform mat4 modelViewMatrix;:在 RawShaderMaterial 的着色器源代码中声明内置矩阵——同名的 uniforms 条目会在每次绘制时被覆盖(modelMatrix、modelViewMatrix、normalMatrix),或替换相机的值(projectionMatrix、viewMatrix、cameraPosition)。
  • new THREE.LineBasicMaterial({ linewidth: 5 }) → new Line2(new LineGeometry().setPositions([-1, 0, 0, 1, 0, 0]), new LineMaterial({ linewidth: 5 })):WebGLRenderer 始终以 1 px 绘制线图元;Line2 需要 LineGeometry,而不是 BufferGeometry,并且这三者都来自 three/addons/lines/(在 WebGPURenderer 下,Line2 来自 three/addons/lines/webgpu/Line2.js,搭配 Line2NodeMaterial 使用)。
  • new THREE.ShaderMaterial({ vertexShader, fragmentShader }) → new THREE.MeshBasicNodeMaterial():在 WebGPURenderer 下,请使用节点材质和 TSL——ShaderMaterial 和 RawShaderMaterial 没有对应的节点版本,并会记录“is not compatible”。
  • import { texture } from "three/nodes"; → import { texture } from "three/tsl";:three/nodes 不存在——节点材质来自 three/webgpu,TSL 函数来自 three/tsl。
  • import * as THREE from "three"; const m = new THREE.MeshStandardNodeMaterial(); → import * as THREE from "three/webgpu"; const m = new THREE.MeshStandardNodeMaterial();:节点材质仅由 three/webgpu 导出,目标渲染器为 WebGPURenderer。
  • new THREE.PointsMaterial({ size: 5 }) → new THREE.Sprite(new THREE.PointsNodeMaterial({ positionNode: instancedBufferAttribute(positions) })):无论 size 值是多少,WebGPU 后端都会以 1 px 绘制 Points——请将 sprite.count 设为点的数量。
  • material.positionNode = positionGeometry.add(offset); → material.positionNode = positionLocal.add(offset);:positionLocal 会保留蒙皮、变形目标、批处理和实例化效果;positionGeometry 是原始静止姿势下的属性。
  • map.encoding = THREE.sRGBEncoding; → map.colorSpace = THREE.SRGBColorSpace;:encoding 和 sRGBEncoding 已不存在,因此旧代码不会产生任何效果,颜色贴图会显得褪色。
  • const m = new THREE.MeshStandardNodeMaterial(); m.colorNode = color(0xff0000); → const m = new THREE.MeshBasicNodeMaterial(); m.colorNode = color(0xff0000);:MeshStandardNodeMaterial 受光照影响,没有灯光或环境时会渲染为黑色,因此无光照效果应使用 MeshBasicNodeMaterial。
  • new THREE.ShaderMaterial({ extensions: { derivatives: true }, fragmentShader }) → new THREE.ShaderMaterial({ fragmentShader }):WebGL1 扩展标志不起作用,因为 GLSL ES 3.00 已内置 dFdx、gl_FragDepth 和 textureLod。

另请参阅

  • threejs-textures - 深入了解加载、色彩空间、滤镜和通道
  • threejs-shaders - GLSL 编写、着色器代码块,以及在 WebGLRenderer 下进行调试
  • threejs-lighting - 灯光、阴影及其与材质的交互

评论

支持 Markdown