¿Cómo organizan los motores de juegos comerciales los búferes de índice / vértice?

8

Prefacio: Esta pregunta vendrá desde un punto de vista Direct3D, porque eso es con lo que estoy familiarizado.

Obviamente incurrimos en una ligera sobrecarga cada vez que cambiamos los búferes de vértices o índices en Direct3D (es decir, con IASetIndexBuffer). Pero supongo que si asignamos un búfer de índice / vértice gigante, tendremos que administrar la memoria manualmente y terminar con un problema de fragmentación (o pausas mientras intercambiamos todos los datos).

Entonces, ¿cómo los motores comerciales cargan / descargan datos? Me estoy inclinando hacia un enfoque basado en 'paquete', por lo que un 'paquete' de modelos tiene su propio búfer de vértices / índices que podemos cargar / descargar ya que el paquete ya no es necesario; y luego intente dibujar todas las instancias del mismo paquete juntas.

Pero me interesaría saber cuál es la forma aceptada / estándar de manejar esto.

Xenoprimate
fuente
1
Esta es una buena pregunta y también se aplica a OpenGL.
glampert

Respuestas:

13

Existen varias técnicas diferentes para organizar los datos, y muchos juegos usan una combinación de ellas.

Para la geometría estática, es mejor tener menos IB y VB individuales.

Tradicionalmente, los juegos se basan en "niveles", lo que significa que los activos para una sección de juego se cargan y luego comienza el juego. Para minimizar los tiempos de carga, la información está idealmente organizada para soportar esto (es decir, cargar todo para el nivel lo más rápido posible sin buscar en el medio / disco), posiblemente replicando información entre niveles. En este enfoque, un esquema es tener un VB e IB grandes para un modelo o una serie de modelos, y luego enviar subconjuntos para dibujar.

Para la generación Xbox 360 / PS 3, la cantidad de RAM era bastante pequeña en relación con el tamaño de los juegos, por lo que los motores se orientaron a la 'transmisión', lo que significa que cargan contenido dinámicamente a medida que el jugador se mueve a través de ellos. Esto también se llama un enfoque de "mundo abierto". En este enfoque, el desafío es 'fragmentar' la geometría en bits que puede cargar en función de sugerencias espaciales. Otro desafío particularmente para las plataformas de 32 bits es garantizar que la memoria no se fragmente (o incluso la fragmentación del espacio de direcciones virtuales) durante un largo período de tiempo: los juegos basados ​​en niveles a menudo restablecen la memoria entre niveles, algo que los motores de transmisión no pueden hacer tan fácilmente Por lo tanto, es útil empacar en un tamaño fijo o un conjunto de tamaños fijos para los IB / VB que se asignaron y reutilizaron como grupo.

Para la generación Xbox One / PS 4, hay mucha RAM para trabajar en relación con las consolas anteriores, y muchos núcleos adicionales, por lo que muchos juegos están comprimiendo agresivamente sus activos y luego usan núcleos de CPU "extra" para descomprimirlos en el antecedentes. Con el espacio de direcciones virtuales de 64 bits, hay menos preocupación por la fragmentación del espacio de direcciones virtuales. Este enfoque mantiene bajos los tiempos de carga, empaqueta bien los activos para la descarga digital y es compatible con la representación de 'mundo abierto'. Aquí se utiliza el enfoque de grupo para gestionar IB / VB.

También hay una presentación de geometría dinámica que a menudo se usa para terrenos, modelos deformables / destructibles, etc. No es eficiente en términos de ancho de banda del bus GPU, por lo que los juegos a menudo tienen una mezcla de geometría estática y dinámica. En este caso, el patrón de actualización de Direct3D Map DISCARD generalmente significa que solo está utilizando un único IB / VB (o para escenarios de renderizado multiproceso, doble IB / VB que intercambia para rellenar / renderizar cada fotograma).

Chuck Walbourn
fuente
Gracias por tu respuesta. ¿Puedo hacer algunas preguntas aclaratorias? ¿Qué es el patrón Direct3D Map DISCARD?
Xenoprimate
1
El patrón se describe aquí para Direct3D 9 como Lock DISCARD, pero ese patrón se usa con Direct3D 10.x / 11.x, así como Map DISCARD para recursos dinámicos. Puede ver un ejemplo de cómo se implementa esto para Direct3D 11 mirando la clase PrimitiveBatch de DirectX Tool Kit .
Chuck Walbourn