He estado usando OpenGL durante un tiempo y he leído una gran cantidad de tutoriales. Además del hecho de que muchos de ellos todavía usan la tubería fija, generalmente arrojan toda la inicialización, los cambios de estado y el dibujo en un archivo fuente. Esto está bien para el alcance limitado de un tutorial, pero estoy teniendo dificultades para resolver cómo escalarlo a un juego completo.
¿Cómo divide su uso de OpenGL en los archivos? Conceptualmente, puedo ver los beneficios de tener, por ejemplo, una clase de renderizado que solo muestra cosas en la pantalla, pero ¿cómo funcionarían cosas como sombreadores y luces? ¿Debería tener clases separadas para cosas como luces y sombreadores?
c++
opengl
architecture
objects
Sullivan
fuente
fuente
Respuestas:
Creo que OO OpenGL no es tan necesario. Es diferente cuando se habla de sombreador, modelo, clase, etc.
Básicamente, primero harías la inicialización del juego / motor (y otras cosas). Luego, cargaría texturas, modelos y sombreadores en RAM (si es necesario) y objetos de almacenamiento intermedio, y cargaría / compilaría sombreadores. Después de eso, usted, en su estructura de datos o clase de sombreador, modelo, tiene ID int de sombreadores, modelo y objetos de búfer de textura.
Creo que la mayoría de los motores tienen componentes de motor y todos tienen ciertas interfaces. Todos los motores que he examinado tienen algún componente como Renderer o SceneManager o ambos (depende de la complejidad del juego / motor). De lo que puede tener la clase OpenGLRenderer y / o DXRenderer que implementan la interfaz Renderer. Luego, si tiene SceneManager y Renderer , puede hacer algunas de las siguientes cosas:
El procesador probablemente llamaría la función de dibujo del objeto, que llamaría la función de dibujo de cada malla que está compuesta y la malla uniría el objeto de textura, el sombreador de enlace, llamaría a la función de dibujo de OpenGL y luego no usaría sombreadores, objetos de búfer de datos de textura y objeto.
NOTA: este es solo un ejemplo, debe estudiar SceneManager con más detalle y analizar su caso de uso para ver cuál es la mejor opción de implementación
Por supuesto, tendría otros componentes del motor, como MemoryManager , ResourceLoader , etc., que se encargarían del uso de memoria de video y RAM, para que pudieran cargar / descargar ciertos modelos / sombreadores / texturas según sea necesario. Los conceptos para esto incluyen almacenamiento en memoria caché, mapeo de memoria, etc. Hay muchos detalles y conceptos sobre cada componente.
Eche un vistazo a una descripción más detallada de otros motores de juegos, hay muchos de ellos y su documentación está bastante disponible.
Pero sí, las clases hacen la vida más fácil; debe usarlos por completo y recordar sobre la encapsulación, la herencia, las interfaces y más cosas interesantes.
fuente
OpenGL ya tiene algunos conceptos de 'Objeto'.
Por ejemplo, cualquier cosa con una identificación puede pasar como un objeto (también hay cosas específicamente llamadas 'Objetos'). Búferes, texturas, objetos de búfer de vértices, objetos de matriz de vértices, objetos de búfer de marco, etc. Con un poco de trabajo puedes envolver clases alrededor de ellos. También le brinda una manera fácil de recurrir a las antiguas funciones de OpenGL en desuso si su contexto no admite las extensiones. Por ejemplo, un VertexBufferObject podría recurrir al uso de glBegin (), glVertex3f (), etc.
Hay algunas formas en que puede necesitar alejarse de los conceptos tradicionales de OpenGL, por ejemplo, probablemente desee almacenar metadatos sobre los búferes en los objetos de búfer. Por ejemplo, si el búfer almacena vértices. ¿Cuál es el formato de los vértices (es decir, posición, normales, códigos de texto, etc.)? Qué primitivas usa (GL_TRIANGLES, GL_TRIANGLESTRIP, etc.), información de tamaño (cuántos flotadores están almacenados, cuántos triángulos representan, etc.). Solo para facilitar su conexión a los comandos de arrays de arrays.
Te recomiendo que mires OGLplus . Son enlaces de C ++ para OpenGL.
También glxx , eso es solo para la carga de extensión.
Además de envolver la API de OpenGL, debería considerar hacer una compilación de un nivel ligeramente superior por encima.
Por ejemplo, una clase de administrador de materiales que es responsable de todos sus sombreadores, cargarlos y usarlos. También sería responsable de transferirles propiedades. De esa manera puede llamar a: materials.usePhong (); material.setTexture (alguna textura); material.setColor (). Esto permite una mayor flexibilidad, ya que puede usar cosas más nuevas, como objetos de almacenamiento intermedio uniformes compartidos para tener solo 1 gran almacenamiento intermedio que contenga todas las propiedades que usan sus sombreadores en 1 bloque, pero si no es compatible, recurra a la carga en cada programa de sombreador. Puede tener 1 sombreador monolítico grande e intercambiar entre diferentes modelos de sombreador usando rutinas uniformes si es compatible o puede recurrir a usar un montón de sombreadores pequeños diferentes.
También puede ver cómo gastar en las especificaciones GLSL para escribir su código de sombreador. Por ejemplo, #include sería increíblemente útil y muy fácil de implementar en el código de carga de su sombreador (también tiene una extensión ARB ). También puede generar su código sobre la marcha en función de qué extensiones son compatibles, por ejemplo, use un objeto uniforme compartido o recurra al uso de uniformes normales.
Finalmente, querrá una API de canalización de representación de nivel superior que haga cosas como gráficos de escenas, efectos especiales (desenfoque, brillo), cosas que requieren múltiples pases de representación como sombras, iluminación y demás. Y además, una API de juego que no tiene nada que ver con la API de gráficos, sino que solo trata con objetos en un mundo.
fuente
oglplus::Context
clase hace que esta dependencia sea muy visible: ¿sería un problema? Creo que ayudará a los nuevos usuarios de OpenGL a evitar muchos problemas.En OpenGL moderno, puede separar casi por completo los objetos renderizados entre sí, utilizando diferentes vaos y programas de sombreado. E incluso la implementación de un objeto se puede separar en muchas capas de abstracción.
Por ejemplo, si desea implementar un terreno, puede definir un TerrainMesh cuyo constructor crea los vértices e índices para el terreno, y los establece en búferes de matriz y, si le da una posición de atributo, el sombreador pliega sus datos. También debe saber cómo representarlo, y debe tener cuidado de revertir todos los cambios de contexto que ha realizado para configurar el renderizado. Esta clase en sí misma no debe saber nada sobre el programa de sombreado que lo va a representar, y tampoco debe saber nada sobre ningún otro objeto en la escena. Por encima de esta clase, podría definir un terreno, que conoce el código del sombreador, y su trabajo es crear la conexión entre el sombreador y TerrainMesh. Esto debería significar obtener atributos y posiciones uniformes y cargar texturas, y cosas así. Esta clase no debería saber nada sobre cómo se implementa el terreno, qué algoritmo LoD usa, solo es responsable de sombrear el terreno. Por encima de esto, podría definir la funcionalidad que no es OpenGL como comportamiento y detección de colisiones, etc.
Llegando al punto, a pesar de que OpenGL está diseñado para usarse a bajo nivel, aún puede construir capas independientes de abstracción, que le permiten escalar a aplicaciones con un tamaño de un juego irreal. Pero la cantidad de capas que desea / necesita realmente depende del tamaño de la aplicación que desea.
Pero no se mienta acerca de este tamaño, no intente imitar el modelo de objetos de Unity en una aplicación de línea de 10k, el resultado será un completo desastre. Construya las capas gradualmente, solo aumente el número de capas de abstracción, cuando sea necesario.
fuente
ioDoom3 es probablemente un excelente punto de partida, ya que puede confiar en Carmack para seguir una excelente práctica de codificación. También creo que él no usa texturas megate en Doom3, por lo que es relativamente sencillo como una tubería de renderizado.
fuente