Ray Marching: campos de distancia con signo, sphere tracing y sombreado con SDF

EN NL ES PT-BR


El ray marching es un método de renderizado que encuentra superficies avanzando a lo largo de un rayo en pasos repetidos. Aparece a menudo en renderizado procedural porque una escena puede describirse mediante funciones en lugar de una malla almacenada o un conjunto de ecuaciones cerradas de intersección de rayos. La versión más común utiliza un campo de distancia con signo (SDF, por sus siglas en inglés) para elegir cada tamaño de paso. Un SDF indica la distancia desde el punto actual hasta la superficie más cercana, con un signo que dice si el punto está fuera o dentro de la forma. Si la distancia es d, entonces la superficie más cercana está exactamente a d unidades, así que el rayo puede avanzar esa cantidad sin sobrepasarla.

Las secciones interactivas que siguen se mantienen en 2D a propósito para que cada idea geométrica se mantenga visible, y la misma lógica se extiende directamente a escenas en 3D. La siguiente sección presenta el algoritmo y explica cómo el sphere tracing usa el campo de distancia para elegir cada paso de forma adaptativa; luego la visualización que sigue muestra un solo rayo avanzando hacia un círculo guiado paso a paso por ese campo.

Algoritmo de ray marching

El término ray marching es amplio. Se refiere a avanzar a lo largo de un rayo en incrementos y revisar la escena repetidamente. La versión más simple usa un tamaño de paso fijo: avanza un poco, muestrea la escena y repite. Es fácil de entender, pero puede ser muy ineficiente. Los pasos pequeños son más seguros cerca de detalles finos pero desperdician trabajo en espacio vacío, mientras que los pasos grandes son más rápidos pero pueden saltarse superficies.

En pseudocódigo, el bucle central repite cuatro pasos:

  1. establecer la distancia recorrida t = 0
  2. muestrear la escena en rayOrigin + rayDir * t
  3. si la muestra está lo suficientemente cerca de una superficie, registrar un impacto
  4. si no, añadir la distancia de paso elegida a t
  5. detenerse tras una distancia máxima o un número máximo de pasos

La versión más común en los tutoriales de gráficos evita la compensación del paso fijo usando sphere tracing sobre un campo de distancia con signo , tal como lo describió John C. Hart en Sphere Tracing: A Geometric Method for the Antialiased Ray Tracing of Implicit Surfaces. Un SDF devuelve la distancia más corta desde un punto hasta la superficie más cercana, con un signo que indica si el punto está fuera (positivo), sobre la superficie (cero) o dentro de la forma (negativo).

Si el campo es preciso, un valor de d(p)d(p) significa que no hay ninguna superficie más cerca que esa distancia desde el punto de muestra actual pp. Eso permite que el rayo salte hacia adelante exactamente d(p)d(p) sin sobrepasar la superficie más cercana. En lugar de elegir un tamaño de paso fijo para todo el rayo, el propio campo decide qué tan lejos puede moverse el rayo de forma segura a continuación. La eficiencia viene de tomar grandes pasos seguros a través del espacio vacío mientras los pasos se encogen automáticamente cerca de las superficies: la siguiente sección lo demuestra paso a paso.

Avanzando por un campo de distancia

Un círculo simple hace que el avance sea visible en detalle. Para un círculo con centro cc y radio rr, el campo de distancia con signo es:

d(p)=pcrd(p) = \lVert p - c \rVert - r

La longitud pc\lVert p - c \rVert es la distancia desde el punto de muestra pp hasta el centro del círculo. Restar el radio desplaza esa distancia para que el borde tenga valor cero, los puntos exteriores tengan valores positivos y los interiores negativos.

Distance-Guided Stepping

Drag the circle or the ray arrow to see how the marcher advances by safe distances.

SDF value 0.00 surface -0.16 +1.25

En la visualización, cada anillo púrpura es la distancia devuelta en el punto de muestra actual. Como el anillo toca la superficie más cercana pero no la cruza, el rayo puede moverse hasta el borde de ese anillo de forma segura. Cuando el rayo apunta directamente hacia el círculo, la distancia devuelta se reduce rápidamente y los pasos convergen hacia el borde. Cuando el rayo apunta en dirección contraria, las distancias pueden crecer y el algoritmo termina sin encontrar un impacto.

Eso es el sphere tracing: el rayo avanza la distancia que devuelve el campo, reevalúa y repite hasta que alcanza una superficie o se rinde. La regla de actualización es simplemente:

pn+1=pn+d(pn)r^p_{n+1} = p_n + d(p_n)\,\hat{r}

donde r^\hat{r} es la dirección del rayo. El tamaño del paso no es arbitrario; viene de la geometría del propio campo. Eso es lo que separa al ray marching con SDF del ingenuo marching con paso fijo.

En un shader, normalmente te detienes cuando ocurre una de tres condiciones:

  1. la distancia cae por debajo de un umbral de impacto pequeño como 0.001
  2. la distancia de viaje acumulada supera un rango máximo
  3. el bucle alcanza un número máximo de pasos

Los tres límites importan. El umbral de impacto controla la precisión, el rango máximo acota el trabajo para rayos que no impactan, y el límite de pasos te protege de casos patológicos o estimadores de distancia mal comportados. El límite de pasos es especialmente importante para rayos que rozan superficies en ángulos rasantes , donde la distancia perpendicular cambia lentamente a medida que el rayo avanza y el sphere tracing puede consumir cientos de pasos para un solo rayo antes de converger.

Construyendo una escena con SDF

Un solo círculo es útil para la intuición, pero el ray marching se vuelve poderoso cuando se puede describir una escena entera como una única función de distancia. Lo haces combinando SDF primitivos en un único campo combinado, siguiendo el enfoque de Iñigo Quilez en Distance Functions. En 2D, un círculo es la distancia a un centro menos el radio. Una línea o un plano pueden representar un suelo. Para combinarlos, normalmente tomas la distancia mínima a todos los objetos porque la superficie más cercana controla el siguiente paso seguro.

2D Ray Marching Scene

Cast a small fan of rays through circles and a ground line to see how the minimum SDF controls every step.

En el explorador de escenas, cada rayo consulta repetidamente el mínimo de las distancias a los círculos y la distancia al suelo. Ese mínimo importa por una razón simple: si un objeto está cerca y otro está lejos, el cercano define el paso seguro más grande posible. Usar la distancia mayor equivocada podría saltarse la superficie más próxima.

Esta regla del “mínimo de primitivas” es la base del modelado SDF constructivo . Un shader no necesita mallas de triángulos para describir la escena. Solo necesita una función que responda: “¿a qué distancia estoy de la superficie más cercana en este momento?”

Por qué converge el método

Una pregunta común entre principiantes es por qué el sphere tracing no se salta geometría delgada. La respuesta es que se basa en una estimación conservadora de la distancia. Si el SDF es exacto, el valor devuelto es una cota inferior garantizada de la distancia real a la superficie más cercana, así que el siguiente paso aterriza sobre o antes de la superficie más cercana posible, nunca más allá.

Esa garantía se debilita cuando la función es solo un estimador de distancia en lugar de un campo de distancia con signo perfecto. El renderizado de fractales es un ejemplo clásico: el estimador puede funcionar, pero la seguridad del paso depende de qué tan conservadora sea esa estimación. Para más información sobre la calidad del campo y cuándo se mantiene la garantía de distancia exacta, consulta la discusión sobre calidad del campo en el artículo sobre campos de distancia con signo.

Normales SDF y sombreado

Las mallas rasterizadas suelen almacenar normales de vértice o derivarlas de los triángulos. Una superficie SDF renderizada con ray marching no tiene una malla explícita, así que la normal debe obtenerse del propio campo. El enfoque consiste en estimar el gradiente del SDF muestreando el campo con pequeños desplazamientos: si la muestra derecha está más lejos fuera del objeto que la muestra izquierda, la superficie se inclina hacia la derecha, y lo mismo para arriba y abajo. Normalizar ese vector gradiente da una normal de superficie utilizable.

Gradient arrow Surface normal

La visualización superpone flechas de gradiente sobre el mapa de calor del SDF. Cada flecha apunta en la dirección de f\nabla f en su ubicación, irradiando hacia afuera desde la superficie más cercana sin importar la forma. Pasa el cursor sobre el campo y aparece una sonda que muestra la distancia con signo, la dirección del gradiente y la magnitud del gradiente en ese punto exacto. La lectura etiqueta la flecha como normal de superficie cuando el cursor está cerca del contorno cero, haciendo explícita la relación entre gradiente y normal. Haz clic para fijar la sonda en su lugar y alterna entre círculo, caja, caja redondeada, segmento de línea y una unión compuesta de dos círculos para confirmar que las normales emergen de la estructura del campo de la misma manera en todas las formas.

El gradiente se estima numéricamente usando diferencias finitas: la plantilla muestra los puntos de muestreo ±ε\pm\varepsilon a lo largo de cada eje, cada uno etiquetado con el valor de distancia muestreado allí. Arrastra el control de ε\varepsilon para ver el equilibrio entre gradientes ruidosos con espaciado muy pequeño y direcciones suavizadas en exceso con espaciado grande. Esta es una de las ideas más útiles en el renderizado con SDF: el mismo campo que guía la intersección también proporciona una forma de sombrear la superficie resultante.

Bucle típico de un shader

Una versión en fragment shader suele verse conceptualmente así:

  1. construir un rayo de cámara para el píxel actual
  2. establecer t = 0
  3. evaluar sceneSdf(rayOrigin + rayDir * t)
  4. si la distancia está por debajo de epsilon, registrar un impacto
  5. si no, incrementar t en esa distancia y continuar
  6. si el bucle termina sin impacto, dibujar el fondo
  7. si hay un impacto, estimar una normal y calcular la iluminación

El bucle es simple, pero los detalles que lo rodean determinan la calidad de la imagen. La configuración de la cámara afecta la distorsión y la composición. El umbral epsilon afecta el bandeado y los artefactos de auto-sombra. El número máximo de pasos determina si los rayos rasantes terminan limpiamente. La calidad de la iluminación depende de la estimación de normales, las sombras, los términos ambientales, los reflejos y el modelo de material que construyas después.

Ventajas y compensaciones

El ray marching es atractivo porque hace que la geometría procedural sea inusualmente directa. Una primitiva es solo una fórmula. La combinación de escenas suele ser cuestión de unas pocas operaciones min y max. Las mezclas suaves, repeticiones, torsiones y deformaciones basadas en ruido a menudo pueden expresarse analíticamente sin reconstruir la topología de la malla. Por eso la técnica se popularizó en el arte con shaders, la producción demoscene y los experimentos de renderizado procedural.

Las compensaciones son igual de reales:

  • cada píxel puede requerir muchas evaluaciones de la escena
  • las características delgadas o muy detalladas pueden necesitar muchos pasos o umbrales cuidadosos
  • las sombras suaves, la oclusión ambiental y los reflejos añaden aún más marchas
  • los estimadores de distancia que no son conservadores pueden causar fallos o artefactos
  • las escenas grandes necesitan una aceleración cuidadosa o un diseño de dominio para mantenerse rápidas

Así que el ray marching no es un reemplazo universal para la rasterización o el trazado de triángulos por hardware. Se entiende mejor como una herramienta poderosa de renderizado procedural con una fortaleza específica: cuando la geometría es más fácil de definir como un campo que como una malla, en contraste con el pipeline de rasterización estándar descrito en vertex vs fragment shaders en el pipeline gráfico . Para una comparación detallada cara a cara de rendimiento, calidad, representación de escena y casos de uso, consulta ray marching vs ray tracing .

Extensiones comunes

Una vez que el rayo primario impacta correctamente, muchos efectos clásicos se construyen a partir del mismo mecanismo. Los rayos de sombra marchan desde la superficie hacia la luz. La oclusión ambiental muestra qué tan rápido aparece la geometría cercana a lo largo de la dirección normal. Los reflejos generan otro rayo desde el punto de impacto. Cuando las familias de rayos reflejados o refractados se agrupan en lugar de dispersarse uniformemente, la misma intuición de enrutamiento de rayos lleva a las cáusticas por concentración de luz . La niebla y los efectos volumétricos acumulan contribuciones a medida que el rayo viaja. Cada uno reutiliza el mismo patrón central de evaluación repetida de la escena, y muchos se vuelven visualmente más útiles una vez que modulas formas o materiales con ruido de valor, ruido Perlin y ruido fractal .

Esa reutilización es una de las razones por las que el ray marching es tan didáctico. El renderizador se mantiene conceptualmente consistente incluso cuando añades más funciones. Sigues preguntando a la escena por información de distancia y usando esa información para decidir qué tan lejos moverte a continuación. La complejidad crece, pero el modelo mental subyacente no cambia.

Resumen

El ray marching con campos de distancia con signo funciona porque la escena le dice a cada rayo qué tan lejos puede moverse de forma segura. Eso convierte la intersección en un proceso iterativo guiado por la geometría en lugar de por incrementos fijos. Si mantienes cuatro ideas en mente, la técnica se vuelve mucho más fácil de razonar:

  1. un SDF devuelve la distancia a la superficie más cercana con un signo
  2. la distancia mínima en la escena determina el siguiente paso seguro
  3. los pasos seguros repetidos convergen hacia la superficie cuando el campo es conservador
  4. el gradiente del campo proporciona una normal utilizable para la iluminación

Esas cuatro piezas son el núcleo de la mayoría de los renderizadores introductorios con shaders SDF. Después de eso, el trabajo es principalmente ingeniería: elegir umbrales, optimizar la evaluación de la escena y superponer iluminación o efectos secundarios.