¿Cómo se implementa la Marcha de Rayos de Campo de Distancia Firmado para un mundo dinámico?

10

Creo que entiendo los conceptos básicos de Signed Distance Field Ray Marching. Modela tu escena con un montón de campos de distancia (como estos: http://iquilezles.org/www/articles/distfunctions/distfunctions.htm ), luego, por cada píxel que emites un rayo, comienza desde el principio del rayo , encuentre la distancia al objeto más cercano en ese punto e incremente el punto por la distancia más cercana, hasta que golpee algo. Logré hacer un renderizador simple, y ahí es donde se detiene la mayoría de las descripciones de la técnica.

Esto me deja con algunas preguntas sobre cómo SDF Ray Marching se puede utilizar en un escenario del mundo real:

Pregunta 1: En un juego real, la escena suele ser compleja y cargada en la CPU, con muchos objetos dinámicos. Entiendo el sacrificio de oclusión básico (como los octrees), y con el renderizado poligonal, crearía una lista (en la CPU) de elementos en la vista frustrum para renderizar.

Entonces, imagina que tengo una escena muy compleja con muchos personajes y objetos dinámicos que se mueven en la pantalla, controlados por la CPU. ¿Cómo transmitiría los objetos que quiero renderizar a la GPU cada fotograma? Cada ejemplo tiene la escena codificada en GLSL. ¿Alguien puede compartir un ejemplo del nivel que se transmite al sombreador dinámicamente?

Pregunta 2: ¿Cómo pueden los objetos tener múltiples colores? Las funciones de distancia solo devuelven una distancia, pero ¿cómo suelen las implementaciones pasar el color de vuelta? (por ejemplo, golpeas una esfera roja y no un cubo azul). Si se tratara de una implementación de CPU, podría llamar a una función global dentro de la función de distancia cuando es un golpe para terminar el marcador de rayos, y eso también podría pasar el objeto golpeado. textura / color. Pero, ¿cómo devolvería el color o la textura del elemento en GLSL?

Gracias.

Andrew Price
fuente

Respuestas:

2

Esta es una respuesta mínima, pero quería compartir la información en caso de que no obtuviera una mejor respuesta.

En cuanto a cómo los juegos reales usan la marcha de rayos, generalmente no lo hacen. Solo en los últimos dos años, los juegos comenzaron a marcar con rayos el búfer de profundidad para hacer reflexiones en el espacio de la pantalla, pero ningún juego que conozco utiliza el marcado de rayos en la forma en que lo describe, ¿todavía?

Para la otra pregunta sobre colores y tal, las personas comúnmente asocian materiales con objetos y usan "coordenadas de textura" del punto donde el rayo golpea el objeto para descubrir las propiedades del material en ese punto del objeto. Los materiales comunes incluyen cosas como color difuso, intensidad especular, color emisivo e índice de transparencia / refracción.

¡Espero que al menos te sirva de ayuda! También puede obtener buenas respuestas del sitio de intercambio de pila de gráficos.

Alan Wolfe
fuente
2
"no conozco ningún juego que utilice la marcha de rayos en la forma en que usted describe" El próximo juego de Media Molecule Dreams usa campos de distancia firmados para esculpir contenido generado por el usuario, pero si entiendo correctamente, los campos se convierten en una nube de puntos para renderizar en lugar de siendo raymarched directamente. Este artículo puede tener algunas ideas: dualshockers.com/2015/08/15/…
DMGregory
1
@DMGregory Niza, pero creo que esto no es estrictamente Ray Marching. Por lo tanto, el punto sigue siendo válido, los juegos generalmente no usan marcha de rayos.
concept3d
1
Actualización de este hilo: el próximo juego Claybook representa sus escenas usando rayos disparados a través de campos de distancia directamente , en lugar de convertirlos primero a geometría convencional. Entonces el "todavía?" parece haber sido confirmado dos años después. :)
DMGregory
1

Actualmente estoy desarrollando un motor de juego que utiliza campos de distancia firmados como una técnica de representación para mostrar una geometría de procedimiento uniforme (generada con primitivas simples como las de su enlace por el momento, buscando implementar fractales Julia e IFS en el futuro). Dado que mi motor está enfocado en la generación de procedimientos y debe definir las figuras de una manera que los haga amigables para los que marcan rayos, creo que estoy en un buen lugar para responder esta pregunta: P.

Con respecto a la transmisión, la solución simple es usar un búfer tipeado de algún tipo y tirarlo a la GPU cuando desee hacer su marcha de rayos. Cada elemento del búfer es un tipo complejo (por ejemplo, una estructura en C / C ++), y cada tipo contiene elementos que definen qué función debe usar para representarlo, su posición, rotación, escala, etc., y un color promedio. El proceso luego se simplifica a:

  1. Elimine su escena en un subconjunto manejable (tenga en cuenta que el sacrificio de frustum y la eliminación de oclusiones se realizan en parte de forma automática por el algoritmo de marcha de rayos de todos modos)
  2. Pase el subconjunto a su búfer de entrada de renderizado
  3. Pase el búfer a la GPU si aún no está allí, luego renderice su escena con la marcha de rayos tradicional. Tendrá que realizar algún tipo de búsqueda por paso para evaluar qué elemento en el búfer de entrada está más cerca de cada rayo para cada iteración del rayo-marcador, y deberá aplicar transformaciones a cualquiera de los rayos (en cuyo caso necesitará invertir las rotaciones de figuras antes de que lleguen a la GPU) o las funciones de distancia (mover el origen de la función para cambios de posición, ajustar, por ejemplo, longitudes de los lados cúbicos para cambios de escala, etc.) El enfoque más simple es modificar los rayos antes los pasa a la función de distancia real del núcleo.

Con respecto a los colores de las figuras, recuerde que los sombreadores le permiten definir tipos complejos y primitivos;). Eso le permite lanzar todo en una estructura de estilo C, luego pasar esas estructuras de su función de distancia.

En mi motor, cada estructura contiene una distancia, un color y una ID que lo vincula a la definición de figura correspondiente en el búfer de entrada. Cada ID se infiere del contexto circundante de la función de distancia relevante (dado que mi función de mapeo recorre el búfer de entrada para encontrar la figura más cercana a cada rayo para cada paso, puedo tratar con seguridad el valor del contador de bucle cuando se llama a cada SDF como la ID de la figura para esa función), mientras que los valores de distancia se definen utilizando un SDF de núcleo arbitrario (por ejemplo,point - figure.pos para una esfera), y los colores se definen a partir del color promedio del elemento apropiado en el búfer de la figura (por lo tanto, es útil mantener las ID de la figura alrededor) o mediante un color de procedimiento ponderado hacia el promedio almacenado (un ejemplo podría estar tomando un recuento de iteración para algún punto en el Mandelbulb, mapeando su "color promedio" desde el espacio de color FP al espacio de color entero, luego usando el color mapeado como una paleta XOR 'contra el recuento de iteración).

Las texturas de procedimiento son otro enfoque, pero nunca las he usado yo mismo. iq ha investigado bastante en esa área y ha publicado algunas demostraciones interesantes en Shadertoy, por lo que podría ser una forma de recopilar información adicional.

Independientemente de si su color es estático para cada figura, generado por procedimiento o muestreado mágicamente a partir de una textura de procedimiento, la lógica básica es la misma: las figuras abstractas en algún tipo de tipo complejo intermedio (por ejemplo, una estructura), almacenan tanto la distancia local como la local. color en una instancia de ese tipo, luego pase el tipo complejo como un valor de retorno de su función de distancia. Dependiendo de su implementación, el color de salida puede pasar directamente a la pantalla o seguir el punto de colisión en su código de iluminación.

No sé si lo anterior fue lo suficientemente claro o no, así que no se preocupe por preguntar si algo no tiene sentido. Realmente no puedo dar ninguna muestra de código GLSL / pixel-shading ya que estoy trabajando con HLSL y calcular el sombreado, pero estoy feliz de tratar de repasar todo lo que no escribí correctamente en primer lugar :).

Paul Ferris
fuente