Estaba aprendiendo OpenGL recientemente. En los juegos, necesitamos actualizar la posición de los objetos del juego con frecuencia, y entrarán y saldrán de la pantalla constantemente. Por lo tanto, significa que al renderizar también necesitamos actualizar el búfer de vértices con bastante frecuencia.
En el contexto de OpenGL, una forma intuitiva es usar glBufferSubData para actualizar los que han cambiado.
Pero también leí en línea un truco llamado Orphaning que crea una nueva información de búfer y le subo toda la información de vértices.
También debido al costo de los cambios de estado y el costo de carga, múltiples glBufferSubData también pueden costar más.
Aquí está mi pregunta
- ¿Qué método es mejor?
- ¿Los puestos realmente importan en este caso?
- ¿Los cambios de estado y el costo de carga realmente son importantes en este caso?
¡Gracias!
opengl
rendering
optimization
vbo
YiFeng
fuente
fuente
Respuestas:
Esta es una pregunta compleja con muchos pequeños detalles que realmente importan, el rendimiento variará según la plataforma y la aplicación. Por lo tanto, debe hacer un perfil de posibles cuellos de botella antes de invertir en optimizaciones.
Dicho esto, en primer lugar, supongo que debe reducir las cargas y actualizaciones tanto como pueda, por ejemplo, usar instancias.
En segundo lugar, tenga en cuenta que las GPU no pueden transferir buffers y renderizar al mismo tiempo, por lo que el dispositivo procesa secuencialmente todos los comandos de OpenGL en la cola de comandos. Existen diferentes formas de copiar datos y / o hacer que estén disponibles para que la GPU los use.
Hay varias formas de transmitir datos a la GPU
1-
glBufferData
oglBufferSubData
métodoUsar
glBufferData
oglBufferSubData
es como memcpy. se pasa un puntero y se puede realizar una operación DMA , dije que podría porque la memoria podría estar anclada en la memoria de la CPU y utilizada directamente por la GPU sin que realmente se produzca una transferencia de memoria a la GPU, dependiendo del indicador de uso (GL_STREAM). En opinión, deberías probar esto al principio porque es más sencillo de implementar.2- obtener un puntero a la memoria interna usando
glMapBuffer
Si lo anterior no es lo suficientemente bueno que puede usar
glMapBuffer
, obtiene un puntero a la memoria interna, y puede usar este puntero para llenar el búfer directamente, esto es bueno con las operaciones de lectura y escritura de archivos, ya que puede asignar directamente los datos del archivo a la memoria de la GPU en lugar de copiar primero a un búfer temporal. Si no desea mapear todo el búfer, puede usarloglMapBufferRange
para mapear una parte del búfer.Un truco es crear un búfer grande, usar la primera mitad para renderizar y la segunda mitad para actualizar.
3- Huérfano de búfer
Con respecto a la huérfana del búfer, esto se puede hacer usando glBufferData con nulo y los mismos parámetros que tenía. El controlador devolverá el bloque de memoria una vez que no se use. Y será utilizado por la próxima llamada glBufferData (no se asignará memoria nueva).
Todos los métodos mencionados causan una gran cantidad de sincronización costosa, nuevamente las GPU no pueden transferir buffers y renderizar al mismo tiempo.
4-
Unsynchronized Buffers
El método más rápido (y el más difícil de acertar) es usar buffers sin sincronización con los que puede usar el
GL_MAP_UNSYNCHRONIZED_BIT
indicadorglMapBufferRange
, el problema es que no se realiza la sincronización, por lo que podríamos cargar datos en un buffer comenzar a usar, y por lo tanto arruinar todo. Puede usar múltiples buffers con bit de sincronización para facilitar un poco las cosas.fuente
Lo hago de otra manera. Puede haber algo mal allí. Algunas cosas peligrosas ocultas.
(Yo uso C # + OpenTK.GameWindow)
Para la creación de instancias del objeto, uso un Array Buffer Object separado para el conjunto de matrices modelo para cada instancia. En el vértice compartido:
En mi código C #, las matrices se almacenan en una matriz flotante
float[] mat4_array
Luego, ato la matriz al Array Buffer Object:
Cada cuadro se actualizan las matrices del modelo. Para actualizar
mat4_array
solo llamo:y renderizar la escena. utilizando
GL.DrawElementsInstanced
.No hay llamadas adicionales de OpenGL y funciona perfectamente.
fuente