2010-09-12 17 views
5

Estaba leyendo sobre la creación de gráficos de "capas de abstracción" para hacer que sea conveniente cambiar entre plataformas de gráficos. Lamentablemente, no he podido encontrar muchos detalles sobre el tema. ¿Es esta abstracción alcanzable en el nivel de función con algo como esto?Cómo diseñar una "capa de abstracción" de OpenGL DirectX

void pushMatrix(){ 
    if (directx){ 
    // do directx function 

    }else if (opengl){ 
    // do opengl function 
    } 

} 

¿Es así como funciona? ¿Hay una mejor manera? ¿Alguien puede señalarme algunos ejemplos de cosas que hacen esto o más código de ejemplo?

+2

Posiblemente el mejor ejemplo de esto es OGRE. Utiliza módulos para abstraer DirectX y OpenGL en una forma interna uniforme. Hay un montón de código, pero funciona bastante bien, por lo que es posible que desee comprobarlo. – ssube

+0

Gracias por la información. –

Respuesta

7

Lo que se suele hacer es tener una interfaz con un procesador de "genérico":

class RendererInterface{ 
    virtual DrawMesh() = 0; 
    virtual SwapBuffers() = 0; 
    /// etc 
} 

con una implementación para cada lib:

class OpenGLRenderer : public RendererInterface{ 
    virtual DrawMesh(){... } 
    .... 
} 

pero el concepto es el mismo que la respuesta de Alexander .

3

Eso terminaría desordenado e ineficiente. Me gustaría abstraer a través de un gráfico de escena, es decir, tener una representación generalizada de alto nivel de la "escena". Esta escena sería renderizada por una instancia de "renderizador", que podría implementarse usando OpenGL o Direct3D.

Le sugiero que eche un vistazo a un motor de gráficos multiplataforma como Ogre3d.

+0

Hmm que parece bastante ineficiente al ver cómo tendría que volver a escribir la mayoría de mis clases, pero entiendo lo que quiere decir con tener funciones/clases de nivel superior. –

+1

El problema con su método es que agregará una tonelada de ramas innecesarias y dispersará las diferentes implementaciones en todo su código. Se pone peor si tiene que escribir en más de 2 API: considere Direct3D 9, Direct3D 10/11, OpenGL 2.x, OpenGL 3/4, OpenGL ES 1, OpenGL ES 2, Playstation, Wii, etc. Resumiendo la ruptura la lógica de representación en piezas separadas se vuelve mucho más fácil de mantener. –

+1

También puede usar la herencia para compartir lógica entre representadores similares, p. Ej. Renderer es subclasificado por Direct3DRenderer y OpenGLRenderer, OpenGLRenderer está subclasificado por OpenGLES2Renderer, etc. –

4

Sí, así es como funciona. Al abstraer la API de gráficos que utiliza, la está eliminando de lo que el programador debe preocuparse. Esto es similar a la forma en que GDI abstrae el dispositivo en el que se escribe, por ejemplo, que el programador no necesita preocuparse por ello.

En este sentido, su biblioteca de funciones similar a la anterior sería como la HDC. Es la interfaz de esta abstracción.

Sería más difícil que una simple comprobación de API, y luego llamar a la (s) función (es) apropiada (s). Las dos API (DirectX y OpenGL) son muy diferentes, y no sería fácil resumirlas en una única interfaz, especialmente si desea cubrir la mayor parte de la funcionalidad.

Necesitarás más abstracción que simplemente funciones universales. Necesitarías crear estructuras más complejas.

Digamos hipotéticamente que OpenGL requirió que llamara a la función A, luego la función B para que algo sucediera, pero DX requirió que llamara al func B, luego al func A. Para acomodar esto, necesitaría hacer algo similar a esto:

void functionA(...) { 
    if (OpenGL) { 
    glFuncA(); 
    } else { 
    //store parameters 
    } 
} 

void functionB(...) { 
    if (OpenGL) { 
    glFuncB(); 
    } else { 
    dxFuncB(); 
    dxFuncA(saved params); 
    } 
} 

No es un muy buen ejemplo, pero demuestra el principal. Crear una abstracción para API muy grandes y diferentes requeriría mucho pensamiento, y mucho más esfuerzo luego de envolver cada función.

+0

¿Qué tal cosas como OpenGL a OpenGL ES 2.0? –

+0

@Justin: OpenGL a OpenGL ES es un cambio mucho más pequeño. DirectX y OpenGL son fundamentalmente diferentes, OpenGL y OpenGL ES son muy similares (comparados). Eso podría ser posible solo con bloques 'if else'. – ssube

+0

@peachykeen Ok gracias, eso era lo que estaba planeando hacer. –

1

Estoy de acuerdo con mhutch 100%. Al reestructurar su renderizador para enfocarse en QUÉ está haciendo, en lugar de en CÓMO hacerlo, hará un diseño mucho más limpio.

Diseñar alrededor de una API muy de cerca o, lo que es peor, ensuciar su código con if (this_platform) { do_this(); } else { do_that(); } hará que el programa se vuelva un desastre.

Mi consejo es ir a través de su aplicación y averiguar una lista de lo que hace, trate de no prestar mucha atención a CÓMO.Puede ser que sea tarde en su proyecto para hacer esto, no conozco su escenario específico, pero (en mi humilde opinión) refactorizarlo desde una pesadilla llena de llamadas API a algo que lo resuma lo suficiente mejorará su resultado final.

Aunque a primera vista, podría pensar que la implementación de un sistema de gráficos de escenas agregaría un montón de sobrecarga. En realidad, obtuve mayores aceleraciones con mi motor de renderizado usando el gráfico de escena para administrar cambios de estado, evitando cambios de estado (cambiando texturas, cambiando sombreadores, etc.) y dibujando la escena en un orden mucho más óptimo. Cosas como la creación de instancias están elegantemente integradas en un sistema de gráficos de escena y pueden darte importantes aceleraciones, así como limpiar todo el desorden centrado en API de tu código y separar el "qué es lo que hace" del "cómo lo hace" en tu principal lógica de programa.

Cuestiones relacionadas