Polls

Cuantas horas programas al día?
 
Inicio arrow Tutoriales arrow General arrow Diseño de un motor 3d moderno: El Driver Gráfico
Diseño de un motor 3d moderno: El Driver Gráfico PDF Print E-mail
Written by Javier Loureiro   
Sunday, 30 March 2008

El Driver Gráfico


El driver gráfico es la clase que se encarga de pintar objetos en bruto en pantalla. Su tarea es la de abstraer el API que usemos para pintar (opengl/directx/consola) de nuestro programa, y pintar de la forma más rápida posible. El termino puede ser confuso, pero motores como el unreal o el irrlich usan ese termino para esta fase del motor.

Para mí, esta seria la primera tarea que se debería de afrontar a la hora de trabajar un motor 3D. Nuestra entrada será una (o varias) listas ordenada de objetos con sus propiedades, y un estado global de las propiedades de render. Podemos comenzar con una lista ordenada "a mano", e ir desarrollando un potente driver gráfico a nuestro gusto.

Cada objeto debe de representar su definición completa. Quiere decir que un objeto debe de tener toda la información necesaria para ser pintado, sin esperar heredar estados de instancias superiores. Esto es fundamental en una tarjeta moderna.

El driver grafico es donde se generaliza el acceso a DirectX/OpenGL o a las consolas. Por eso debemos de tener cuidado a lo que dejamos activar por el usuario. Lo ideal es activar el "concepto" de shader, o el "concepto de efecto", y que cada driver active lo necesario para pintar ese efecto, sin permitir desde fuera el cambiar estados "atómicos" de renderizado. Pero realmente... ¿Que significa esto?

Para mantener compatibilidad, y que nuestro motor sea mas fácilmente optimizable, las propiedades del material deberían de huir del bajo nivel (ya que precisamente para eso escribimos un driver gráfico). Hay que escapar de cosas como activar flags en el API (como activar, por ejemplo, el test de profundidad o un modo alpha concreto). Lo ideal es que tengamos estados de un nivel superior, como "activar sombras suaves", "activar mapas de normales", "activar material", etc. Que es una llamada de bajo nivel, y que es una llamada de alto nivel os corresponde decidirlo a vosotros, y es una de las decisiones donde podréis sacarle mas partido a vuestro motor, y aquí podéis mejorar muchas cosas segun tengais efectos nuevos que requieran un control mas fino. La idea es que un estado de alto nivel puede agrupar una serie larga de llamadas al driver grafico, es "multiplataforma", y debe de tener sentido en distintas versiones de las API's. Por ejemplo, activar una característica SM3.0 no debería de ser parte del driver, pero si algo como "activar especular" que es una función mas general. El trabajo del driver sera decidir que es "activar especular" en función de hardware donde estemos ejecutando.

A nivel tarjeta, debemos de tener en cuenta que podemos tener varios "targets" de render. Esto es, a veces pintaremos en una textura, o en el framebuffer directamente. Nuestro codigo deberia de tener esto en cuenta a la hora de generalizar las llamadas.

En cuanto a la velocidad, es muy importante que no enviemos muchas llamadas al drivers, para que la tarjeta no tenga que cambiar su estado, o lo cambie lo mínimo posible. Por ello deberemos de tener todo ordenado por shader (para minimizar los cambios de shader). Se suele tener el buffer relleno con algo ya al principio, para minimizar el repintado en profundidad, por ejemplo, pintando el fondo antes que la escena.

El driver debería de tener una "render cache", que es la parte que optimiza las llamadas al API. Así, si tenemos varios objetos, y todos tienen el estado de "activar sombras suaves", nuestro driver debería de realizar las llamadas de tarjeta iniciales para configurar el hardware la primera vez, pero las siguientes llamadas tienen que detectar que todo esta ya activado, para ahorrar los cambios de estado de tarjeta, que en medio de un frame son muy costosos en tiempo. El paso previo a invocar las llamadas al driver gráfico, fue precisamente crear listas ordenadas para minimizar estos cambios de estado en la tarjeta. De todos modos, si la lista esta desordenada, deberíamos de pintarlo igual, ya que quizás el efecto precise por algún motivo actuar de esa forma. Hay que primar la funcionalidad antes que el rendimiento, pero al llamar a nuestro propio driver gráfico, debemos de hacerlo de la forma optima, como en cualquier otro software.

El mismo driver gráfico debería de gestionar correctamente las texturas. Conocer cuantas estan enviadas al driver, gestionar los identificadores de bajo nivel y su correspondiente identificador de alto nivel, y decidir que algoritmo utilizar para reemplazar las subidas, etc.

Hoy en dia todos los drivers soportan arrays de vértices, así que debemos de generalizar a ese nivel. A veces enviamos demasiada geometria a los buffers de vértices (quizás el efecto o la escena requieran algo asi). El driver gráfico debe de manejar algún sistema de cache para descartar la geometría, por ejemplo usando un algoritmo LRU (least recent used), ahorrando así descargas innecesarias.

Hay veces que necesitamos pintar en órdenes concretos, por ejemplo, para transparencias. En este caso pintamos primero lo que no es transparente, y después lo que es transparente. Debemos de pensar como definir este tipo de propiedades, teniendo en cuenta que quizás cambiemos todo esto de forma global (activando el wireframe, o el shadow map).

Enviar las escenas a tarjeta para que posteriormente el API las pinte se denomina "modo retain". Pero es importante que el driver gráfico nos permita pintar en "modo inmediato". Esto es, pintar un triángulo suelto. Esto es importante porque quizá tengamos que hacer cosas con el GUI o pintar algo para un tema en concreto.

También es posible que usemos varias listas para los distintos pases. Por ejemplo, un material del scenegraph, después se traduce en varios shaders, y puede que estos se pinten en distintos pases. Un material "piel de fruta" es un poco difuso, y un poco especular, pero el material "tela" es totalmente difuso. Asi que durante la visita del scenegraph, incluiremos los objetos con algún shader difuso en la lista de "pase difuso" y los objetos con algún componente especular en la lista "pase especular". Así en ese pase no pintaremos los objetos de "tela" y nuestro pase sera mas rápido.

El nombre driver grafico es propio. No todos los motores lo denominan así, pero es un nombre que indica "bajo nivel", aunque esta por encima del API de la tarjeta. Quizás al modo de llamar la tarjeta deberiamos de llamarle API. El driver gráfico llama a la tarjeta, pero no tiene que hacer eso exclusivamente. Incluso si nuestro motor fuese de software, aquí seria donde lo implementaríamos todo.

El driver grafico debe de tener funcionalidad para:

  • Pintar geometría (usando vertex buffers)

  • Activar/desactivar texturas

  • Activar/desactivar materiales

  • Gestión de texturas en memoria

  • Gestión de Luces

  • Enviar la geometría a los buffers de objetos

  • Cambiar las propiedades de todos los objetos para rendear shadow maps o modo wireframe

  • Rendear en distintos targets

  • Componer pases de renderizado (difuso/especular)

  • Gestionar sobras

  • Permitir pintar en modo inmediato (esto nos obliga a implementar bastantes llamadas a las API´s)

El driver gráfico NO debería de tener funciones para:

  • Llamadas directas al API (esto os obliga a hacer un wrapper de todo el API)

  • Depender de estados "heredados" en los objetos

  • Ocuparse de las dependencias de lo que vamos a pintar

  • Físicas/Inteligencia de los objetos

  • User Interface y eventos de teclado/ratón

Referencias

 http://entland.homelinux.com/blog/2008/03/03/implementing-a-graphic-driver-abstraction/

 

This e-mail address is being protected from spam bots, you need JavaScript enabled to view it  

 

blog  Jesús de Santos

 

blog de Iñigo Quilez

 

 

Comentarios
Añadir nuevoBuscar
Rubén Penalva     | 212.0.110.xxx | 2008-04-02 16:58:05
Hi,
vaya, se me acumula el trabajo! tengo las notas del anterior articulo en sucio y ya habeis puesto otro.... :P A ver si puedo postearlas antes de que pase 1 año..... ^^U

Sería interesante (bueno mejor dicho, seria ya la leche! :P) que pusieseis ejemplos de casos reales del diseño que proponeis. Ayudaria bastante a facilitar la comprension de los conceptos que planteais, ya que no son para nada triviales. Por supuesto que las transparencias del articulo de referencia de Jesus son vitales, pero aun asi un ejemplillo de fuego real no vendria mal.

Por cierto hay una cosa que no llego a ver del todo sobre lo de tener estados de alto nivel en el driver. Comprendo el concepto que proponen arquitecturas como las de Frostbite u Offset Engine, pero no veo claro que haya que situarlo en el driver y no en una capa por encima de este.

Un saludo,
Rubén Penalva
Mimestim   | 84.79.161.xxx | 2008-04-02 19:41:34
Hola, de nuevo gracias por la serie de artículos, ya me he leido ambos. Saludos.
Gabriel   | 83.35.135.xxx | 2008-04-04 10:43:11
"Gestionar sobras" (??)

Gracias por los articulos.
- programaciongrafica - re:     | 195.235.227.xxx | 2008-04-21 10:25:26
Hola Gabriel, a ver si te sirve este ejemplo real: http://usuarios.lycos.es/programaciongrafica/modules.php?name=News&file=article&sid=4&mode=&order=0&thold=0

Corresponde a una serie de tutoriales que estoy desarrollando (no sé si bien o mal) pero con la idea de que sirvan de ayuda para la gente que se inicia.

Saludos.

Rubén Penalva escribió:
Hi,
vaya, se me acumula el trabajo! tengo las notas del anterior articulo en sucio y ya habeis puesto otro.... :P A ver si puedo postearlas antes de que pase 1 año..... ^^U

Sería interesante (bueno mejor dicho, seria ya la leche! :P) que pusieseis ejemplos de casos reales del diseño que proponeis. Ayudaria bastante a facilitar la comprension de los conceptos que planteais, ya que no son para nada triviales. Por supuesto que las transparencias del articulo de referencia de Jesus son vitales, pero aun asi un ejemplillo de fuego real no vendria mal.

Por cierto hay una cosa que no llego a ver del todo sobre lo de tener estados de alto nivel en el driver. Comprendo el concepto que proponen arquitecturas como las de Frostbite u Offset Engine, pero no veo claro que haya que situarlo en el driver y no en una capa por encima de este.

Un saludo,
Rubén Penalva
- programaciongrafica - re: re:   | 195.235.227.xxx | 2008-04-21 10:37:11
Perdón,puse Gabriel, era a Rubén Penalva al que quería contestar.

Saludos.
Escribir comentario
Nombre:
Email:
 
Website:
Título:
Código UBB:
[b] [i] [u] [url] [quote] [code] [img] 
 
Security Image
Por favor introduce el código anti-spam que puedes leer en la imagen.

Copyright (C) 2007 Alain Georgette / Copyright (C) 2006 Frantisek Hliva. All rights reserved.



menéameDigg!Del.icio.us!Google!Technorati!Yahoo!
Last Updated ( Wednesday, 02 April 2008 )
 
< Prev   Next >

Lista de Correo

visita la lista de correo de codepixel. Es una lista abierta, asi que podrás subscribirte y preguntar tus dudas de programación, compartir tus opiniones, aportar ideas, y formar parte de la comunidad codepixelera.