MeshPhongMaterial fija el modelo; evaluarlo por fragmento es el algoritmo. Dos decisiones, una sola línea de API.
0 · Antes de empezar
El pipeline: dónde se calcula la luz
Renderizar es generar una imagen 2D a partir de una descripción 3D. Son cuatro problemas distintos, no uno.
1 · Qué hace la luz cuando toca una superficie
Luz y superficies
Un fotón que llega a una interfaz tiene exactamente tres destinos posibles.
Lo que decide el balance
La proporción entre los tres depende del material y del ángulo de
incidencia. Esa dependencia angular tiene nombre —efecto Fresnel— y se
ve en la slide 08.
1 · Qué hace la luz cuando toca una superficie
Iluminación local vs. global
Iluminación local
diffuse_bounces = 0Lo que no recibe luz directa queda negro.
Iluminación global
diffuse_bounces = 8Aparecen inter-reflexiones y sangrado de color.
Lo que Phong no calcula
Phong y Blinn-Phong no pueden calcular inter-reflexiones: las sustituyen
por una constante, el término ambiente.
El costo de los rebotes
En local, cada punto se calcula sólo con las fuentes. En global depende
de toda la escena: si cada rebote abriera $n$ rayos, $k$ rebotes serían
$n^k$ rayos por píxel. El costo crece exponencialmente.
Sangrado de color
Una superficie iluminada rebota luz teñida de su propio color. En la
imagen de la derecha, el costado izquierdo de la caja alta sale rojizo y
el derecho de la caja baja, verdoso.
1 · Qué hace la luz cuando toca una superficie
Reflexión especular y difusa
No son dos fenómenos distintos: son el mismo fenómeno a dos escalas de rugosidad.
Las dos se unifican
La BRDF describe las dos con una sola función: cuánta luz que entra por
una dirección sale por otra. Especular y difusa son dos formas de esa
función.
1 · Qué hace la luz cuando toca una superficie
Refracción: la ley de Snell
Lo que no se refleja, entra. Y al entrar, cambia de dirección.
\[n_1 \sin\theta_1 = n_2 \sin\theta_2\]
$n$ es el índice de refracción del medio: vacío 1.00 · aire 1.0003 · agua 1.33 · vidrio 1.52 · diamante 2.42.
Al pasar a un medio más denso ($n_2 > n_1$) el rayo se acerca a la normal.
Por encima de un ángulo crítico no hay transmisión: reflexión total interna.
Un dato para la clase
Hughes registra que la ley de refracción ya era conocida por Ibn Sahl de
Bagdad hacia 984 d.C., seis siglos y medio antes de Snell. El nombre es
una convención, no un crédito.
Phong no modela nada de esto. La refracción no aparece en este capítulo:
requiere trazar el rayo dentro del objeto, que es un algoritmo de
iluminación global.
1 · Qué hace la luz cuando toca una superficie
El efecto Fresnel
El reparto entre reflexión y transmisión no es una constante del material: depende del ángulo.
\[F(\theta) = R_0 + (1 - R_0)(1 - \cos\theta)^5\]
Dieléctricos (plástico, vidrio, agua): $R_0 \approx 0.04$. Casi todo entra.
Conductores (metales): $R_0 \approx 0.5$ a $1.0$, y coloreado por el metal.
Phong tampoco modela esto
En Phong, $k_s$ es una constante: el brillo no cambia con el ángulo de
vista. Por eso un piso de madera renderizado con Phong nunca tiene ese
reflejo alargado que sí se ve en el mundo real cuando mirás casi de canto.
1 · Qué hace la luz cuando toca una superficie
Iluminación global: calcular los rebotes
La luz que llega a una superficie no viene solo de las fuentes: viene de todo lo demás.
Cada superficie iluminada ilumina a su vez a las demás, así que la luz que
sale de un punto depende de la que sale de todos los otros. Eso es la
ecuación de rendering (Kajiya, 1986). Su solución es una suma de
rebotes: la luz directa, más la de un rebote, más la de dos… Cada término
aporta menos que el anterior, porque en cada rebote se absorbe una parte.
Radiosidad: divide la escena en parches y resuelve un sistema lineal, un valor por parche. Sólo superficies difusas; el resultado sirve para cualquier punto de vista.
Path tracing: desde la cámara, sigue un solo camino aleatorio por muestra y promedia muchos. Es lento y tiene ruido, pero converge a la solución correcta. Es lo que usa Cycles.
Photon mapping: primero dispara fotones desde las luces y guarda dónde caen; después estima la luz en cada punto con los fotones cercanos.
1 · Qué hace la luz cuando toca una superficie
Medios participativos
Hasta acá supusimos que entre los objetos hay vacío. No lo hay.
\[I(d) = I_0 \, e^{-\sigma d}\]
Niebla, humo, polvo, agua: la luz se absorbe y se dispersa en el camino, no solo en las superficies.
Ley de Beer-Lambert: la intensidad decae exponencialmente con la distancia recorrida.
$\sigma$ es el coeficiente de extinción del medio.
Scene.fog y FogExp2 implementan exactamente esto. FogExp2 es la
forma exponencial de la fórmula de arriba; Fog a secas es una
interpolación lineal más barata y menos física.
1 · Qué hace la luz cuando toca una superficie
Dispersión subsuperficial
En algunos materiales, la luz entra, se pierde adentro, y sale por otro lado.
Piel, cera, mármol, leche, hojas, jade: la luz penetra la superficie.
Adentro rebota muchas veces contra partículas microscópicas.
Sale por un punto $P_o$ distinto del de entrada $P_i$, milímetros más allá.
Por eso una mano contra una linterna se ve roja: la luz atravesó el tejido.
Rompe el supuesto de la BSDF
Toda la maquinaria de BRDF y BTDF asume $P_i = P_o$. Acá eso es falso, y
no es un detalle: hace falta una función distinta, la BSSRDF, que toma
los dos puntos como argumentos. Lo vemos en la slide siguiente.
BRDF — Bidirectional Reflectance Distribution Function: la luz que sale por el hemisferio de reflexión.
BTDF — Transmittance: la luz que sale por el hemisferio de transmisión.
Responde una sola pregunta: de la luz que entra por $\omega_i$, ¿cuánta sale por $\omega_o$?
Dónde deja de alcanzar
Supone que la luz entra y sale en el mismo punto P. En piel o mármol
entra en $P_i$ y sale más allá, en $P_o$: ahí hace falta la BSSRDF.
Dónde entra Phong
Phong es una BRDF concreta; Cook-Torrance es otra. La BRDF es la
categoría, no un modelo.
2 · Las simplificaciones del tiempo real
Tres simplificaciones para llegar a 60 fps
Acá se termina la física y empieza la ingeniería. Todo lo que sigue es deliberadamente falso.
2 · Las simplificaciones del tiempo real
RGB: física contra percepción
La luz no viene en tres colores. Nosotros sí la vemos en tres.
En la naturaleza la luz es una distribución espectral continua $P(\lambda)$.
La retina tiene tres tipos de cono: S (~420 nm), M (~534 nm), L (~564 nm).
RGB no es una propiedad de la luz: es una aproximación a cómo la muestrea el ojo humano (teoría triestímulo).
El malentendido frecuente
Decir «se computan las frecuencias roja, verde y azul» sugiere que la luz
tiene esas tres frecuencias. No las tiene: el espectro es continuo. Se
computan tres canales porque tenemos tres tipos de cono, no porque el
espectro tenga tres partes.
Qué se pierde
Con 3 canales no se puede simular dispersión cromática (el arcoíris de
un prisma) ni fluorescencia. Un motor que los necesite tiene que
renderizar espectralmente, con decenas de bandas.
3 · Fuentes de luz
Fuentes reales contra fuentes idealizadas
La misma escena, la misma potencia total. Lo único que cambia es el tamaño del emisor.
Fuente de área
emisor de 130 × 105 cmSombras con penumbra: transición gradual.
Fuente puntual
emisor de 2 × 2 cmSombras infinitamente duras.
Por qué idealizamos
Calcular la sombra de una fuente con tamaño exige integrar sobre su
superficie. Un punto reduce eso a un solo vector $\mathbf{L}$. El precio es
el borde de navaja de la columna derecha.
3 · Fuentes de luz
Luz ambiente
\[I_a = k_a \odot i_a\]
$k_a$ — coeficiente del material, RGB en $[0,1]^3$.
$i_a$ — intensidad/color de la luz ambiente.
$\odot$ — producto componente a componente: un filtro óptico.
Defecto crítico, y es el punto de la slide
Es constante en toda la superficie: un rincón cóncavo recibe lo mismo
que una cara expuesta. Justo al revés de lo que pasa en la realidad.
AmbientLight. Los motores lo reemplazan por Ambient Occlusion, que
modula esta constante según cuán ocluido está el punto.
Solo ambiente · un disco planoAmbiente + difusa · vuelve a ser una esfera
3 · Fuentes de luz
Luz hemisférica
Un paso barato: que la ambiente deje de ser una constante.
Cuesta un producto escalar más que la ambiente y ya devuelve información de forma.
Misma esfera, misma cámara, misma intensidad total: toda la diferencia la
hace un producto escalar, N·Up. En Three.js es
HemisphereLight(skyColor, groundColor, intensity).
skyColor#6FB3FF
groundColor#8A5A2B
HemisphereLightAmbientLight
3 · Fuentes de luz
Luz direccional
El Sol, o cualquier fuente tan lejana que ya no importa dónde está.
\[p_{luz} = (x, y, z, 0)^T\]
Definida por una dirección, no por una posición.
$\mathbf{L}$ es constante para todos los puntos de la escena: se calcula una vez.
No hay atenuación: $f_{att}(d) = 1$.
En coordenadas homogéneas se distingue por la cuarta componente: $w = 0$.
DirectionalLight. Su position no es una posición: define la dirección desde la que llega la luz hacia el target.
3 · Fuentes de luz
Luz puntual y atenuación
Acá aparece la distancia, y con ella el problema más viejo del modelo.
Emite en todas las direcciones desde una posición fija. $w = 1$.
Por fragmento: $\mathbf{L} = (P_{luz} - P)/\|P_{luz} - P\|$ y $d = \|P_{luz} - P\|$.
La ley física $1/d^2$ es correcta e inservible: diverge cuando $d \to 0$. El resto —el denominador cuadrático, el $\min(1,\cdot)$— son parches encadenados sobre ese problema.
Hughes sobre el min(1, ·)
«there's no reasonable explanation for the “min” in the expression except
that “things got dark too fast otherwise”». Vale citarlo tal cual: muestra
que estas fórmulas son parches históricos, no leyes derivadas.
PointLight: decay = 2 es la ley cuadrática, decay = 0 no atenúa.
distance recorta a cero — otro parche, este por performance.
3 · Fuentes de luz
Luz spot
Una puntual a la que se le recorta el cono. Y el recorte necesita dos ángulos, no uno.
Parámetros: posición $S$, dirección $\mathbf{D}_{spot}$, y dos ángulos.
$\phi$ = innerCutoff: hasta acá, intensidad plena.
$\gamma$ = outerCutoff: de $\phi$ a $\gamma$, la intensidad cae a cero.
Con un solo ángulo el borde sería un escalón: se ve el recorte.
Por qué con cosenos y no con ángulos
$\cos\theta$ ya lo tenemos: es $-\mathbf{L}\cdot\mathbf{D}_{spot}$, un
producto escalar que la GPU hace gratis. El ángulo costaría un $\arccos$
por fragmento.
SpotLight expone angle (el externo) y penumbra ∈ [0,1]: qué fracción del cono es zona de caída.
3 · Fuentes de luz
Luz de área rectangular
La única fuente de esta lista que se parece a algo real. Y la que Phong no puede resolver.
La luz se emite desde una superficie con ancho y alto reales.
Produce penumbras auténticas, no aproximadas.
Requiere integrar la irradiancia sobre el área: $L_r = \int_A \ldots \, dA$.
En tiempo real se resuelve con LTC (Linearly Transformed Cosines) o Monte Carlo, no con Phong directo.
RectAreaLight existe en Three.js pero no proyecta sombras: el
cálculo de sombra de una fuente extensa no entra en el presupuesto de
tiempo real.
Interactiva
3 · Fuentes de luz
Probemos todas las luces
Una tetera, un piso y las seis fuentes del bloque: encendé cada una, combinalas y mové sus parámetros.
4 · El modelo de Phong
El modelo de Phong
Bui Tuong Phong, tesis doctoral 1973, publicado en ACM en 1975.
\[I = I_a + I_d + I_s\]
$I_a$ambiente: la luz que llega de toda la escena, aproximada por una constante
$I_d$difusa: la luz que se reparte igual en todas las direcciones
$I_s$especular: el brillo, que depende de dónde está la cámara
Es un modelo empírico: no se deriva de la física, se ajusta a lo que se ve.
Es un modelo local: no sabe que existen otros objetos en la escena.
Descompone la reflectancia en tres términos independientes que se suman.
Qué NO es
No conserva energía. Puede devolver más luz de la que recibe si los
coeficientes están mal elegidos. No es un defecto de implementación: el
modelo no lo pretende. La conservación estricta llega con PBR.
Por qué sobrevivió cincuenta años
Porque es barato y porque se ve bien. Tres productos escalares y una
potencia por fragmento. Hughes es duro con él —«this entire model,
especially the "ambient term", was a terrible thing»— y aun así sigue en
todos los motores.
Interactiva
4 · El modelo de Phong
Los vectores en el punto P
Cinco vectores. Todos unitarios. Todo el resto de la clase se escribe con estos.
$\mathbf{N}$ — normal a la superficie en $P$.
$\mathbf{L}$ — hacia la fuente (no desde ella: es el error de signo más común).
$\mathbf{V}$ — hacia la cámara.
$\mathbf{R}$ — reflejo de $\mathbf{L}$ respecto de $\mathbf{N}$.
$\mathbf{H}$ — bisectriz de $\mathbf{L}$ y $\mathbf{V}$. Pertenece a Blinn-Phong, se usa en la slide 30.
Si no lo están, los productos escalares dejan de ser cosenos. Shirley lo
llama «a very common error in shading computations».
4 · El modelo de Phong
Las tres componentes
Phong no es una fórmula: son tres fórmulas que se suman.
Ambiente
+
Nivel base constante. No aporta forma.
Difusa
+
Depende de la orientación respecto de la luz. Aporta el volumen.
Especular
=
Depende de dónde está la cámara. Aporta el brillo.
Total
La suma. Cada término resuelve algo que los otros no.
Por qué aditivo
La luz se suma: dos fuentes iluminando un punto dan la suma de sus
contribuciones. Esa linealidad es lo que permite estudiar el modelo
término por término.
Interactiva
4 · El modelo de Phong
Componente ambiente
El término más simple, y el que más confusión genera en la implementación.
\[I_a = k_a \odot i_a\]
$k_a \in [0,1]^3$ — reflectancia ambiental del material.
$\mathbf{N}\cdot\mathbf{L} = \cos\theta$ — porque los dos son unitarios.
Independiente de la cámara: un punto difuso se ve igual desde cualquier lado.
Modela superficies mates: papel, tiza, madera sin lustrar, piedra.
4 · El modelo de Phong
Componente difusa
Por qué el $\max(\cdot,\ 0)$ no es opcional. Pasados los 90°, el
producto escalar $\mathbf{N}\cdot\mathbf{L}$ se vuelve negativo: la luz
está detrás de la superficie. Sin el recorte, la fórmula no devuelve «nada
de luz», devuelve luz negativa, y como los términos se suman, esa cara
le resta a lo que aportan las otras fuentes y el ambiente. El
$\max(\cdot,\ 0)$ pone por escrito lo que pasa en la realidad: una cara que
no ve a la fuente no recibe nada de ella, y nada es cero.
Escribirla sin el max
En la práctica el síntoma son manchas oscuras, o iluminación que
atraviesa el objeto.
Dónde aparece en serio
Shirley aclara al margen que esto pasa sobre todo con normales
interpoladas — o sea, con Phong shading, que es el tema del bloque 7.
El bug nace acá y se manifiesta allá.
Interactiva
4 · El modelo de Phong
Componente especular
El brillo. El único término que depende de dónde estás parado.
$\mathbf{R}\cdot\mathbf{V} = \cos\phi$ — cuánto se alinea el reflejo ideal con la mirada.
$\alpha$ — exponente de brillo. Controla qué tan angosto es el lóbulo.
También lleva $\max(\cdot,0)$, por la misma razón que la difusa.
Si movés la cámara, el brillo se mueve con vos.
Interactiva
4 · El modelo de Phong
α y $k_s$: los dos ejes del brillo
α bajo (5-20): material rugoso o mate. Brillo amplio y difuso.
α alto (100-1000): material pulido. Brillo chico e intenso.
$k_s$ no cambia el tamaño del brillo: cambia cuánto se refleja.
El orden importa
Es $\max(\mathbf{R}\cdot\mathbf{V}, 0)^{\alpha}$ y no
$\max((\mathbf{R}\cdot\mathbf{V})^{\alpha}, 0)$. Con $\alpha$ par, elevar
primero convierte los negativos en positivos y aparecen brillos
en la cara oculta del objeto.
Regla de la variable única, aplicada
Las 16 se renderizan por separado, con la luz en la misma posición
relativa. Cada fila cambia solo $k_s$; cada columna, solo α.
4 · El modelo de Phong
Blinn-Phong: por qué se te movió el brillo
Phong (1975) y Blinn (1976) no son el mismo modelo, aunque los motores llamen a los dos «Phong».
Phong
\[(\mathbf{R}\cdot\mathbf{V})^{\alpha}\]
1975Hay que calcular $\mathbf{R}$ en cada fragmento.
Blinn-Phong
\[(\mathbf{N}\cdot\mathbf{H})^{\beta}\]
1976Más barato, y mejor en ángulos rasantes.
El exponente no es el mismo
$2\psi = \phi$: el ángulo de Blinn-Phong es la mitad del de Phong. Con
el mismo exponente, el brillo de Blinn-Phong sale más grande. Para un
resultado comparable hace falta $\beta \approx 2\text{–}4\,\alpha$.
Por eso al cambiar de modelo sin tocar shininess el brillo "se mueve".
constante, fuera del corchete: no depende de la fuente
$f_{att}(d)$
modula los dos términos que sí dependen de la distancia
$\max(\mathbf{N}\cdot\mathbf{L},0)$
el recorte que evita luz negativa
$\max(\mathbf{R}\cdot\mathbf{V},0)^{\alpha}$
o $(\mathbf{N}\cdot\mathbf{H})^{\beta}$ si usás Blinn‑Phong
Por qué la ambiente queda afuera del corchete
Porque no viene de ninguna fuente en particular: es el sustituto de la luz
indirecta de toda la escena. Atenuarla por la distancia a una fuente no
tendría sentido.
Lo que esta ecuación no hace
No conserva energía, no depende del ángulo de Fresnel, no sabe de
inter-reflexiones y no distingue rugosidad de brillo. Cada una de esas
cuatro cosas es el capítulo de PBR.
4 · El modelo de Phong
Múltiples fuentes · metales y dieléctricos
¿Por qué el brillo del plástico es blanco y el del oro es dorado?
La ambiente aparece una sola vez, fuera de la sumatoria.
Dieléctricos (plástico, madera, vidrio): $k_s$ es blanco. El brillo toma el color de la luz.
Conductores (metales): $k_s$ es coloreado por la reflectancia del metal, y $k_d \approx 0$.
Por qué el metal tiñe el brillo
En un dieléctrico, la luz que se refleja en la superficie no entra al
material: sale sin teñirse. En un metal, los electrones libres absorben
selectivamente según la longitud de onda, y lo que se refleja ya sale
coloreado.
Interactiva
4 · El modelo de Phong
Probemos el material de Phong
La tetera, tres luces blancas fijas y todos los coeficientes de MeshPhongMaterial, sin mapas.
Bloque 5
La superficie entra en la ecuación
Hasta acá, cada coeficiente de la ecuación era un número para todo el objeto. De acá en adelante, sale de una textura.
Flat, Gouraud y Phong shading — dónde se evalúa la fórmula que ya vimos.
Por qué hay que renormalizar la normal interpolada, y qué pasa si no.
Mapas: difuso, de reflexión (cube maps), de normales.
El sistema TBN y por qué el mapa de normales se ve violáceo.
Light maps: cómo se falsea la iluminación global de la slide 05.
5 · De Phong a la superficie
Dónde quedamos
La ecuación de la primera mitad, y las cinco constantes que ahora dejan de serlo.
Cada uno puede pasar a ser un valor por fragmento, leído de una textura.
La ecuación no cambia. Cambia de dónde salen sus números.
6 · Las normales
La normal como atributo de vértice
La normal no es una propiedad de la superficie: es un número guardado por vértice.
Cada vértice lleva posición, normal y UV en el mismo buffer.
El fragment shader no ve la malla: ve lo que la GPU interpoló entre esos números.
Por eso dos mallas idénticas pueden sombrearse distinto: lo que cambia son los atributos.
En Three.js
BufferGeometry guarda cada atributo en su propio BufferAttribute:
position, normal, uv. computeVertexNormals() rellena normal
promediando las caras vecinas.
6 · Las normales
¿En qué espacio se calcula la iluminación?
Objeto → mundo → vista: tres sistemas de coordenadas encadenados.
$\mathbf{N}\cdot\mathbf{L}$ sólo tiene sentido si los dos están en el mismo.
Convención del curso: iluminación en espacio de mundo. Es la de Three.js.
Por qué importa el sistema, no sólo el espacio
Shirley lo dice textualmente: «It is important to choose a coordinate
system that is orthonormal when viewed in world space, because shading
equations depend on angles between vectors». Si la base no es ortonormal,
los ángulos se deforman aunque todo esté «en el mismo espacio».
6 · Las normales
La matriz normal
Una normal es una dirección, con $w = 0$: la traslación no la mueve, así
que sólo cuenta el bloque $3\times3$ de $\mathbf{M}$. Multiplicada como si
fuera un punto, con $w = 1$, la traslación la inclina. Con rotación o escalado
uniforme, $\mathbf{M}$ alcanza. Con escalado anisotrópico, $\mathbf{M}$ inclina
las normales y dejan de ser perpendiculares; la inversa transpuesta las
mantiene perpendiculares, pero cambia su largo: por eso siempre se
renormaliza.
Por cara: una normal perpendicular a cada triángulo.
Por vértice: el promedio normalizado de las caras que lo comparten.
No elegimos todavía ningún algoritmo de sombreado. Eso viene en el bloque 7.
Qué quiere decir «normal por cara»
En la GPU la normal es siempre un atributo de vértice. «Por cara»
quiere decir que los tres vértices del triángulo llevan la misma
normal: la perpendicular a la cara. Como dos triángulos vecinos
necesitan normales distintas en la esquina que comparten, ese vértice se
duplica: la misma posición, dos normales.
La distinción que se pierde siempre
«Facetado» y «suave» describen el resultado. Lo que lo produce puede ser
la asignación de normales o el algoritmo de sombreado. Son dos
palancas distintas y conviene no confundirlas.
7 · Algoritmos de sombreado
Modelo ≠ algoritmo, otra vez
El modelo dice qué se calcula. El algoritmo dice dónde se calcula.
Modelo de iluminación: Lambert, Phong, Blinn-Phong… la fórmula.
Algoritmo de sombreado: flat, Gouraud, Phong shading… la frecuencia de evaluación.
Nueve combinaciones, todas válidas. Three.js usa Blinn-Phong + por fragmento.
La trampa del nombre
«Phong» nombra dos cosas distintas: el modelo de reflexión (1975) y el
algoritmo de interpolación de normales. Shirley lo señala expresamente:
llamar Phong shading al sombreado por fragmento «is confusing».
7 · Algoritmos de sombreado
Flat shading
Una evaluación por cara. El resultado es constante en todo el triángulo.
Se evalúa la ecuación una vez por polígono, con la normal de la cara.
Es el más barato de los tres y el único que muestra la malla tal cual es.
Correcto para superficies que realmente son planas: un cubo, un cristal tallado.
En Three.js
material.flatShading = true. Ojo: hay documentación vieja que habla de
una propiedad shading con THREE.FlatShading — esa API se eliminó en
r72.
7 · Algoritmos de sombreado
Gouraud shading: se interpola el color
Se evalúa en los vértices y el rasterizador interpola el resultado.
Tres evaluaciones por triángulo, sin importar cuántos píxeles cubra.
Lo que se interpola es el color ya calculado, no la normal.
Fue el estándar durante veinte años, y sigue siendo lo correcto en hardware limitado.
Dónde se evalúa
En el vertex shader. Por eso Gouraud es barato: el costo escala con la
cantidad de vértices, no con la de píxeles.
7 · Algoritmos de sombreado
Bandas de Mach: por qué las vemos
El facetado se ve peor de lo que es, y la culpa es de la retina.
En un salto de intensidad, el ojo exagera el contraste a los dos lados.
La causa es la inhibición lateral: cada receptor resta el promedio de sus vecinos.
No está en la imagen. Está en el observador.
Qué implica para nosotros
Cualquier discontinuidad de intensidad va a leerse más fuerte de lo que la
calculamos. Es la razón por la que flat shading resulta tan desagradable,
y por la que Gouraud fue una mejora tan grande.
7 · Algoritmos de sombreado
El defecto grave de Gouraud
Con el máximo especular sobre un vértice: el brillo aparece, pero deformado y del tamaño del triángulo.
Con el máximo en el medio del triángulo: el brillo desaparece por completo.
Al mover la luz, alterna entre las dos cosas: parpadea.
Por qué esto mata a Gouraud para materiales brillantes
Para que Gouraud funcione con brillos hay que subdividir hasta que cada
triángulo sea del tamaño del brillo. Shirley lo dice textualmente.
Gouraud · máximo sobre un vérticePhong · máximo sobre un vérticeGouraud · máximo en el medioPhong · máximo en el medio
7 · Algoritmos de sombreado
Phong shading: se interpolan las normales
Se interpola la normal y la ecuación se evalúa después, una vez por fragmento.
Lo que viaja del vertex al fragment shader es la normal, no el color.
La ecuación completa se evalúa por píxel cubierto.
Es lo que hace hoy cualquier material de Three.js que responda a la luz.
El nombre es desafortunado
Se lo suele llamar per-fragment shading, que describe mejor lo que hace.
«Phong shading» viene del mismo autor que el modelo de Phong, pero es una
cosa distinta.
7 · Algoritmos de sombreado
La normal interpolada se acorta
El promedio de dos vectores unitarios no es unitario.
La interpolación es lineal; la superficie de los vectores unitarios es una esfera.
El resultado cae dentro de la esfera: es más corto.
Hay igualdad sólo si $\mathbf{N}_1$ y $\mathbf{N}_2$ son paralelos, o sea en las zonas planas.
$\mathbf{N}\cdot\mathbf{L}$ deja de ser un coseno y la difusa se apaga en
el medio de cada cara. La especular se apaga mucho más, porque el factor
acortado va elevado a $\alpha$.
7 · Algoritmos de sombreado
Los tres, lado a lado
FlatGouraudPhong
Flat: facetas planas, brillo con forma de polígono.
Gouraud: silueta suave, pero el brillo se derrite.
Phong: silueta igual de suave y el brillo redondo, del tamaño correcto.
La silueta no cambia nunca
Los tres tienen el mismo contorno poligonal. Ningún algoritmo de sombreado
agrega geometría: eso queda para el bloque 11.
8 · La textura entra en la ecuación
Un mapa difuso es $k_d$ por fragmento
El mapa difuso
A la izquierda, $k_d$ es una constante para todo el objeto.
A la derecha, $k_d$ se lee de una textura en cada fragmento.
El resto de la ecuación no se entera. Misma malla, misma luz, mismo shader.
$k_d$ constanteCon mapa difuso
La frase que encuadra la segunda mitad
Shirley lo dice así: «each time shading is computed, we read one of the
values used in the shading computation —the diffuse color, for instance—
from a texture instead of using the attribute values that are attached to
the geometry».
8 · La textura entra en la ecuación
Un mapa especular es $k_s$ por fragmento
El mapa especular · huellas
El mapa escala $k_s$ en cada fragmento: blanco es pulido, negro es mate.
Sólo se ve donde hay brillo. Fuera del reflejo, la esfera es idéntica.
Si la luz se mueve, el brillo encuentra otras huellas.
$k_s$ constanteCon mapa especularOtra luz · otras huellas
En Three.js
specularMap existe en MeshPhongMaterial, MeshLambertMaterial y
MeshBasicMaterial, y se lee del canal R. En Phong escala el brillo
especular y también el reflejo del envMap; en Lambert y Basic, sólo el
reflejo. MeshStandardMaterial no lo tiene: ahí el equivalente es el
roughnessMap.
8 · La textura entra en la ecuación
Color o datos: la única regla de espacio de color que nos toca
Lo que representa color —difuso, albedo, emisivo— se carga como sRGB.
Lo que representa datos —normales, rugosidad, altura, AO— se carga lineal.
Confundirlos falla en los dos sentidos: un mapa de color cargado lineal sale lavado; un normal map cargado como sRGB tuerce las normales.
En Three.js
textura.colorSpace = THREE.SRGBColorSpace para los mapas de color;
THREE.NoColorSpace para los de datos. Documentación vieja usa encoding
y sRGBEncoding: esa API quedó deprecada en r152.
Interactiva
9 · Mapas de entorno
Proyección equirectangular
Una sola imagen rectangular que cubre toda la esfera de direcciones.
El mapa equirectangular
El eje horizontal es la longitud ($0$ a $2\pi$), el vertical la latitud.
Es el formato en que vienen casi todos los HDRI que van a descargar.
Se deforma en los polos: ahí una fila entera de texels colapsa en un punto.
Reflejado en una esfera espejo
Por qué igual se usa
Una sola imagen, fácil de editar y de previsualizar. La GPU la convierte a
cube map al cargarla, que es el formato que realmente muestrea.
Interactiva
9 · Mapas de entorno
Cube map: seis caras
Seis texturas cuadradas, una por cara de un cubo centrado en el objeto.
El cube map desplegado
Cada cara cubre 90° × 90° de la esfera de direcciones.
La distorsión es uniforme: no hay polos que se apelotonen.
Reflejado en una esfera espejo
En Three.js
CubeTextureLoader carga las seis imágenes en orden px, nx, py, ny, pz,
nz. Con scene.background = cubeTexture además se ve el entorno detrás
del objeto.
9 · Mapas de entorno
El límite: espejos perfectos
roughness 0.0roughness 0.18roughness 0.45
Un mapa de entorno devuelve un texel por dirección: un reflejo nítido.
Una superficie rugosa refleja muchas direcciones a la vez, y el reflejo se difumina.
Hacerlo bien es pre-filtrar el entorno por nivel de rugosidad. Eso es IBL, y es PBR.
Qué queda abierto
Los tres renders de al lado salen de un motor que sí hace ese
pre-filtrado. Con el cube map crudo del pipeline clásico, sólo se puede
hacer la primera columna. Volvemos sobre esto en el bloque 13.
10 · Normal maps y espacio tangente
Detalle sin geometría
El mapa de normales
La malla es idéntica en los dos: una esfera lisa.
A la derecha, la normal que entra en la ecuación se lee de un mapa.
El relieve es una ilusión del sombreado, no geometría.
Sin normal mapCon normal map
Por qué existe la técnica
Agregar el mismo detalle con geometría real costaría cientos de miles de
triángulos. Un normal map cuesta una textura y una lectura por fragmento.
10 · Normal maps y espacio tangente
Qué guarda un normal map
Un vector por texel, empaquetado en los tres canales de color.
Una normal tiene componentes en $[-1, 1]$; un texel guarda valores en $[0, 1]$.
La codificación mapea un rango en el otro: es una transformación afín, nada más.
R, G y B no son color: son las componentes x, y, z de un vector.
\[RGB = 0.5\,\mathbf{N} + 0.5\]
El truco de lectura
Si un canal vale 128, esa componente vale 0. Si vale 255, vale +1. Si vale
0, vale −1. Con eso se puede leer un normal map a ojo.
10 · Normal maps y espacio tangente
Por qué se ve violáceo
El violeta no es un color elegido: es el valor de «no perturbar nada».
Sin perturbar, la normal en espacio tangente es $(0, 0, 1)$; codificada, $(128, 128, 255)$: ese violeta. Lo que se aparta del violeta está inclinado.
El bump map es un mapa de altura en grises: guarda cuánto sobresale cada punto. El normal map guarda hacia dónde se inclina, que es la derivada de esa altura.
Three.js acepta un bumpMap, pero no puede usarlo como normal: tiene que derivarla en cada fragmento, con más lecturas y un relieve más blando. Por eso la altura se convierte una vez a normal map, y se usa ese.
El normal mapEl bump map (altura)
10 · Normal maps y espacio tangente
Decodificar: de $[0,1]$ a $[-1,1]$
El paso inverso de la codificación, y el que más se olvida.
Es la inversa exacta de $RGB = 0.5\,\mathbf{N} + 0.5$.
Sin este paso, todas las componentes quedan positivas.
El síntoma: el relieve se aplana y se corre hacia una esquina.
Porque el resultado sigue siendo una imagen razonable. No hay error,
no hay pantalla negra: sólo un relieve que se ve raro y nadie sabe por
qué.
10 · Normal maps y espacio tangente
No hay desplazamiento de la superficie
La ilusión se cae en un lugar: el borde.
El normal map cambia la normal, no la posición de los vértices.
En el interior, el relieve convence. En la silueta, no hay nada que sobresalga.
Tampoco hay auto-sombra: un ladrillo no proyecta sombra sobre el de al lado.
Dónde deja de alcanzar
En objetos vistos de canto, en bordes contra el cielo, y en superficies
con relieve profundo. Para eso está el bloque 11.
10 · Normal maps y espacio tangente
¿Respecto de qué eje apunta esa normal?
La pregunta que obliga a inventar todo lo que viene.
El texel dice $(0.6,\ 0,\ 0.8)$. ¿Hacia dónde es eso en el mundo?
Depende de cómo esté orientada la cara.
Hace falta un sistema de ejes propio de cada cara: el espacio tangente.
La alternativa que no funciona
Guardar la normal en coordenadas de mundo: la textura sólo serviría para
esa superficie, sin poder repetirla, espejarla ni usarla en otro modelo.
10 · Normal maps y espacio tangente
El espacio tangente
Un sistema de coordenadas propio en cada punto de la superficie.
No es un espacio global: hay uno distinto en cada fragmento.
Está pegado a la superficie, y su eje principal se alinea con las UV.
El normal map guarda sus vectores en ese espacio, y por eso es reutilizable.
La consecuencia práctica
Una sola textura de ladrillos sirve para una pared, para una columna y
para el piso. Si las normales estuvieran en coordenadas de mundo, harían
falta tres texturas distintas.
10 · Normal maps y espacio tangente
La base TBN
Tres ejes ortonormales: tangente, bitangente y normal.
T — la dirección en que crece $u$. Va en el canal R.
B — la dirección en que crece $v$. Va en el canal G.
N — la normal de la cara. Va en el canal B.
Los tres forman una matriz que lleva del espacio tangente al de mundo.
El léxico de color no es decoración
Rojo = X = R, verde = Y = G, azul = Z = B. El color con que se dibuja cada
eje en estos diagramas es el mismo canal donde se guarda su componente. Es
la misma información dicha dos veces.
10 · Normal maps y espacio tangente
Bitangente, no binormal
El nombre correcto, y por qué el otro se usa igual.
«Binormal» viene del triedro de Frenet, que describe una curva.
En una superficie no hay una sola tangente: hay un plano de tangentes.
Por eso hacen falta dos, y las elige la parametrización UV.
Reconocer el préstamo
Three.js y buena parte de la industria dicen «binormal». Está mal usado,
pero está tan instalado que conviene reconocerlo al leer código ajeno.
10 · Normal maps y espacio tangente
De dónde salen T y B
De los bordes del triángulo, y de cuánto cambian las UV a lo largo de ellos.
Dos ecuaciones vectoriales, dos incógnitas: se despeja.
Los $\Delta u$ y $\Delta v$ salen de las UV de los mismos tres vértices.
Por eso T y B dependen del desenrollado, no sólo de la forma de la malla.
BufferGeometryUtils.computeTangents() hace exactamente esta cuenta y
deja el resultado en el atributo tangent. Necesita que la geometría
tenga uv; sin UV no hay tangente posible.
10 · Normal maps y espacio tangente
El signo de la bitangente
Con UV espejadas, el producto vectorial apunta para el lado equivocado.
Espejar UV es habitual: ahorra media textura en cualquier modelo simétrico.
En la mitad espejada, $\mathbf{B} = \mathbf{N} \times \mathbf{T}$ da la dirección contraria.
Por eso la tangente se guarda en un vec4, con $w = \pm 1$ como corrector.
Cómo se ve
El relieve aparece invertido en la mitad espejada: lo hundido sale y
lo que sale se hunde. No rompe nada, no tira ningún error, y sólo pasa de
un lado del modelo.
10 · Normal maps y espacio tangente
Componer la normal final
Las tres componentes del texel son los pesos de los tres ejes.
Es un cambio de base: del espacio tangente al de mundo.
Escrito como matriz, $\mathbf{N}' = TBN \cdot \mathbf{n}$, con $TBN$ armada por columnas.
Y hay dos maneras de hacerlo, con costos distintos.
Transformar $\mathbf{L}$ y $\mathbf{V}$ al espacio tangente en el vertex
shader, con $TBN^T$, y hacer toda la iluminación ahí. Se pasan dos
vectores por vértice en vez de una matriz por fragmento.
Interactiva
10 · Normal maps y espacio tangente
Normal maps: todo junto
80 triángulos. Elegí la capa, mové la luz y, con un clic, mirá un fragmento de cerca.
11 · Relieve: de la ilusión a la geometría
La sombra delata el relieve plano
Con luz rasante, un normal map no proyecta ninguna sombra. No tiene con qué.
El normal map perturba la normal, no la superficie: la malla sigue siendo un plano.
Un fragmento plano no puede taparle la luz a su vecino: no hay auto-sombra.
Tampoco hay sombra arrojada sobre el mortero, que es donde el ojo la busca.
Normal map · la superficie sigue planaGeometría desplazada · aparece la sombra
Cuándo se nota
Con la luz de frente el normal map es indistinguible de la geometría. El
error aparece cuando la luz se vuelve rasante: ahí la sombra que falta es
más informativa que el sombreado que sí está.
11 · Relieve: de la ilusión a la geometría
Displacement: mover los vértices de verdad
El mismo mapa de altura, pero aplicado a la posición en vez de a la normal.
Mismo mapa de altura que alimenta al normal map; cambia dónde se usa.
Va en el vertex shader: silueta, auto-sombra y paralaje reales.
El costo no es la textura: es la densidad de malla.
\[P' = P + h(u,v)\,\mathbf{N}\]
24×24 segmentos · el relieve se rompe512×512 segmentos · el relieve cierra
La regla práctica
El relieve representable está limitado por la separación entre vértices.
Con la malla más gruesa que el detalle del mapa no sale un relieve suave:
sale uno roto.
11 · Relieve: de la ilusión a la geometría
Parallax: desplazar la UV según la vista
El término medio: sin tocar un vértice, pero con paralaje de verdad.
El rayo del ojo toca el polígono en A. Desde ahí se marcha por el mapa de altura, en espacio tangente, hasta cruzar el relieve en B.
La distancia de A a B en la textura es el $\Delta uv$: el fragmento A se pinta con la textura de B.
Da paralaje y auto-oclusión. No da silueta ni sombra arrojada.
11 · Relieve: de la ilusión a la geometría
Los tres, comparados
Misma pared, misma luz, misma cámara. Lo único que cambia es la técnica.
Normal map · 2 triángulos · sin paralajeParallax · 2 triángulos · sin siluetaDisplacement · ~500 000 triángulos · real
12 · Light maps, alfa y orden
Light maps: guardar lo que no se puede calcular
El light map: las cinco caras desplegadasSólo la luz directaCon el light map
Cada texel guarda la luz que llega a un punto de la superficie: el resultado, no la fórmula.
Acá vuelve la iluminación global de la slide 05, pero precalculada.
Sólo sirve para lo que no se mueve: la geometría y las luces quedan congeladas.
Por qué sólo el decorado
El mapa vale para la geometría de fondo, que está quieta. Un personaje que
camina no puede llevar su iluminación horneada: se le aplica de otra
manera.
12 · Light maps, alfa y orden
El segundo canal UV
Un light map no puede usar el mismo desenrollado que el mapa de color.
UV1 puede repetirse y superponerse: el mismo ladrillo sirve en veinte paredes.
UV2 tiene que ser inyectivo: cada punto de la superficie, su propio texel.
Si dos puntos comparten texel, comparten la luz que se horneó ahí. Y no es la misma.
En Three.js
BufferGeometry guarda el segundo juego en el atributo uv1, y una
textura lo elige con textura.channel = 1. En material anterior a r155
aparece como uv2: se renombró, y es una fuente frecuente de confusión.
Interactiva
12 · Light maps, alfa y orden
Luz horneada: un dormitorio con lightmaps
12 · Light maps, alfa y orden
Alpha maps: opacidad por fragmento
El mapa de alfaSin alpha map: la malla es un cuadradoCon alpha map
El mapa de alfa es dato, no color: su único canal es la opacidad.
Recorta la silueta por fragmento, sin tocar un solo vértice.
Es lo que hace que un árbol tenga hojas y no cientos de miles de triángulos.
En Three.js
alphaMap necesita transparent: true. Con alphaTest en un valor entre
0 y 1, todo fragmento con alfa menor no se dibuja.
12 · Light maps, alfa y orden
discard o blending
Dos maneras de usar el alfa, con costos y problemas distintos.
Alpha test: binario y barato. El fragmento queda en el z-buffer y no depende del orden.
Blending: medio tono real, pero hay que ordenar y el objeto no queda en el z-buffer.
La regla práctica: follaje y rejas con alpha test; vidrio y humo con blending.
Por qué el alpha test es más cómodo de lo que parece
Como escribe profundidad, un objeto con alpha test se comporta como uno
opaco: se lo puede dibujar en cualquier orden y sigue tapando bien lo que
tiene detrás. Es lo que hace que un bosque entero se pueda dibujar sin
ordenar nada.
12 · Light maps, alfa y orden
El problema del orden
La misma escena, la misma cámara. Lo único que cambia es en qué orden se dibujan las tres capas.
La prueba de profundidad es conmutativa: con ella sola, el orden no importa.
Mezclar no lo es: a sobre b no da lo mismo que b sobre a.
Por eso lo translúcido se dibuja de atrás hacia adelante, y hay que ordenarlo en la aplicación.
De atrás hacia adelanteDe adelante hacia atrás
Y no siempre se puede
Ordenar por objeto alcanza cuando los objetos no se atraviesan. Dos
superficies translúcidas que se cruzan no tienen un orden correcto:
cualquiera de los dos está mal en parte de la pantalla. Ahí ya no hay
solución dentro de este pipeline.
12 · Light maps, alfa y orden
Un objeto transparente solo: dos pasadas
Cuando no hay nada detrás contra qué mezclar, lo que falta son las caras de atrás del propio objeto.
Con una sola pasada se dibujan sólo las caras de adelante: el objeto se ve opaco.
Se dibuja dos veces: primero las de atrás, después las de adelante.
Es el mismo orden de siempre —de atrás hacia adelante— pero adentro de un solo objeto.
Una pasada: sólo las caras de adelanteDos pasadas: atrás y después adelante
En Three.js
Dos mallas con la misma geometría: una con side: THREE.BackSide y
renderOrder: 0, otra con side: THREE.FrontSide y renderOrder: 1. En
WebGL crudo es la misma idea con gl.cullFace(gl.FRONT) y después
gl.cullFace(gl.BACK).
13 · El puente a PBR
Ambient occlusion: el parche del parche
El mapa de AOAmbiente constanteAmbiente × AO
El AO map guarda, por texel, cuánto del cielo le tapa la geometría vecina.
Multiplica a la ambiente, no se suma: es un factor entre 0 y 1.
Va en el segundo canal UV, igual que el light map, y por el mismo motivo.
No es una sombra
Una sombra depende de dónde está la luz; el AO no. Es una propiedad de la
forma del objeto, y por eso se puede hornear una sola vez y sirve para
cualquier iluminación.
La superficie está cubierta de microfacetas; la rugosidad dice cuánto se desvían.
Rugosidad 0, reflejo especular; rugosidad 1, difuso. Y puede ser un mapa.
Por qué es mejor que el exponente
El exponente de Phong no tenía ni unidades ni límites: 30 y 300 son igual
de arbitrarios. La rugosidad va de 0 a 1 y significa lo mismo en cualquier
motor.
13 · El puente a PBR
Metal o dieléctrico
metalness 0 · dieléctricometalness 0.5 · ningún material realmetalness 1 · metal
Un dieléctrico refleja sin teñir: el brillo tiene el color de la luz, no el del material.
Un metal absorbe lo que entra y tiñe su reflejo con su propio color. Y no tiene difuso.
Por eso metalness es casi binario: 0 o 1. Los valores del medio no son ningún material real.
El valor por omisión engaña
El libro dice que metalness y roughness valen 0.5 por omisión. En r162
valen 0 y 1, verificado en el código. Un 0.5 heredado de un ejemplo viejo
es un material que no existe.
13 · El puente a PBR
Emissive: superficie que no depende de la luz
Un término que se suma al final y al que ninguna luz afecta.
Color puro sumado al final: ninguna luz lo modifica.
No ilumina a los vecinos: la otra esfera y el piso no cambian.
Para que ilumine hace falta una luz real, o bloom en post.
emissive apagadoemissive encendido · el vecino no cambia
En Three.js
emissive es un color —negro por omisión— y emissiveIntensity su
intensidad. El libro es explícito: «It doesn't act as a light source».
13 · El puente a PBR
De Phong a PBR, término por término
Qué le pasa a cada término al pasar a un modelo físico.
14 · Cierre
El mapa de los mapas
Interactiva
14 · Cierre
Los mapas del capítulo, en una escena real
14 · Cierre
Referencias · qué viene después
Todo lo que dice esta presentación está verificado contra estas obras, página por página.
Hughes, J. et al., Computer Graphics: Principles and Practice, 3.ª ed.Cap. 26 «Light», pp. 669-712 · Cap. 27 «Materials and Scattering», Ec. 27.20-21, p. 722 · microfacetas p. 726 · conductores p. 682 · oclusión ambiental p. 742
Marschner, S. & Shirley, P., Fundamentals of Computer Graphics, 5.ª ed.Cap. 5 «Surface Shading», pp. 99-106 · §9.2, p. 197 · §11.4.3, p. 280 · Cap. 22, pp. 630 y 641 · §17.13, pp. 486-487
Angel, E. & Shreiner, D., Interactive Computer Graphics with WebGL, 7.ª ed.Cap. 6 «Lighting and Shading», pp. 277-302 · §7.10.5, p. 371
Ghayour, F. & Cantor, D., Real-Time 3D Graphics with WebGL 2, 2.ª ed.Cap. 6: profundidad, blending y face culling
Dirksen, J., Learn Three.js, 4.ª ed.pp. 105-107, 125-131 — nombres y propiedades de los materiales
Phong, B. T., Illumination for Computer Generated PicturesCommunications of the ACM 18(6), 1975, pp. 311-317
LearnOpenGL, Basic Lighting · Light Casterslearnopengl.com — CC BY-NC 4.0
Qué viene después, y qué no estaba en los libros
Sigue PBR: la ecuación de rendering, el modelo de microfacetas, Fresnel e
iluminación basada en imagen. Tres cosas de este capítulo no aparecen en
ninguna de las cinco obras —parallax occlusion mapping, el segundo canal
UV y el AO fuera de Hughes— y están verificadas contra el código de
Three.js r162 o contra la figura generada. Cuando una fuente no alcanza,
se dice.