UtkarshBirla28/threejs-materials

Choix et configuration des matériaux three.js : non éclairés, diffus, spéculaires, PBR, toon, matériaux de points et lignes, propriétés partagées (blending, stencil), réponse à l'environnement, et équivalents WebGPU node-material et TSL. À utiliser pour styliser les maillages ou ajuster le comportement des matériaux.

Qu'est-ce que threejs-materials ?

Ce skill fournit un guide complet pour sélectionner et configurer les matériaux three.js, ciblant la version r186. Il couvre tous les types de matériaux, des plus basiques (MeshBasicMaterial, PointsMaterial) aux plus avancés (MeshPhysicalMaterial avec transmission, clearcoat ou iridescence). Le guide explique les propriétés partagées (blending, stencil, réponse à l'environnement) et comment utiliser les textures et la lumière. Il inclut également une section dédiée au WebGPU et au TSL (Three.js Shading Language), avec des exemples pour les matériaux nodaux et les équivalents TSL de la node-material, bien que le WebGL domine sur la plupart des cas. Un avertissement important est présent pour les projets utilisant trois 0.175 (r175) et Remotion : il détaille les différences API à ne pas utiliser, les choix de post-processing (pmndrs `postprocessing` au lieu d'EffectComposer) et les conventions d'animation (basées sur `useCurrentFrame()`). Le skill est indispensable pour les développeurs travaillant sur des rendus 3D avec three.js, que ce soit pour le WebGL ou WebGPU, et pour ceux qui migrent entre versions ou qui utilisent des pipelines d'animation avec Remotion.

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

Installed? Explore more Développement et programmation skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Matériaux Three.js

Cible three.js r186. Les exemples utilisent WebGLRenderer ; la section WebGPU et TSL utilise WebGPURenderer.

Remplacement local (ajouté le 2026-11-10 par Claude pour ce PC ; ne fait pas partie du skill d'origine). Notre pipeline de courts métrages animés (<ROOT>\studio, de mromidev/claude-animated-shorts) est verrouillé sur three 0.175 (r175)

  • Remotion 4.0.290 + @react-three/fiber 9.1.2 + pmndrs postprocessing 6.37.2. Garder three verrouillé : shade.ts/cardshade.ts corrige les chunks de shader three par chaîne de caractères. Lorsque vous travaillez sur ce pipeline :
  • Ignorer les « Erreurs courantes » / conseils API nécessitant r176+ (dépréciation HDRLoader, Timer, PCFSoftShadowMap, setEffects, RenderPipeline, outputBufferType, mesh.pivot, Capsule height, TSL/WebGPU). Vérifier d'abord que l'API existe dans r175.
  • Ne jamais animer avec useFrame, Clock, Timer, delta time, setAnimationLoop ou requestAnimationFrame. Remotion rend image par image : dérivez chaque valeur de useCurrentFrame() / fps (et mixer.setTime(frame / fps) pour les clips).
  • Le post-processing est pmndrs postprocessing, pas three/addons EffectComposer : n'ajoutez pas de OutputPass (double encodage sRGB).
  • Couleurs toon : le mappage de tons est NEUTRE dans notre compositeur ; méfiez-vous des valeurs par défaut ACES et de la teinte tonemapping_fragment.
  • Pour les autres projets three.js, les conseils originaux pour r186 ci-dessous s'appliquent tels quels.

Démarrage rapide

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);

// Matériau PBR - le choix par défaut pour les surfaces éclairées et réalistes
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)); // les matériaux éclairés rendent en noir sans lumières
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);

Aperçu des types de matériaux

MatériauCas d'utilisationÉclairage
MeshBasicMaterialCouleur non éclairée, textures, maquettesAucun
MeshLambertMaterialSurfaces mates diffusesDiffus
MeshPhongMaterialPlastique brillant, spéculaire économiqueDiffus + spéculaire
MeshStandardMaterialFlux de travail PBR métal/rugositéPBR
MeshPhysicalMaterialPBR avec couche transparente, transmission, lustre, iridescencePBR
MeshToonMaterialOmbrage celPas d'ombrage
MeshMatcapMaterialAspect éclairé intégré dans une texture matcap, pas de lumières nécessairesIntégré
ShadowMaterialSurface transparente montrant uniquement les ombres qu'elle reçoitOmbres uniquement
PointsMaterialNuages de pointsAucun
LineBasicMaterial / LineDashedMaterialLignesAucun
ShaderMaterial / RawShaderMaterialGLSL personnalisé, WebGLRenderer uniquementPersonnalisé

Les textures de données de couleur (map, emissiveMap, specularMap, sheenColorMap, specularColorMap, matcap LDR, un canvas ou une vidéo utilisée comme couleur) nécessitent texture.colorSpace = THREE.SRGBColorSpace, sinon les couleurs rendent délavées. Les cartes scalaires (normales, relief, déplacement, rugosité, métallisation, occlusion ambiante, alpha, gradient toon) conservent la valeur par défaut. Les chargeurs HDR définissent leur propre espace colorimétrique.

MeshBasicMaterial

Aucun calcul d'éclairage. Rapide, toujours visible. Prend en charge envMap avec reflectivity (0 à 1) et combine (THREE.MultiplyOperation, THREE.MixOperation, THREE.AddOperation) ; specularMap (sRGB) masque la contribution de l'environment map.

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

const material = new THREE.MeshBasicMaterial({
  color: 0xffffff, // multiplié avec la carte
  map,
  transparent: true,
  opacity: 0.5,
  side: THREE.DoubleSide, // FrontSide (défaut), BackSide, DoubleSide
  fog: true, // affecté par le brouillard de la scène
});

MeshLambertMaterial et MeshPhongMaterial

Lambert est uniquement diffus. Phong ajoute un reflet spéculaire ; c'est l'alternative économique lorsque Standard est trop lourd.

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

const phong = new THREE.MeshPhongMaterial({
  color: 0x0000ff,
  specular: 0x111111, // couleur du reflet
  shininess: 30, // plus élevé = reflet plus net
  flatShading: false, // plat vs lisse pour les normales
});

Les deux prennent également en charge map, emissiveMap, specularMap (sRGB ; masque la réflexion de l'environnement map et le reflet sur Phong), normalMap, bumpMap, displacementMap, aoMap, envMap, envMapIntensity et envMapRotation.

MeshStandardMaterial (PBR)

Rendu physiquement réaliste. Recommandé pour des résultats réalistes.

const map = await new THREE.TextureLoader().loadAsync("color.jpg");
map.colorSpace = THREE.SRGBColorSpace;
const ormMap = await new THREE.TextureLoader().loadAsync("orm.jpg"); // glTF ORM : occlusion rouge, rugosité verte, métallisation bleue ; scalaire : conserver la valeur par défaut

const material = new THREE.MeshStandardMaterial({
  color: 0xffffff, // multiplié avec la carte
  roughness: 1.0, // 0 = miroir, 1 = entièrement diffus ; multiplié par roughnessMap (vert)
  metalness: 1.0, // 0 = diélectrique, 1 = métal ; multiplié par metalnessMap (bleu), donc garder 1 avec une carte
  map,
  roughnessMap: ormMap,
  metalnessMap: ormMap,
  normalMap: null, // détail de surface ; échelle avec normalScale (un Vector2)
  aoMap: ormMap, // occlusion ambiante (rouge) ; intensité avec aoMapIntensity
  displacementMap: null, // déplacement de sommets ; échelle avec displacementScale, décalage avec displacementBias
  emissive: 0x000000,
  emissiveIntensity: 1,
  emissiveMap: null, // sRGB
  envMap: null, // ou se fier à scene.environment (voir ci-dessous)
  fog: true,
});

lightMap (avec lightMapIntensity) cuit la lumière indirecte de la même manière que aoMap cuit l'occlusion ; une lightMap HDR ou EXR est LinearSRGBColorSpace, ce que les chargeurs définissent.

Canaux UV : aoMap et lightMap lisent le canal que vous choisissez

Chaque texture mappée en UV échantillonne l'attribut sélectionné par texture.channel : 0 lit uv (par défaut), 1 lit uv1, 2 lit uv2, 3 lit uv3. aoMap et lightMap n'ont pas besoin d'un deuxième jeu d'UV - ils échantillonnent uv sauf si vous changez channel. GLTFLoader charge TEXCOORD_1 comme uv1 et définit channel lui-même.

const aoMap = await new THREE.TextureLoader().loadAsync("ao.jpg"); // scalaire : conserver la valeur par défaut
const material = new THREE.MeshStandardMaterial({ aoMap }); // échantillonne uv : aucun attribut supplémentaire nécessaire

// Alternative pour un déplié séparé (une carte AO ou de lumière cuite) : copier les paires u,v de votre boulanger dans uv1
const bakedUv = new THREE.Float32BufferAttribute(mesh.geometry.attributes.position.count * 2, 2); // rempli de zéros jusqu'à ce que vous les copiiez
mesh.geometry.setAttribute("uv1", bakedUv); mesh.material = material;
aoMap.channel = 1; // ce matériau échantillonne maintenant uv1 au lieu de uv

MeshPhysicalMaterial (PBR avancé)

Étend MeshStandardMaterial avec des fonctionnalités de couche et de volume. Des variantes de texture existent pour la plupart : clearcoatMap, clearcoatRoughnessMap, clearcoatNormalMap, transmissionMap, thicknessMap, iridescenceMap, iridescenceThicknessMap, sheenColorMap, sheenRoughnessMap, anisotropyMap, specularIntensityMap, specularColorMap.

const material = new THREE.MeshPhysicalMaterial({
  // Couche transparente (peinture automobile, laque)
  clearcoat: 1.0, // 0 = aucune, 1 = couche complète
  clearcoatRoughness: 0.1,
  // Transmission (verre, eau) - réfracte les objets opaques et l'arrière-plan de la scène derrière
  transmission: 1.0, // 0 = opaque, 1 = entièrement transmissif
  thickness: 0.5, // épaisseur du volume pour la réfraction
  attenuationDistance: 1, // unités monde ; Infinity (la valeur par défaut) = pas d'absorption
  attenuationColor: new THREE.Color(0xffaa66), // la lumière blanche devient cette couleur après attenuationDistance
  ior: 1.5, // indice de réfraction, 1 à 2.333
  // Lustre (tissu, velours)
  sheen: 1.0,
  sheenColor: new THREE.Color(0xffffff),
  sheenRoughness: 0.5,
  // Iridescence (bulles de savon, irisations d'huile)
  iridescence: 1.0,
  iridescenceIOR: 1.3,
  iridescenceThicknessRange: [100, 400], // nanomètres
  // Anisotropie (métal brossé) ; direction avec anisotropyRotation
  anisotropy: 1.0,
  // Dispersion (verre prismatique) ; rétroréflectivité (panneaux de signalisation, équipement de sécurité)
  dispersion: 0.0,
  retroreflectivity: 0.0,
  // Remplacements spéculaires : specularIntensity, specularColor (plus leurs cartes)
});

Verre - transmission avec une surface lisse et quelque chose derrière à réfracter :

const glass = new THREE.MeshPhysicalMaterial({
  color: 0xffffff,
  metalness: 0,
  roughness: 0,
  transmission: 1,
  thickness: 0.5,
  ior: 1.5,
});
// la transmission réfracte les objets opaques et l'arrière-plan derrière ; scene.environment ajoute ses réflexions

MeshToonMaterial

Ombrage cel. La carte de gradient est une donnée non colorée - conserver son espace colorimétrique par défaut.

const steps = new Uint8Array([120, 200]); // deux étapes d'ombrage
const gradientMap = new THREE.DataTexture(steps, 2, 1, THREE.RedFormat);
gradientMap.minFilter = THREE.NearestFilter; // étapes dures ; LinearFilter les mélange
gradientMap.magFilter = THREE.NearestFilter;
gradientMap.needsUpdate = true;

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

MeshNormalMaterial et MeshDepthMaterial

// Normales encodées en RGB - débogage et aspects illustratifs plats
const normals = new THREE.MeshNormalMaterial({ flatShading: false, wireframe: false });

// Profondeur en niveaux de gris (BasicDepthPacking, par défaut) ; RGBADepthPacking la conditionne pour la relire dans un shader
const depth = new THREE.MeshDepthMaterial();

PointsMaterial

Pour les nuages de points. size est en pixels ; avec sizeAttenuation (par défaut, caméras perspective uniquement) il est multiplié par la moitié de la hauteur du canvas et divisé par la profondeur du point dans l'espace de vue.

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, // échelle avec la distance
  alphaTest: 0.5, // avec une carte ou alphaMap : ignorer les fragments en dessous de cet alpha
});

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

LineBasicMaterial et LineDashedMaterial

WebGL et WebGPU dessinent toujours les primitives de ligne à 1 px de large ; linewidth, linecap et linejoin n'affectent que le SVGRenderer. Pour les lignes épaisses sous WebGLRenderer, utilisez Line2 avec LineGeometry et LineMaterial depuis three/addons/lines/ (linewidth en pixels) ; LineMaterial est un ShaderMaterial, donc WebGPURenderer a besoin de Line2 depuis three/addons/lines/webgpu/Line2.js, qui utilise 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 }); // toujours 1 px

const dashed = new THREE.LineDashedMaterial({ color: 0xffffff, dashSize: 0.5, gapSize: 0.25 });
const line = new THREE.Line(geometry, dashed);
line.computeLineDistances(); // requis, sinon la ligne dessine en plein
scene.add(line);

ShaderMaterial (WebGLRenderer uniquement)

GLSL personnalisé avec des uniformes three.js injectés pour vous. Il compile toujours en GLSL ES 3.00 : texture(), textureLod() et dFdx fonctionnent, et texture2D / gl_FragColor restent comme alias - laissez glslVersion non défini. ShaderMaterial, RawShaderMaterial et onBeforeCompile n'ont pas de chemin WebGPURenderer ; là, utilisez les matériaux nodaux et TSL.

const timer = new THREE.Timer();
timer.connect(document); // mettre en pause lorsque l'onglet est caché

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(); // en premier à chaque image, sans argument
  material.uniforms.time.value = timer.getElapsed();
  renderer.render(scene, camera);
}

Déclarés pour vous dans le shader : modelMatrix, modelViewMatrix, projectionMatrix, viewMatrix, normalMatrix, cameraPosition, et les attributs position, normal, uv (plus instanceMatrix sur un InstancedMesh, que vous appliquez vous-même : projectionMatrix * modelViewMatrix * instanceMatrix * vec4(pos, 1.0), et color avec vertexColors). Les jeux d'uv supplémentaires et tangent ne sont pas déclarés - ajoutez in vec2 uv1; vous-même.

RawShaderMaterial (WebGLRenderer uniquement)

Aucune déclaration n'est préfixée (seulement #version de glslVersion, les définitions SHADER_TYPE et SHADER_NAME, et vos defines), mais le moteur de rendu définit toujours projectionMatrix, modelViewMatrix, viewMatrix, normalMatrix, modelMatrix et cameraPosition - déclarez-les dans le shader et ne les passez jamais dans uniforms : une entrée du même nom est écrasée à chaque dessin (modelMatrix, modelViewMatrix, normalMatrix) ou remplace la valeur de la caméra (projectionMatrix, viewMatrix, cameraPosition).

const material = new THREE.RawShaderMaterial({
  glslVersion: THREE.GLSL3, // sans cela, le shader est GLSL ES 1.00, qui n'a pas texture()
  vertexShader: `
    precision 

…

[remplacé pour la traduction]

Individual skills in this repo

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

Skills associés