Iluminación Horneada en Color de Vértice con Wonderland Engine

Para su juego de Mini-Golf “Above Paradowski”, Colin Freeman, Ayushman Johri y James Kane utilizaron una técnica impresionante para hornear la iluminación en su escena. Ahorraron búsquedas de texturas de lightmap en el fragment shader mientras lograban un aspecto altamente pulido para su experiencia.

En este artículo, vamos a destacar por qué esta técnica es inteligente y cómo puedes utilizarla en Wonderland Engine.

Iluminación Horneada en Color de Vértice con Wonderland Engine
Iluminación Horneada en Color de Vértice con Wonderland Engine

Captura de pantalla de una isla flotante en Blender: iluminación plana (izquierda), colores de vértice horneados (derecha).

Motivación 

Calcular la iluminación toma mucho tiempo. Para un resultado realista, necesitas trazar caminos de luz y rebotes, cada rebote resultando en más caminos de luz y rebotes por calcular. ¡La cantidad de trabajo explota!

Así es como se renderizan las películas animadas, pero en VR en tiempo real, en lugar de minutos por cuadro, tenemos alrededor de 11 milisegundos para dos cuadros (ojo izquierdo y derecho) a 90 Hz para dispositivos VR autónomos. En lugar de granjas de renderizado de GPU, tenemos una GPU móvil.

Como mantener 60-90 Hz es importante para la comodidad e inmersión en VR, necesitamos abordar el problema de una manera diferente. Wonderland Engine ya implementa muchos grandes métodos y optimizaciones para renderizar rápido, incluso con sombras en tiempo real, pero para escenas extremadamente grandes, necesitamos cada parte de rendimiento que podamos obtener.

Horneado de Iluminación 

En lugar de calcular la iluminación en tiempo de ejecución, podemos calcularla por adelantado y almacenar el resultado en nuestro activo, por ejemplo, dibujando o calculando sombras en nuestras texturas. Este proceso se llama “horneado”.

Incluso podemos usar los mismos métodos utilizados en la animación 3D y obtener así resultados muy realistas.

Las texturas funcionan bien, ya que permiten almacenar una gran cantidad de detalle con sombras finas y efectos de iluminación. Especialmente con el streaming de texturas de Wonderland Engine, puedes usar texturas de muy alta resolución y obtener escenas de aspecto increíble.

Sin embargo, las texturas requieren mucha información para almacenarse, incluso cuando están bien comprimidas. En su lugar, podemos cambiar parte del detalle por el tamaño de la descarga y almacenar un atributo de color adicional en tu malla por vértice.

Texturas de Lightmap vs Colores de Vértice 

Al hornear iluminación en texturas, nuestro cálculo de luz en la GPU se reduce principalmente a una lectura de textura: para cada píxel que renderizamos en la pantalla, buscamos el píxel correcto en el lightmap. Cada píxel renderizado puede obtener un color diferente del lightmap, permitiendo detalles de alta frecuencia.

Los colores de vértice, por otro lado, son la entrada del vertex shader e interpolados entre vértices. La frecuencia de detalle dependerá de la resolución de tu malla y generalmente es muy baja. Esto reduce el cálculo del color del píxel aún más a solo pasar el color interpolado del vertex shader al framebuffer de salida.

Rendimiento 

¿Qué es más eficiente? La respuesta para cualquier pregunta de rendimiento siempre es: depende. Especialmente de tus cuellos de botella.

Muchas aplicaciones de WebXR hoy están limitadas por llamadas de dibujo: la CPU no puede hacer más trabajo, por lo que optimizar la carga de trabajo de la GPU no tiene efecto. Posiblemente en la duración de la batería, pero no en tu tasa de cuadros.

Wonderland Engine resuelve esto completamente con sus optimizaciones, renderizando decenas de miles de objetos dinámicos en menos de diez llamadas de dibujo en casi todos los casos. Que algunas otras aplicaciones están limitadas por el shading de vértices al animar muchos personajes es resuelto con un método de skinning altamente optimizado para VR que puede procesar eficientemente cientos de mallas animadas diferentes.

Pero incluso las aplicaciones de Wonderland Engine pueden terminar limitadas por el shading de fragmentos. Más instrucciones y operaciones más costosas en tu fragment shader requieren más poder computacional de la GPU por píxel en pantalla. Nuestro shader “Physical” (PBR) tiene más instrucciones que “Phong”, que tiene más que “Flat”.

Mientras que las GPU modernas son muy rápidas al leer texturas, simplemente leer los colores de los datos de la malla durante la captura de vértice será más eficiente en términos de caché y es difícil de superar, especialmente si esto también significa que puedes omitir normales y coordenadas de textura de tu malla por completo. Para esta técnica, podemos usar un shader plano sin textura que requiere solo posiciones y colores.

Esto deja una menor cantidad de memoria para leer por vértice y apenas cualquier trabajo que hacer por fragmento. Esto nos dejaría limitados solo por el shading o la captura de vértice, pero solo a conteos de vértice muy impresionantes en nuestra escena como se muestra en Resumen.

Tutorial 

Comenzamos horneando iluminación a colores de vértice en Blender y luego importamos el modelo en Wonderland Engine.

Hornear a Colores de Vértice en Blender 

Elige una escena y configura las luces. Blender ya tiene soporte completo para hornear a colores de vértice, por lo que no se necesitan plugins, la configuración es directa:

  1. Abre una ventana de scripting en Blender y usa el siguiente script de Python para añadir una capa de color de vértice a todos los objetos seleccionados, ejecutando este script:
1import bpy
2
3for o in bpy.context.selected_objects:
4    if o.type != 'MESH':
5        continue
6    if len(o.data.vertex_colors) != 0:
7        continue
8
9    o.data.vertex_colors.new()
  1. En las Propiedades de Renderizado, cambia el motor de renderizado a Cycles
  2. Encuentra la sección Bake más abajo y cambia Output > Target a Vertex Colors
  3. Establece el Bake Type a Diffuse
  4. Pulsa el botón Bake en la parte superior de esta sección

Para ver el resultado, puedes configurar los ajustes del viewport para visualizar el resultado:

  1. En el 3D Viewport encuentra la flecha junto a los tipos de renderizado (generalmente el botón más a la derecha en el menú superior)
  2. Para Lighting selecciona Flat
  3. Para Color selecciona Vertex
Iluminación Horneada en Color de Vértice con Wonderland Engine

Finalmente exporta el modelo como GLB seleccionando File > Export > glTF 2.0 (.glb/.gltf).

Importar en Wonderland Engine 

Crea el siguiente VertexColor.frag en una subcarpeta shaders en tu proyecto:

 1#include "lib/Compatibility.frag"
 2
 3#define USE_COLOR
 4
 5#define USE_MATERIAL_ID
 6#include "lib/Inputs.frag"
 7
 8void main() {
 9    outColor = fragColor;
10}

A continuación, importamos el modelo en Wonderland Engine y utilizamos este shader para renderizarlo:

  1. Arrastra y suelta el archivo .glb en el Navegador de Recursos
  2. Desde allí, arrástralo a la vista de escena
  3. Ve a Views > Resources > Pipelines y selecciona Phong Opaque o Phong Opaque Textured, dependiendo de si tus objetos inicialmente estaban usando texturas.
  4. Cambia el shader al nuevo shader VertexColor.

Al cambiar el pipeline existente de Phong, podemos cambiar automáticamente todos los materiales. Una configuración más limpia sería asignar el pipeline “VertexColor” creado automáticamente y asignarlo a todos los materiales que queremos cambiar.

Ahora deberías ver los colores de vértice correctamente aplicados a tu escena.

Iluminación Horneada en Color de Vértice con Wonderland Engine

Resumen 

Hornear iluminación a colores de vértice es una forma muy eficiente de lograr visuales de aspecto hermoso. El siguiente video demuestra 3.6 millones de vértices renderizados con este método a 60-72 fps en Meta Quest 2 en el Meta Quest Browser.

YouTube Video

La demo utiliza las optimizaciones integradas de Wonderland Engine, fixed-foveation (en 1.0) y el método descrito en este post. La escena se renderiza en 2 llamadas de dibujo (a partir de 0.9.4, el próximo soporte para renderizado multivista reducirá esto en un 50%). Cada objeto aún podría moverse independientemente mediante scripts o animación sin impactar negativamente el rendimiento.

Last Update: December 2, 2022

Mantente al día.