Materiais no Three.js: Entendendo Tipos e Propriedades Essenciais

Visão Geral dos Materiais no Three.js

No Three.js, os materiais podem ser classificados em duas categorias principais:

  • Materiais Simples: Não respondem à iluminação da cena
  • Materiais Físicos (PBR): Simulam interações realistas com a luz, apresentando variações visuais conforme a iluminação

Para prototipagem rápida, MeshNormalMaterial é uma excelente escolha por ser leve e oferecer percepção imediata da geometria. Em produção, MeshStandardMaterial é recomendado para resultados fotorealistas, especialmente quando combinado com environment maps para capturar reflexões do entorno.

MeshBasicMaterial — O Material Básico

Este material ignora completamente a iluminação da cena. Seus atributos principais incluem:

  • color: Cor uniforme da superfície
  • wireframe: Exibe apenas a estrutura de arestas
  • opacity e transparent: Controlam transparência
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const cena = new THREE.Scene();

const perspectiva = new THREE.PerspectiveCamera(
  50,
  window.innerWidth / window.innerHeight,
  0.1,
  100
);
perspectiva.position.set(2, 2, 6);

const geometriaCaixa = new THREE.BoxGeometry(1.8, 1.8, 1.8);
const materialBasico = new THREE.MeshBasicMaterial({
  color: 0x2196f3,
  wireframe: false
});
const caixa = new THREE.Mesh(geometriaCaixa, materialBasico);
cena.add(caixa);

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

const orbitControls = new OrbitControls(perspectiva, renderizador.domElement);
orbitControls.enableDamping = true;

function cicloRenderizacao() {
  caixa.rotation.y += 0.005;
  orbitControls.update();
  renderizador.render(cena, perspectiva);
  requestAnimationFrame(cicloRenderizacao);
}
cicloRenderizacao();

window.addEventListener('resize', () => {
  perspectiva.aspect = window.innerWidth / window.innerHeight;
  perspectiva.updateProjectionMatrix();
  renderizador.setSize(window.innerWidth, window.innerHeight);
});

Trabalhando com o Objeto Color

O Three.js armazena cores no intervalo [0, 1] como ponto flutuante. Quando atribuímos um valor hexadecimal, internamente o framework realiza a normalização:

// Conversão simplificada de hexadecimal para RGB normalizado
const hexValue = 0x2196f3;

const componenteR = ((hexValue >> 16) & 0xff) / 255;  // 0.129
const componenteG = ((hexValue >> 8) & 0xff) / 255;   // 0.588
const componenteB = (hexValue & 0xff) / 255;           // 0.953

Isso significa que ao manipular propriedaeds de cor via código, você pode tanto usar hexadecimal quanto componentes RGB em ponto flutuante diretamente:

// Ambas as formas são equivalentes
materialBasico.color.set(0xff5722);
materialBasico.color.setRGB(1.0, 0.34, 0.13);

MeshNormalMaterial — Visualização de Normais

O MeshNormalMaterial utiliza os vetores normais de cada superfície como valores de cor. Como normais são vetores tridimensionais com componentes x, y, z no intervalo [0, 1], cada componente é mapeada diretamante para os canais R, G e B.

Isso produz uma coloração arco-íris intuitiva que revela a orientação de cada face, sendo extremamente útil para debugging de geometrias.

import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const cena = new THREE.Scene();

const perspectiva = new THREE.PerspectiveCamera(
  50,
  window.innerWidth / window.innerHeight,
  0.1,
  100
);
perspectiva.position.set(3, 3, 5);

const geoEsfera = new THREE.SphereGeometry(1.5, 64, 64);
const matNormais = new THREE.MeshNormalMaterial({
  flatShading: false
});
const esfera = new THREE.Mesh(geoEsfera, matNormais);
cena.add(esfera);

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

const controles = new OrbitControls(perspectiva, renderizador.domElement);

function animacao() {
  esfera.rotation.x += 0.003;
  esfera.rotation.z += 0.003;
  controles.update();
  renderizador.render(cena, perspectiva);
  requestAnimationFrame(animacao);
}
animacao();

window.addEventListener('resize', () => {
  perspectiva.aspect = window.innerWidth / window.innerHeight;
  perspectiva.updateProjectionMatrix();
  renderizador.setSize(window.innerWidth, window.innerHeight);
});

Materiais PBR — Simulação de Iluminação Física

Os materiais PBR (Physically Based Rendering) simulam como a luz interage com superfícies reais. Dois modelos clássicos merecem destaque:

  • MeshLambertMaterial: Calcula reflexão difusa (lambertiana), ideal para superfícies opacas como madeira, concreto e tecidos
  • MeshPhongMaterial: Adiciona reflexão especular, perfeito para superfícies brilhantes como metal polido e plástico

Indispensável: Fontes de Luz

Diferentemente do material básico, os materiais PBR requerem fontes de luz na cena. Sem iluminação, os objetos aparecem completamente pretos.

// Iluminação uniforme — sem sombras, apenas preenche a cena
const luzAmbiente = new THREE.AmbientLight(0xffffff, 0.4);
cena.add(luzAmbiente);

// Luz pontual — emite radiação em todas as direções a partir de um ponto
const luzPonto = new THREE.PointLight(0xffffff, 80);
luzPonto.position.set(5, 8, 5);
cena.add(luzPonto);

Exemplo: Construindo uma Árvore Estilizada

Para demonstrar ambos os materiais, vamos criar uma composição simples de árvore usando um cone (copa) e um cilindro (tronco).

import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const cena = new THREE.Scene();
cena.background = new THREE.Color(0x87ceeb);

const cam = new THREE.PerspectiveCamera(
  50,
  window.innerWidth / window.innerHeight,
  0.1,
  200
);
cam.position.set(8, 6, 10);

// ── Copa da árvore (Lambert) ──
const geoCopa = new THREE.ConeGeometry(2.5, 6, 24);
const matCopa = new THREE.MeshLambertMaterial({ color: 0x2e7d32 });
const copa = new THREE.Mesh(geoCopa, matCopa);
copa.position.y = 6;

// ── Tronco da árvore (Phong) ──
const geoTronco = new THREE.CylinderGeometry(0.6, 0.8, 4, 16);
const matTronco = new THREE.MeshPhongMaterial({
  color: 0x6d4c41,
  shininess: 15
});
const tronco = new THREE.Mesh(geoTronco, matTronco);
tronco.position.y = 2;

// ── Agrupamento ──
const arvore = new THREE.Group();
arvore.add(copa);
arvore.add(tronco);
cena.add(arvore);

// ── Plano do chão ──
const geoPlano = new THREE.PlaneGeometry(40, 40);
const matPlano = new THREE.MeshLambertMaterial({ color: 0x4caf50 });
const plano = new THREE.Mesh(geoPlano, matPlano);
plano.rotation.x = -Math.PI / 2;
cena.add(plano);

// ── Iluminação ──
const solAmbiente = new THREE.AmbientLight(0xffffff, 0.3);
cena.add(solAmbiente);

const solPonto = new THREE.PointLight(0xfff8e1, 120);
solPonto.position.set(10, 15, 10);
cena.add(solPonto);

// ── Renderização ──
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);

const orbita = new OrbitControls(cam, renderer.domElement);
orbita.target.set(0, 3, 0);
orbita.update();

function loop() {
  orbita.update();
  renderer.render(cena, cam);
  requestAnimationFrame(loop);
}
loop();

window.addEventListener('resize', () => {
  cam.aspect = window.innerWidth / window.innerHeight;
  cam.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
});

Comparação Visual

Ao observar a cena acima, note que o tronco com material MeshPhongMaterial exibe um brilho especular sutil na superfície, enquanto a copa com MeshLambertMaterial apresenta apenas difusão suave. Ajuste o parâmetro shininess do material Phong para controlar a intensidade do reflexo especular — valores maiores produzem realces menores e mais concentrados.

Tags: three.js materiais MeshBasicMaterial MeshNormalMaterial MeshLambertMaterial

Publicado em 6-3 02:51 por Thomas