Gráfico de escena para motor de renderizado diferido

10

Como ejercicio de aprendizaje, he escrito un motor de renderizado diferido. Ahora me gustaría agregar un gráfico de escena a este motor, pero estoy un poco desconcertado sobre cómo hacerlo.

En un motor de renderizado normal (normal), simplemente agregaría todos los elementos (todos implementando IDrawable e IUpdateAble) a mi gráfico de escena, que viajar primero por la amplitud del gráfico de escena y llamar a Draw () a todas partes.

Sin embargo, en un motor de renderizado diferido, tengo que separar las llamadas de extracción. Primero tengo que dibujar la geometría, luego las ruedas de sombra y luego las luces (todas para diferentes objetivos de renderizado), antes de combinarlas todas. Entonces, en este caso, no puedo simplemente recorrer el gráfico de la escena y simplemente llamar a dibujar. De la forma en que lo veo, tengo que viajar por todo el gráfico de la escena 3 veces, verificando qué tipo de objeto es el que debe dibujarse, o tengo que crear 3 gráficos de escena separados que de alguna manera están conectados entre sí. Ambas parecen soluciones pobres, me gustaría manejar los objetos de escena más transparentes.

Otra solución que he pensado fue viajar a través del gráfico de la escena como normal y agregar elementos a 3 listas separadas, separar la geometría, las ruedas de sombra y las luces, y luego iterar estas listas para dibujar las cosas correctas, es esto mejor, y ¿es ¿Es prudente repoblar 3 listas en cada cuadro?

Roy T.
fuente

Respuestas:

6

Un enfoque que he usado en un proyecto de C ++ es que el gráfico de escena (que tiene el índice espacial) llena un vector 'visible' std :: de hits basado en el tronco de visualización actual. Esta lista visible es administrada por el gráfico de escena, por lo que solo se recalcula cuando la cámara se mueve: los objetos en movimiento en el gráfico se mueven en esta lista y usan lápidas y listas de cambios sin clasificar que se ordenan y fusionan de nuevo según sea necesario.

La lista de elementos visibles se ordena primero por ID de sombreador y dentro de cada tipo por distancia desde la cámara. Las ID del sombreador se asignan de tal manera que el terreno primero ordena y luego los edificios y luego las unidades y luego los proyectiles y luego las partículas, etc., siendo un RTS. Algunos modelos tienen más de un sombreador, pero solo anuncian su sombreador principal. Cuando se les pide que dibujen, aquellos que necesitan bits dibujados con otro sombreador también se agregan a una lista enlazada de un solo paso.

Entonces, el dibujo pasa por la matriz visible en una pasada, y en esa pasada se crea una lista vinculada de esos elementos para volver a visitar, y se dibuja una segunda pasada y así sucesivamente.

Dibujar de adelante hacia atrás y opaco y luego transparente ayuda a mantener todo cuerdo.

Quizás esto no esté minimizando la cantidad de cambios de sombreador, etc. pero es bastante factible y sencillo de implementar.

No tengo idea sobre XNA y cuán aplicable es esto y cuánto de estas cosas de bajo nivel que creas, me temo. Sin embargo, sería muy interesante saber qué piensan los veteranos de este enfoque para los RTS de C ++.

Será
fuente
Hola Will, me gusta mucho esta respuesta, especialmente porque es totalmente diferente de lo que he pensado hasta ahora. Su método parece muy cuerdo, especialmente cuando también piensa en objetos semitransparentes (que en su mayoría he evitado hasta ahora). Construir una lista (vinculada) de su gráfico de escena para los objetos a visitar parece una muy buena idea. Y sí, en XNA también tenemos que hacer todas estas cosas de bajo nivel :).
Roy T.
3

Mi sugerencia sería un enfoque de 2 pasos adaptado a sus requisitos específicos, similar a lo que usted mismo describió. Necesita un gráfico de escena y una "colección de renderizado" para cada uno de los pasos de renderizado, en su caso sombra, geometría, luces (¿quizás un cuarto sean objetos transparentes?)

El gráfico de escena se puede basar en cualquier tipo de relaciones, pero mi preferencia personal se basaría en relaciones espaciales donde cada nodo puede contener los otros nodos para facilitar el sacrificio rápido.

Las colecciones de render pueden ser cualquier tipo de estructura de datos adaptada al paso específico. Por ejemplo, la colección de sombras podría ser una lista o un árbol ordenado por profundidad para maximizar el rechazo temprano de z. La colección de geometría podría clasificarse según el uso del sombreador para minimizar los cambios de sombreado (estado). La colección de luces podría ser una lista o un árbol ordenados por distancia de luz, tamaño o una combinación de ellos, de modo que pueda limitar el renderizado de luz a solo las luces más efectivas si el rendimiento es un problema.

Independientemente de las estructuras de datos que elija, asegúrese de que la operación de inserción sea rápida y asegúrese de que use la agrupación y otras técnicas para eliminar cualquier asignación / destrucción de datos porque va a borrar y completar estas listas en cada cuadro.

Ahora unir todo es fácil. Simplemente recorra el gráfico de la escena y agregue cada elemento a las colecciones de renderizado relevantes. Ayuda si su estructura de datos ordena / estructura automáticamente nuevas entradas en función de los requisitos. Cuando haya terminado, revise las colecciones de render en el orden requerido y renderícelas.

Debido a que sus estructuras de datos tienen una inserción rápida y no generan basura, no hay penalización por repoblar listas como usted mencionó.

Mercado
fuente