Saltar al contenido

sheen: por qué un tejido no es un MeshStandardMaterial

El lóbulo de retrodispersión que produce el halo de los bordes en terciopelo y satén, la distribución de Charlie, y el valor por defecto que hace que sheen parezca no funcionar.

Retrodispersión, no reflexión especular

Un tejido de fibras, como el terciopelo, el ante o el satén, no tiene una superficie en el sentido de una plancha con rugosidad. Tiene un bosque de fibras más o menos perpendiculares a la tela. Cuando la luz llega, rebota entre esas fibras varias veces y sale preferentemente hacia atrás, en dirección a la fuente, y también hacia los lados en incidencia rasante.

El efecto visible es un halo claro en la silueta del objeto, justo donde una BRDF de microfacetas produciría lo contrario. Es lo que hace que un sofá de terciopelo tenga los bordes de los cojines más claros que su centro, y por qué una tela así cambia de aspecto según en qué dirección la pases la mano.

Three.js lo implementa con una distribución específica llamada Charlie, de Estévez y Kulla, y una función de visibilidad de Neubelt pensada para el mismo caso. En el shader son D_Charlie y V_Neubelt, y la BRDF que las combina es BRDF_Sheen. Es un lóbulo aparte que se suma al material base; no lo sustituye.

Los tres parámetros y la trampa del defecto

sheen es la intensidad de la capa, de cero a uno. sheenColor es su tinte. sheenRoughness controla la anchura del halo.

La trampa está aquí:

JS
this.sheenColor = new Color( 0x000000 );   // negrothis.sheenRoughness = 1.0;this.sheen = 0;

sheenColor vale negro por defecto. El shader multiplica el lóbulo por ese color, así que poner sheen: 1 sin tocar nada más da exactamente cero de contribución. El material se recompila, pagas el coste, y no se ve absolutamente nada. Es la razón por la que medio internet cree que sheen no funciona.

La configuración mínima que sí hace algo:

JS
import * as THREE from 'three';// Terciopelo rojo: base oscura y saturada, halo claro y calido.const terciopelo = new THREE.MeshPhysicalMaterial({  color: 0x6a0f1a,  roughness: 0.9,  metalness: 0,  sheen: 1.0,  sheenColor: new THREE.Color(0xd98a7a),  sheenRoughness: 0.25});// Saten: base mas clara, halo mas estrecho y mas brillante.const saten = new THREE.MeshPhysicalMaterial({  color: 0x2a3f66,  roughness: 0.55,  metalness: 0,  sheen: 1.0,  sheenColor: new THREE.Color(0xbfd0ff),  sheenRoughness: 0.1});

La receta que funciona casi siempre: base con roughness alto y color saturado, sheenColor claro y desaturado, sheenRoughness bajo. Un sheenRoughness alto ensancha tanto el lóbulo que deja de leerse como halo y se convierte en una subida general del brillo, que es indistinguible de haber aclarado el color base.

Los dos mapas asociados tienen canales distintos y conviene no confundirlos: sheenColorMap usa los canales RGB, y sheenRoughnessMap usa el canal alfa. Ese alfa no es un descuido, permite empaquetar el color y la rugosidad del sheen en una sola textura RGBA.

Qué tejidos lo necesitan

No todos. La pregunta discriminante es si el tejido tiene pelo o brillo direccional.

Lo necesitan: terciopelo, ante, pana, felpa, satén, seda, algunos tafetanes, y cualquier tela con fibra levantada. También, fuera del mundo textil, el polvo fino sobre una superficie y la pelusa de una fruta.

No lo necesitan: algodón mate, lino, lona, fieltro, denim. Todos esos son superficies rugosas normales y un MeshStandardMaterial con roughness alto y un buen normalMap de trama los resuelve mejor y más barato. Añadirles sheen los hace parecer sintéticos.

El coste

sheen añade un lóbulo por luz directa, un término indirecto propio, y tres evaluaciones de IBLSheenBRDF, que es un ajuste polinómico con una exponencial. Es más caro que clearcoat en cuanto hay varias luces, porque el lóbulo de sheen se evalúa por luz igual que el principal, y encima la compensación de energía se calcula por luz también.

Como referencia práctica, sobre un MeshStandardMaterial con dos luces y entorno, activar sheen sube el coste del fragmento en torno a un cuarenta por ciento. Sigue siendo mucho más barato que transmission, que no compite en la misma liga.

La decisión razonable: sheen en el material protagonista, un sofá, una cortina, una prenda en primer plano; y MeshStandardMaterial con normalMap de trama para todo lo demás. En una escena de interior con quince objetos textiles, poner sheen en los quince es tirar rendimiento en superficies que ocupan cien píxeles.