Normal maps, Parallax Mapping & Displacement
Un mapa de normales modifica la normal de la superficie que se usa para el cálculo de la luz reflejada. De este modo, se obtiene una sensación de relieve en la superficie sin necesidad de geometría extra.
La idea es falsear como la luz es reflejada cuando incide sobre el material creando esa ilusión de profundidad sin pagar el coste de geometría extra.
El problema con el normal map es que la normal para una coordenada $(u,v)$ no es la "correcta". Fíjate en la imagen de abajo:
Estamos mirando el punto A de la superficie con coordenadas UV $(u_a, v_a)$. Sin embargo, estamos simulando un relieve por lo que realmente si estuviera modelado con geometría deberías ver el punto B con coordenadas UV $(u_b, v_b)$ (no el A).
Por lo tanto, la normal que deberíamos obtener si preguntamos por el punto A no es la que está almacenada en $(u_a, v_a)$ si no la que está almacenada en el punto $(u_b, v_b)$.
Para solventar este problema se usa la familia de algoritmos Parallax Mapping. Toda la familia de algoritmos Parallax Mapping reciben las coordenadas UV "originales" (las del punto A) y devuelven una aproximación de las coordenadas UV del punto B.
Además de recibir como entrada las coordenadas $(u_a, v_a)$, tienen como entrada adicional un heightmap y, en función del algoritmo, algún parámetro extra.
Los algoritmos Parallax Mapping en orden de complejidad son:
- Parallax Mapping with Limited Offset
- Steep Parallax Mapping
- Parallax Occlusion Mapping (POM)
Aquí una ilustración del resultado de estos métodos:
Empecemos por el primero.
Parallax Mapping with Limited Offset
El primer algoritmo y más básico es el Parallax Mapping with Limited Offset, también llamado Bump Offset en Unreal Engine.
Intenta aproximar el punto B en un solo paso: toma el valor de profundidad del punto A, representado en la imagen como H(A), y lo multiplica por un factor dado como parámetro (en Unreal el parámetro se llama Height Ratio), se lo suma al vector tangente en A y obtiene el punto P como aproximación al punto B.
El Parallax Mapping with Limited Offset (Bump Offset en UE4) es muy eficiente y practicamente tiene el mismo coste que el normal mapping.
Así quedaría en el editor de materiales un material de ladrillos:
Dónde el height map está almacenado en el canal alpha de la textura.
Steep Parallax Mapping
El siguiente miembro de la familia es el Steep Parallax Mapping.
La idea es aproximar el punto P en varios pasos, no solo en uno. Se va desplazando paso a paso hasta que se encuentra un punto por debajo de la línea de profundidad y se devuelve dicho punto:
En Steep Parallax Mapping además del height ratio se toma como parámetros el número de pasos mínimo y máximo.
En Steep Parallax Mapping se va tomando un texture sample del height map (texture2d(heightmap, uv)) en cada paso hasta llegar al punto que quede "dentro" de la linea de profundidad.
Parallax Occlusion Mapping
El último algoritmo, Parallax Occlusion Mapping, intenta mejorar la aproximación tomando dos texture sampling cuando lleguemos a la intersección. Entonces podemos interpolar ambos valores para obtener una mejor aproximación.
En Unreal Engine tenemos el nodo ParallaxOcclusionMapping en el editor de materiales:
En UE4 el algoritmo hace el cálculo de las sombras autoinfligidas por la propia geometría.
Displacement Map
Hasta aquí ningún método altera la geometría. Los mapas de desplazamiento (Displacement Map) hacen precisamente eso: desplazan vértices.
En UE4 la tessellation se hace muy fácil:
- Se desplaza los vértices con World Displacement
- Usar Tessellation Multiplier para añadir geometría.
Aquí un post completo sobre tessellation en UE4.