Materiais Three.js
Alvo: three.js r186. Os exemplos usam WebGLRenderer; a seção WebGPU e TSL usa WebGPURenderer.
Substituição local (adicionado em 2026-11-10 por Claude para este PC; não faz parte da skill original). Nosso pipeline de animações curtas (
<ROOT>\studio, do mromidev/claude-animated-shorts) está fixado em three 0.175 (r175)
- Remotion 4.0.290 + @react-three/fiber 9.1.2 + pmndrs postprocessing 6.37.2. Mantenha o three fixado: shade.ts/cardshade.ts corrigem partes de shaders do three. Ao trabalhar nesse pipeline:
- Ignore "Erros Comuns" / conselhos de API que necessitem de r176+ (HDRLoader, Timer, PCFSoftShadowMap deprecation, setEffects, RenderPipeline, outputBufferType, mesh.pivot, Capsule
height, TSL/WebGPU). Verifique se a API existe no r175 primeiro.- Nunca anime com useFrame, Clock, Timer, delta time, setAnimationLoop ou requestAnimationFrame. O Remotion renderiza quadro a quadro: derive cada valor de
useCurrentFrame()/ fps (emixer.setTime(frame / fps)para clipes).- Pós-processamento é o pmndrs
postprocessing, não o three/addons EffectComposer: não adicione um OutputPass (dupla codificação sRGB).- Cores cartoon: o mapeamento de tom é NEUTRAL em nosso compositor; cuidado com padrões ACES e a tonificação
tonemapping_fragment.- Para outros projetos three.js, a orientação original r186 abaixo se aplica como escrito.
Início Rápido
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);
// Material PBR - a escolha padrão para superfícies iluminadas e realistas
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)); // materiais iluminados renderizam pretos sem luzes
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);
Visão Geral dos Tipos de Material
| Material | Caso de uso | Iluminação |
|---|---|---|
| MeshBasicMaterial | Cor sem iluminação, texturas, wireframes | Nenhuma |
| MeshLambertMaterial | Superfícies difusas foscas | Difusa |
| MeshPhongMaterial | Plástico brilhante, especular barato | Difusa + especular |
| MeshStandardMaterial | Fluxo de trabalho PBR metal/rugosidade | PBR |
| MeshPhysicalMaterial | PBR com verniz, transmissão, brilho, iridescência | PBR |
| MeshToonMaterial | Sombreamento cartoon | Passos cartoon |
| MeshMatcapMaterial | Aparência iluminada incorporada em textura matcap, sem necessidade de luzes | Incorporada |
| ShadowMaterial | Superfície transparente que mostra apenas as sombras que recebe | Sombras apenas |
| PointsMaterial | Nuvens de pontos | Nenhuma |
| LineBasicMaterial / LineDashedMaterial | Linhas | Nenhuma |
| ShaderMaterial / RawShaderMaterial | GLSL personalizado, apenas WebGLRenderer | Personalizada |
Texturas de dados de cor (map, emissiveMap, specularMap, sheenColorMap, specularColorMap, matcap LDR, uma canvas ou vídeo usado como cor) precisam texture.colorSpace = THREE.SRGBColorSpace, ou as cores renderizam desbotadas. Mapas escalares (normal, bump, displacement, roughness, metalness, ao, alpha, toon gradientMap) mantêm o padrão. Carregadores HDR definem seu próprio espaço de cor.
MeshBasicMaterial
Nenhum cálculo de iluminação. Rápido, sempre visível. Suporta envMap com reflectivity (0 a 1) e combine (THREE.MultiplyOperation, THREE.MixOperation, THREE.AddOperation); specularMap (sRGB) mascara a contribuição do env-map.
const map = await new THREE.TextureLoader().loadAsync("color.jpg");
map.colorSpace = THREE.SRGBColorSpace;
const material = new THREE.MeshBasicMaterial({
color: 0xffffff, // multiplicado com o mapa
map,
transparent: true,
opacity: 0.5,
side: THREE.DoubleSide, // FrontSide (padrão), BackSide, DoubleSide
fog: true, // afetado pelo nevoeiro da cena
});
MeshLambertMaterial e MeshPhongMaterial
Lambert é apenas difuso. Phong adiciona um destaque especular; é a alternativa barata quando Standard é muito pesado.
const lambert = new THREE.MeshLambertMaterial({
color: 0x00ff00,
emissive: 0x111111, // cor de auto-iluminação
emissiveIntensity: 1,
});
const phong = new THREE.MeshPhongMaterial({
color: 0x0000ff,
specular: 0x111111, // cor do destaque
shininess: 30, // maior = destaque mais nítido
flatShading: false, // sombreamento plano vs. normais suaves
});
Ambos também suportam map, emissiveMap, specularMap (sRGB; mascara a reflexão do env-map e o destaque no Phong), normalMap, bumpMap, displacementMap, aoMap, envMap, envMapIntensity e envMapRotation.
MeshStandardMaterial (PBR)
Renderização baseada em física. Recomendado para resultados realistas.
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 vermelho, roughness verde, metalness azul; escalar: mantenha o padrão
const material = new THREE.MeshStandardMaterial({
color: 0xffffff, // multiplicado com o mapa
roughness: 1.0, // 0 = espelho, 1 = totalmente difuso; multiplicado por roughnessMap (verde)
metalness: 1.0, // 0 = dielétrico, 1 = metal; multiplicado por metalnessMap (azul), então mantenha 1 com um mapa
map,
roughnessMap: ormMap,
metalnessMap: ormMap,
normalMap: null, // detalhe da superfície; escala com normalScale (um Vector2)
aoMap: ormMap, // oclusão ambiente (vermelho); intensidade com aoMapIntensity
displacementMap: null, // deslocamento de vértices; escala com displacementScale, deslocamento com displacementBias
emissive: 0x000000,
emissiveIntensity: 1,
emissiveMap: null, // sRGB
envMap: null, // ou confie em scene.environment (veja abaixo)
fog: true,
});
lightMap (com lightMapIntensity) assa luz indireta da mesma forma que aoMap assa oclusão; um lightMap HDR ou EXR é LinearSRGBColorSpace, que os carregadores definem.
Canais UV: aoMap e lightMap leem o canal que você escolher
Toda textura com mapeamento UV amostra o atributo selecionado por texture.channel: 0 lê uv (padrão), 1 lê uv1, 2 lê uv2, 3 lê uv3. aoMap e lightMap não precisam de um segundo conjunto UV - eles amostram uv a menos que você mude channel. GLTFLoader carrega TEXCOORD_1 como uv1 e define channel por si só.
const aoMap = await new THREE.TextureLoader().loadAsync("ao.jpg"); // escalar: mantenha o padrão
const material = new THREE.MeshStandardMaterial({ aoMap }); // amostra uv: nenhum atributo extra necessário
// Alternativa para um unwrap separado (um mapa AO ou de luz assado): copie os pares u,v do seu baker para uv1
const bakedUv = new THREE.Float32BufferAttribute(mesh.geometry.attributes.position.count * 2, 2); // preenchido com zeros até você copiá-los
mesh.geometry.setAttribute("uv1", bakedUv); mesh.material = material;
aoMap.channel = 1; // este material agora amostra uv1 em vez de uv
MeshPhysicalMaterial (PBR Avançado)
Estende MeshStandardMaterial com recursos de camada e volume. Variantes de textura existem para a maioria deles: clearcoatMap, clearcoatRoughnessMap, clearcoatNormalMap, transmissionMap, thicknessMap, iridescenceMap, iridescenceThicknessMap, sheenColorMap, sheenRoughnessMap, anisotropyMap, specularIntensityMap, specularColorMap.
const material = new THREE.MeshPhysicalMaterial({
// Verniz (tinta de carro, laca)
clearcoat: 1.0, // 0 = nenhum, 1 = camada completa
clearcoatRoughness: 0.1,
// Transmissão (vidro, água) - refrata os objetos opacos e scene.background atrás
transmission: 1.0, // 0 = opaco, 1 = totalmente transmissivo
thickness: 0.5, // espessura do volume para refração
attenuationDistance: 1, // unidades do mundo; Infinity (padrão) = sem absorção
attenuationColor: new THREE.Color(0xffaa66), // luz branca fica esta cor após attenuationDistance
ior: 1.5, // índice de refração, 1 a 2.333
// Brilho (tecido, veludo)
sheen: 1.0,
sheenColor: new THREE.Color(0xffffff),
sheenRoughness: 0.5,
// Iridescência (bolhas de sabão, manchas de óleo)
iridescence: 1.0,
iridescenceIOR: 1.3,
iridescenceThicknessRange: [100, 400], // nanômetros
// Anisotropia (metal escovado); direção com anisotropyRotation
anisotropy: 1.0,
// Dispersão (vidro prismático); retrorrefletividade (sinais de trânsito, equipamentos de segurança)
dispersion: 0.0,
retroreflectivity: 0.0,
// Substituições especulares: specularIntensity, specularColor (mais seus mapas)
});
Vidro - transmissão com superfície lisa e algo atrás para refratar:
const glass = new THREE.MeshPhysicalMaterial({
color: 0xffffff,
metalness: 0,
roughness: 0,
transmission: 1,
thickness: 0.5,
ior: 1.5,
});
// transmission refrata os objetos opacos e o fundo atrás; scene.environment adiciona suas reflexões
MeshToonMaterial
Sombreamento cartoon. O mapa de gradiente são dados não coloridos - mantenha seu espaço de cor padrão.
const steps = new Uint8Array([120, 200]); // duas etapas de sombreamento
const gradientMap = new THREE.DataTexture(steps, 2, 1, THREE.RedFormat);
gradientMap.minFilter = THREE.NearestFilter; // etapas duras; LinearFilter as mescla
gradientMap.magFilter = THREE.NearestFilter;
gradientMap.needsUpdate = true;
const material = new THREE.MeshToonMaterial({ color: 0x00ff00, gradientMap });
MeshNormalMaterial e MeshDepthMaterial
// Normais codificadas como RGB - depuração e aparências ilustrativas planas
const normals = new THREE.MeshNormalMaterial({ flatShading: false, wireframe: false });
// Profundidade como escala de cinza (BasicDepthPacking, o padrão); RGBADepthPacking empacota para leitura em um shader
const depth = new THREE.MeshDepthMaterial();
PointsMaterial
Para nuvens de pontos. size está em pixels; com sizeAttenuation (padrão, apenas câmeras perspectiva) é multiplicado pela metade da altura da canvas e dividido pela profundidade do ponto no espaço de visão.
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, // escala com distância
alphaTest: 0.5, // com um map ou alphaMap: descarta fragmentos abaixo deste alfa
});
const points = new THREE.Points(geometry, material);
scene.add(points);
LineBasicMaterial e LineDashedMaterial
WebGL e WebGPU sempre desenham primitivas de linha com 1 px de largura; linewidth, linecap e linejoin afetam apenas o SVGRenderer. Para linhas grossas com WebGLRenderer use Line2 com LineGeometry e LineMaterial de three/addons/lines/ (linewidth em pixels); LineMaterial é um ShaderMaterial, então WebGPURenderer precisa de Line2 de three/addons/lines/webgpu/Line2.js, que usa 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 }); // sempre 1 px
const dashed = new THREE.LineDashedMaterial({ color: 0xffffff, dashSize: 0.5, gapSize: 0.25 });
const line = new THREE.Line(geometry, dashed);
line.computeLineDistances(); // necessário, ou a linha desenha sólida
scene.add(line);
ShaderMaterial (apenas WebGLRenderer)
GLSL personalizado com uniforms do three.js injetados para você. Ele sempre compila como GLSL ES 3.00: texture(), textureLod() e dFdx funcionam, e texture2D / gl_FragColor permanecem como aliases - deixe glslVersion não definido. ShaderMaterial, RawShaderMaterial e onBeforeCompile não têm caminho para WebGPURenderer; lá, use node materials e TSL.
const timer = new THREE.Timer();
timer.connect(document); // pausa quando a aba está oculta
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(); // primeira coisa a cada quadro, sem argumento
material.uniforms.time.value = timer.getElapsed();
renderer.render(scene, camera);
}
Declarados para você no shader: modelMatrix, modelViewMatrix, projectionMatrix, viewMatrix, normalMatrix, cameraPosition, e os atributos position, normal, uv (mais instanceMatrix em um InstancedMesh, que você aplica você mesmo: projectionMatrix * modelViewMatrix * instanceMatrix * vec4(pos, 1.0), e color com vertexColors). Os conjuntos uv extras e tangent não são declarados - adicione in vec2 uv1; você mesmo.
RawShaderMaterial (apenas WebGLRenderer)
Nenhuma declaração é prefixada (apenas #version de glslVersion, as definições SHADER_TYPE e SHADER_NAME, e seus defines), mas o renderizador ainda define projectionMatrix, modelViewMatrix, viewMatrix, normalMatrix, modelMatrix e cameraPosition - declare-os no shader e nunca os passe em uniforms: uma entrada com o mesmo nome é sobrescrita a cada desenho (modelMatrix, modelViewMatrix, normalMatrix) ou substitui o valor da câmera (projectionMatrix, viewMatrix, cameraPosition).
const material = new THREE.RawShaderMaterial({
glslVersion: THREE.GLSL3, // sem ele o shader é GLSL ES 1.00, que não tem texture()
vertexShader: `
precision highp float;
in vec3 position;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
void main() {
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
precision highp float;
out vec4 fragColor;
void main() {
fragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`,
});
Propriedades Compartilhadas
Aplicável a todos os materiais de malha (mas não PointsMaterial, LineBasicMaterial etc., a menos que observado).
| Propriedade | Tipo | Padrão | Descrição |
|---|---|---|---|
| blending | THREE.NormalBlending | NormalBlending | Modo de mesclagem. Opções: NormalBlending, AdditiveBlending, SubtractiveBlending, MultiplyBlending, CustomBlending (com blendSrc, blendDst, blendEquation, blendSrcAlpha, blendDstAlpha, blendEquationAlpha). |
| stencilWrite | boolean | false | Habilita operações de estêncil. |
| stencilFunc | THREE.AlwaysStencilFunc | AlwaysStencilFunc | Função de teste de estêncil: NeverStencilFunc, LessStencilFunc, EqualStencilFunc, LessEqualStencilFunc, GreaterStencilFunc, NotEqualStencilFunc, GreaterEqualStencilFunc, AlwaysStencilFunc. |
| stencilRef | number | 0 | Valor de referência para o teste de estêncil. |
| stencilFail | THREE.ReplaceStencilOp | KeepStencilOp | Operação quando o teste de estêncil falha: KeepStencilOp, ZeroStencilOp, ReplaceStencilOp, IncrementStencilOp, DecrementStencilOp, IncrementWrapStencilOp, DecrementWrapStencilOp, InvertStencilOp. |
| stencilZFail | THREE.ReplaceStencilOp | KeepStencilOp | Operação quando o teste de estêncil passa, mas o teste de profundidade falha. |
| stencilZPass | THREE.ReplaceStencilOp | KeepStencilOp | Operação quando o teste de estêncil e o teste de profundidade passam. |
| polygonOffset | boolean | false | Habilita deslocamento de profundidade baseado em polígono (resolve z-fighting). |
| polygonOffsetFactor, polygonOffsetUnits | number | 0 | Fator e unidades para polygonOffset. |
| premultipliedAlpha | boolean | false | Assumir alfa pré-multiplicado nas entradas de cor (texturas, vértices). |
| forceSinglePass | boolean | false | Força renderização de um único passe mesmo em configurações multiview. |
| toneMapped | boolean | true | Se o material deve ser submetido ao mapeamento de tom da cena. |
PointsMaterial suporta blending e transparent, mas não estêncil, polygonOffset ou toneMapped. LineBasicMaterial suporta os mesmos que PointsMaterial.
Mesclagem Personalizada
const material = new THREE.MeshStandardMaterial({
blending: THREE.CustomBlending,
blendSrc: THREE.SrcAlphaFactor,
blendDst: THREE.OneMinusSrcAlphaFactor,
blendEquation: THREE.AddEquation,
blendSrcAlpha: THREE.SrcAlphaFactor,
blendDstAlpha: THREE.OneMinusSrcAlphaFactor,
blendEquationAlpha: THREE.AddEquation,
});
Ambiente: scene.environment, envMap e envMapIntensity
Um envMap usado em um material substitui a configuração de ambiente da cena (scene.environment) para aquele material. scene.environment é um HDR (carregado com RGBELoader ou EXRLoader) ou LDR (carregado com TextureLoader, mas lembre-se de converter para LinearSRGBColorSpace) que é aplicado como envMap a todos os materiais da cena que não têm um envMap explícito. Com um envMap explícito, envMapIntensity escala sua contribuição (padrão: 1). Sem um envMap, envMapIntensity não faz nada. scene.environment usa envMapIntensity do material, se definido, senão 1.
import { RGBELoader } from "three/addons/loaders/RGBELoader.js";
const envMap = await new RGBELoader().loadAsync("venice_sunset_1k.hdr"); // HDR: já LinearSRGBColorSpace
scene.environment = envMap;
// Ou defina um envMap específico do material com envMapIntensity
const material = new THREE.MeshStandardMaterial({ envMap, envMapIntensity: 0.5 });
Erros Comuns
Luzes faltando. MeshStandardMaterial, MeshPhysicalMaterial e outros materiais iluminados renderizam pretos sem uma ou mais luzes na cena não sombreadas. HemisphericLight, DirectionalLight, PointLight, SpotLight ou RectAreaLight (o último requer área de luz e não suporta sombras). AmbientLight e LightProbe fornecem iluminação indireta, mas não produzem realces ou sombras. Materiais não iluminados (MeshBasicMaterial, PointsMaterial, LineBasicMaterial, MeshNormalMaterial, MeshDepthMaterial) sempre são visíveis sem luzes.
Texturas sem espaço de cor. Texturas que contêm dados de cor (map, emissiveMap, specularMap, sheenColorMap, specularColorMap) precisam texture.colorSpace = THREE.SRGBColorSpace; o padrão é THREE.LinearSRGBColorSpace, que as torna mais escuras. Mapas de dados não coloridos (normal, bump, displacement, roughness, metalness, ao, alpha, gradientMap) devem manter o padrão.
Mapas ORM com canais que são definidos como 1 por padrão. glTF armazena oclusão ambiente, rugosidade e metalicidade nos canais vermelho, verde e azul de uma única textura (ORM). Como metalness e roughness padrão são 1, se você definir metalnessMap: ormMap mas metalnessTudo em 1, as áreas onde o canal azul não está definido (texturas RGB genéricas frequentemente são brancas no canal B) serão metálicas - defina metalness: 1, roughness: 1 com seus mapas para que os valores do mapa substituam.
envMap sem envMapIntensity. Sem um envMap ou scene.environment, definir envMapIntensity não faz nada. Com um envMap, envMapIntensity escala sua contribuição. O padrão de envMapIntensity é 1 em todos os materiais compatíveis.
LineBasicMaterial e largura de linha. WebGL e WebGPU não suportam largura de linha > 1. Para linhas grossas, use Line2 de three/addons/lines/.
ShaderMaterial não funciona no WebGPURenderer. ShaderMaterial, RawShaderMaterial e onBeforeCompile são apenas WebGLRenderer. Para WebGPU, use NodeMaterial e TSL.
NodeMaterial e TSL (WebGPURenderer)
TSL (Three.js Shader Language) é um DSL de nó para construir materiais que são compilados nativamente para WebGPU e WebGL. Use-o com WebGPURenderer. Ele é o caminho de material de primeira classe para WebGPU.
import { WebGPURenderer } from "three/addons/renderers/webgpu/WebGPURenderer.js";
import {
color, // construtor de nó de cor: color(0xff0000) ou color("red")
texture, // carga de textura: texture(loader.load("tex.jpg"))
uv, // coordenadas UV: uv() ou uv(1) para uv1
vec3, // nó vec3: vec3(1, 2, 3)
add, mul, sin, time, // operações e time
MeshBasicNodeMaterial, // equivalentes de material para WebGPU
} from "three/tsl";
const material = new MeshBasicNodeMaterial();
material.colorNode = add(uv(), time.mul(0.1)); // UV animado como cor
const material2 = new MeshStandardNodeMaterial();
material2.colorNode = texture(carregador.load("color.jpg"));
material2.roughnessNode = 0.5; // número como nó
const material3 = new MeshPhysicalNodeMaterial();
material3.iridescenceNode = 1;
material3.iridescenceIORNode = 1.3;
material3.iridescenceThicknessNode = vec3(100, 400); // intervalo
const material4 = new MeshToonNodeMaterial();
material4.colorNode = color(0x00ff00);
// gradientMap não é um nó; defina a propriedade gradientMap diretamente
// material4.gradientMap = stepsTexture;
Para começar, substitua as classes de material por suas contrapartes Node (MeshBasicNodeMaterial, MeshStandardNodeMaterial etc.) e substitua a string de propriedades passadas como primitivas ou nós. O WebGPURenderer também suporta materiais legados (MeshStandardMaterial etc.) através de uma compilação de nó automaticamente, mas o NodeMaterial lhe dá acesso total a TSL para shaders personalizados sem a penalidade de desempenho de conversão de ShaderMaterial.
ShaderMaterial e RawShaderMaterial não têm um caminho em tempo de execução WebGPU - o material não renderizará. Use NodeMaterial e TSL para customizações de shader ao escolher como alvo o WebGPU.