Standard y Physical: los dos materiales PBR
Qué hace MeshStandardMaterial que Phong no puede hacer, en qué se diferencia MeshPhysicalMaterial, y por qué los dos necesitan un envMap para verse bien.
MeshStandardMaterial es el material que deberías usar por defecto en 2026, y MeshPhysicalMaterial es el mismo material con seis capas opcionales encima. La diferencia con Phong no es que sean “más bonitos”: es que su modelo de reflexión respeta la conservación de energía y separa el comportamiento de metales y dieléctricos, lo que significa que un material configurado una vez se comporta correctamente bajo cualquier iluminación en lugar de haber sido ajustado a ojo para una escena concreta.
- Enumerar los parámetros que definen un
MeshStandardMaterialy qué controla cada uno. - Explicar la relación de herencia entre
MeshPhysicalMaterialyMeshStandardMaterial. - Justificar por qué un material PBR sin mapa de entorno se ve peor que un Phong.
- Medir el coste relativo de las capas del material físico y activarlas solo cuando aportan.
Standard: cinco números y una imagen
Todo MeshStandardMaterial se reduce a un puñado de parámetros escalares que puedes sustituir por texturas:
| propiedad | rango | qué controla |
|---|---|---|
color |
color | el albedo, el color base de la superficie |
roughness |
0 a 1 | cuánto se dispersa la reflexión; 0 espejo, 1 mate |
metalness |
0 a 1 | si la superficie es conductora; en la práctica 0 o 1 |
emissive |
color | luz que emite la superficie, sin iluminarla |
envMap |
textura | el entorno que se refleja |
envMapIntensity |
número | cuánto pesa ese entorno |
Los valores por defecto son roughness: 1 y metalness: 0, es decir, un dieléctrico completamente mate. Ese material sin luces se ve negro, y sin envMap se ve plano. Ninguna de las dos cosas es un fallo del material.
MeshStandardMaterial sombrea por fragmento, calcula el término difuso y el especular con una BRDF de microfacetas, y usa el mapa de entorno tanto para la reflexión especular como para la luz ambiental difusa. Ese último punto es el que decide si tu escena parece de 2005 o de ahora: la iluminación indirecta de un PBR viene entera del entorno, y sin entorno las zonas en sombra son negro puro.
import * as THREE from 'three';
import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.toneMapping = THREE.ACESFilmicToneMapping;
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x11111b);
// Entorno procedural: una habitacion con focos. Sin fichero externo.
const pmrem = new THREE.PMREMGenerator(renderer);
const habitacion = new RoomEnvironment();
scene.environment = pmrem.fromScene(habitacion, 0.04).texture;
habitacion.dispose();
const camera = new THREE.PerspectiveCamera(
45, window.innerWidth / window.innerHeight, 0.1, 100
);
camera.position.set(0, 0, 6);
const geometria = new THREE.SphereGeometry(0.7, 64, 32);
// Una rejilla: metalness en filas, roughness en columnas.
for (let fila = 0; fila < 2; fila++) {
for (let col = 0; col < 5; col++) {
const material = new THREE.MeshStandardMaterial({
color: 0xd4af37,
metalness: fila,
roughness: col / 4
});
const esfera = new THREE.Mesh(geometria, material);
esfera.position.set((col - 2) * 1.6, fila === 0 ? 0.9 : -0.9, 0);
scene.add(esfera);
}
}
renderer.setAnimationLoop(() => renderer.render(scene, camera));
Esa rejilla es la referencia visual que conviene tener a mano. La fila de metales cambia de color a lo largo de la rugosidad porque el color del metal está en su reflexión; la fila de dieléctricos mantiene el color base y solo cambia el brillo. Si entiendes esa diferencia, entiendes el modelo entero.
material.envMap aplica el entorno a ese material concreto. scene.environment lo aplica a todos los materiales de la escena que no tengan uno propio, sin tocar el fondo. scene.background solo cambia lo que se ve detrás, sin iluminar nada. Los tres son independientes y se combinan; el error clásico es poner un HDRI de fondo y preguntarse por qué los objetos no reflejan nada.
Physical: el mismo material con capas
MeshPhysicalMaterial extiende MeshStandardMaterial. No es un material alternativo: es el mismo, con propiedades adicionales que por defecto están apagadas. Un MeshPhysicalMaterial recién creado, sin tocar nada, produce exactamente el mismo píxel que un MeshStandardMaterial equivalente, y casi el mismo coste, porque las capas se compilan condicionalmente.
Lo que añade, en una frase cada uno:
clearcoat: una segunda capa especular fina encima, como una laca.transmission: transparencia refractiva de verdad, conthicknesseior.sheen: un lóbulo de retrodispersión en los bordes, para tejidos.iridescence: interferencia de película fina, el arcoíris de una pompa.anisotropy: reflexión estirada en una dirección, metal cepillado.specularIntensityyspecularColor: control fino del especular de los dieléctricos.dispersion: separación cromática al refractar, contransmission.
Cada una tiene su propia lección en el nivel siguiente. Aquí lo que importa es el criterio de cuándo saltar de Standard a Physical, y es sorprendentemente simple: cuando el material que quieres tiene dos superficies. Un coche pintado es pintura más barniz. Una pompa es jabón más aire. Un jersey es fibra más pelusa. Un vaso es cristal más interior. Si tu material tiene una sola superficie, Standard le basta.
El defines de MeshPhysicalMaterial incluye siempre STANDARD y PHYSICAL, así que el shader que se compila no es el de Standard aunque no actives ninguna capa. Y hay un detalle de arquitectura que muerde: los setters de clearcoat, transmission, sheen, iridescence, anisotropy y dispersion incrementan material.version solo cuando el valor cruza el cero. Es decir, animar clearcoat de 0.3 a 0.8 es gratis, pero animarlo de 0 a 0.1 fuerza una recompilación del shader en ese fotograma, con su tirón correspondiente. Si vas a animar una capa desde apagada, arráncala en un valor mínimo distinto de cero, por ejemplo 0.001, y anima desde ahí. El mismo patrón está en alphaTest de la clase base: pasar de 0 a cualquier valor positivo recompila.
El coste, con orden
De más barato a más caro por píxel, para un mismo número de luces:
MeshBasicMaterial: no ilumina, es una multiplicación.MeshLambertMaterial: un producto escalar por luz.MeshToonMaterial: lo mismo más una búsqueda en el gradiente.MeshPhongMaterial: añade un lóbulo especular por luz.MeshStandardMaterial: BRDF de microfacetas, Fresnel, y muestreo del entorno prefiltrado.MeshPhysicalMaterial: lo anterior más una BRDF por cada capa activa.
Los saltos no son uniformes. De Lambert a Phong hay poco. De Phong a Standard hay bastante, sobre todo por el muestreo del entorno. De Standard a Physical depende por completo de qué actives: clearcoat añade un lóbulo especular más y una normal más; transmission es el caso grave, porque obliga al renderer a hacer una copia de la escena a un render target para poder muestrear lo que hay detrás del objeto, lo que significa dibujar la escena dos veces.
Si estás optimizando y ves que el fragment shader es el cuello, la primera pregunta es cuántos materiales Physical hay en pantalla y cuántos de ellos tienen transmission activo. La segunda es si esas mismas superficies se distinguirían de un Standard bien parametrizado en un vídeo a treinta fotogramas por segundo. La respuesta honesta suele ser que no.
Duplica la rejilla de esferas con MeshPhysicalMaterial en lugar de MeshStandardMaterial, todas con las capas apagadas, y comprueba con el panel de rendimiento que el coste es prácticamente idéntico. Después activa clearcoat: 1 en una sola fila y vuelve a medir. Anota el porcentaje de subida: te servirá de referencia para el resto del track.