Sie sind auf Seite 1von 41

TRABAJO DE INFORMÁTICA GRÁFICAS 2006/2007

UNIVERSIDAD DE SALAMANCA

INTRODUCCIÓN A DIRECT3D

VÍCTOR ROLDÁN BETANCORT

RAÚL SÁNCHEZ RUIZ


ÍNDICE

1. HISTORIA ........................................................................................................................1

2. HAL & COM ....................................................................................................................4

2.1. HARDWARE ABSTRACTION LAYER (HAL)................................................................... 4

2.2. COMPONENT OBJECT MODEL (COM) ...................................................................... 6

3. PRINCIPIOS DE LA PROGRAMACIÓN DE GRÁFICOS EN DIRECT3D ...................................8

4. ARQUITECTURA: LA TUBERÍA DE DIRECT3D (DIRECT3D-PIPELINE) ...........................10

5. TUBERÍA DE TRANSFORMACIONES ................................................................................12

6. TRANSFORMACIONES DEL MUNDO ...............................................................................14

7. TRANSFORMACIONES DE VISTA ...................................................................................17

8. TRANSFORMACIONES DE LA PROYECCIÓN ...................................................................18

9. PUERTO DE VISTA (VIEWPORTS) ..................................................................................20

10. DISPOSITIVOS DE DIRECT3D ......................................................................................22

11. BUFFERS DE VERTICES (VERTEX BUFFERS)................................................................26

12. RENDERIZAR UNA ESCENA A PARTIR DE UN BUFFER DE VÉRTICES ...............................29

13. DIBUJAR A PARTIR DE UN BUFFER DE ÍNDICES (INDEX BUFFER)...............................32

14. CONCLUSIÓN FINAL Y COMPARATIVA ENTRE DIRECT3D Y OPENGL .........................34

15. BIBLIOGRAFÍA ............................................................................................................38


INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

1. HISTORIA

Direct3D es el API (Application Programming Interface) de programación de


gráficos 3D perteneciente a la familia DirectX. Su historia se remonta mediados de la
década de los 90 con la aparición del sistema operativo Microsoft Windows 95. Durante
esa época, la mayoría de los juegos se desarrollaban bajo DOS y a Microsoft le
interesaba enormemente “enganchar” a ese amplio sector de la informática que son los
videojuegos a su nuevo proyecto, y así hacer mucho más famoso su sistema operativo.
Sin embargo, Windows 95 ofrecía demasiadas complicaciones para los programadores
de juegos: existía un gran número de capas de abstracción al hardware de audio y video
que limitaban enormemente su uso, además de ralentizarlo. El acceso directo que DOS
garantizaba también tenia sus propias complicaciones, pero a pesar de ello, dejaban a su
alcance acceso total al hardware de audio y video, lo cual llevó a los desarrolladores a
escribir complejos códigos para lograr una buena consistencia para todas las
configuraciones de PC, y a continuar trabajando bajo DOS.

En vista de esta situación, Microsoft se planteó la posibilidad de desarrollar un


interfaz que permitiese a los desarrolladores de juegos un mejor acceso al hardware para
así permitir que los juegos se ejecutasen a una velocidad aceptable, y proporcionase una
abstracción del hardware subyacente que tanto complicaba el desarrollo de los juegos.

Pero en lugar de desarrollar su propia API desde cero, Microsoft hizo un astuto
movimiento, y es que si Bill Gates es bien conocido es por su gran capacidad como
empresario, no siendo la primera vez en la historia de la empresa en que se lleva a cabo
algo similar: Microsoft adquirió un motor 3D en desarrollo y lo integró en DirectX.

Durante la década de los 90, una importante parte de los motores 3D para ordenador
se desarrollaban en Gran Bretaña. Cabe destacar empresas como RenderWare, Argonaut
y su conocidísimo motor “BRender” (el cual fue portado en 1994 al sistema operativo
OS/2) u otras como la pequeña empresa RenderMorphics. Esta última fue fundada en
1993 por Servan Keondjian, Kate Seekings y Doug Rabson, y fueron los responsables
del desarrollo de un producto denominado “Reality Lab”. Fue Keondjian quien
desarrollo el motor durante el día mientras tocaba el piano en una banda durante la
noche. Mientras tanto, Seekings obtuvo un master en gráficos por computador en la
universidad de Middlesex, presentando como proyecto la librería 3D desarrollada por el
equipo, y que curiosamente suspendió por no haberse ceñido a las especificaciones del
mismo. RenderMorphics había integrado Reality Lab en su “Game SDK”, y confiaban
en que tendría gran aceptación entre los desarrolladores de juegos, y no se equivocaron.
Durante la presentación de su SDK en 1994 en “SIGGRAPH94”, Microsoft presenció el
evento, finalmente adquiriendo la empresa en Febrero de 1995.

Tras la adquisición de RenderMorphics, Microsoft integró Reality Lab en su familia


de APIs DirectX. Una determinada parte de los componentes de Reality Lab fueron
transformados al estándar de API 3D de Windows en ese momento, el “3-D-DDI”, que
fue desarrollado por Michael Abrash, que posteriormente ayudo a John Carmack a
desarrollar el revolucionario motor de juego “Quake” de ID Software.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


-1-
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

DirectX 1.0 no fue nada aceptado, era muy lento, mal estructurado, muy complejo e
incluso con muchos fallos de programación. La siguiente versión no apareció hasta
1996, la versión 2.0 de DirectX, que no logró integrase en la comunidad de
programadores de juegos.

Obviamente, Microsoft no pensaba en abandonar, y trabajo mucho para mejorarlo.


La primera versión que fue realmente viable fue la 3.0. Algunos años después surgió la
5.0 (saltándose la 4.0), que fue la primera versión útil de verdad. Grandes mejoras se
introdujeron en Direct3D en la versión 6.0 de DirectX, como el soporte de
transformaciones e iluminaciones por aceleración de hardware, reorganización de las
luces, materiales, objetos de puertos de vista (que entonces pasó a controlarse mediante
“dispositivos”, conocidos como “devices”), además de un cambio completo en el
control de las texturas, que pasó a se mucho mas sencillo.

La versión 7.0 fue la primera que fue altamente aceptada por los desarrolladores de
juegos: funcionaba bien, hacía la programación de juegos razonablemente fácil, y a
mucha gente le empezó a gustar el interfaz. La versión 8.0 introdujo las mayores
mejoras de la historia de Direct3D. Prácticamente se modifico la arquitectura,
fusionando en una misma interfaz la parte 2D del API, “DirectDraw”, y la 3D en una
misma interfaz denominada “DirectX Graphics”, que llevo a un menor uso de memoria
y un modelo de programación más sencillo. Gracias a esos cambios, DirectX fue por
primera vez mas sencillo de usar y mas consistente que hasta el entonces dominante
OpenGL. Esta versión introdujo técnicas como “Point Sprites” (Conjunto de píxeles con
apoyo por hardware en el sistema de partículas para generar efectos de lluvia,
explosiones, nieve…), “3D Volumetric Textures” (texturas con 3 dimensiones,
permitiéndose iluminaciones por píxel, efectos atmosféricos…), una enorme mejora en
la librería “Direct3DX”, introducida en la versión 7.0 y que proporcionan rutinas útiles
y altamente eficientes para, por ejemplo, enumerar configuraciones de dispositivos,
configurarlos, ejecutar en pantalla completa o en ventana de forma uniforme, cambios
de tamaño, cálculos sobre matrices, etc., así como las técnicas de “N-Patches”, o los
famosos “Vertex & Píxel Shaders”, que produjo un cambio radical en la forma de
programar los juegos modernos y su apariencia.

Entre la versión 8.0 y la 9.0 no se introdujeron demasiados cambios. La 9.0 mejora


enormemente los estándares de “Píxel & Vertex Shader”. Ya que programar los
“shaders” es complejo, se introdujo el HLSL (High-Level Shader Languaje), que
permitía escribir “shaders” de una forma rápida y fácil, además de eficiente, en un
lenguaje similar al C, en lugar de la antigua sintaxis similar al ensamblador. Además de
esto se incluyeron en la versión 9.0 el antialiasing de líneas, G-Buffer, o el esperado
soporte para 24-bits de precisión de color.

La última que está por llegar en breve (10), incorpora importantes cambios
estructurales que soluciona diversos problemas que presentaba la versión 9 y que
limitaba a los creadores de videojuegos, como por ejemplo el “object overhead”
(sobrecarga de objetos), derivado del cuello de botella introducido por el acceso de la
CPU a la API de DirectX. Otra importante limitación era el uso de un pipeline fijo, lo
cual muchas veces podía desembocar en la subutilización de recursos (por ejemplo,
situaciones en las que el Píxel Shader estaba usado al 100% mientras que el Vertex
Shader estaba completamente inutilizado).

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


-2-
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

Para solucionar estas deficiencias, la versión 10 introduce nuevos shaders de


geometría, el “Stream Out” y sobre todo, una nueva arquitectura unificada (Vertex,
Píxel y Geometry Shaders están unificados, componiéndose como un único elemento de
funcionalidad dinámica). Todo esto desemboca un altísimo nivel de detalle que roza el
foto-realismo, mejorado procesamiento de sombras, escenas y ambientes más
complejos.

Durante mucho tiempo, el API Direct3D se consideraba muy malo comparado con
OpenGL. Sin embargo, el paso del tiempo y la continua evolución han convertido a
Direct3D en una interfaz de programación de gráficos muy potente y estable, y en
muchos casos va de la mano en lo que se refiere a innovación en el campo de los
gráficos 3D, ya que Microsoft trabaja muy de cerca con las empresas de hardware
gráfico llegando, en casos recientes, a introducir nuevas técnicas antes de que el
hardware lo haga.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


-3-
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

2. HAL & COM

Si quisiéramos hacer una descripción general de la estructura de Direct3D, habría


que destacar la existencia del HAL (Hardware Abstraction Layer) y el uso del modelo
COM (Component Object Model) para encapsular su código. El uso de estas dos
características surge partir de la necesidad de tener un API robusto, que proporcione una
enorme compatibilidad hardware con mecanismo de ejecución alternativo en caso de
que este no soporte alguna característica, una interfaz versátil y que no exija a los
programadores aprender nuevas especificaciones con cada versión, así como una
compatibilidad total con las anteriores versiones de DirectX.

2.1. HARDWARE ABSTRACTION LAYER (HAL)

Una de las primeras ventajas que proporciona Direct3D es lo que se conoce como
capa de abstracción del hardware o HAL. A parte del controlador del dispositivo
(driver) que se proporciona con el hardware de video, Direct3D proporciona una capa
de software en torno a la tarjeta gráfica, a la que pertenece el HAL.

Dicho HAL esta en comunicación con el driver de la tarjeta gráfica, y ofrece al


programador una capa que abstrae las diferencias de cada hardware, haciendo ver a
Direct3D la tarjeta como una entidad funcional con unas determinadas características:
cuando la tarjeta es capaz de realizar una determinada técnica o cálculo, la muestra
como activada, cuando no, la muestra como desactivada. Así, por ejemplo, cuando un
programa solicita operaciones al API de Direct3D, en función de si una característica es
presentada por el HAL, decidirá hacer uso de ella por hardware o en caso de que no la
presenta, usar alguna técnica de emulación alternativa, que siempre se traduce en una
degradación de la calidad de la imagen.

FIGURA 1: RELACIÓN DEL HAL Y GDI CON EL DRIVER

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


-4-
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

Por tanto, Direct3D usa el HAL para acceder a la tarjeta gráfica a través del driver, y
se muestra como un dispositivo. Si la tarjeta gráfica soporta Direct3D, entonces
existirá HAL en el computador, y para ello el driver debe ofrecer una interfaz
compatible con DirectX, ciñéndose a unas determinadas características. Cabe destacar
además que si la tarjeta no ofrece ningún tipo de aceleración por hardware, no se podrá
crear el dispositivo HAL.

Los dispositivos HAL tienen cuatro modos de procesamiento de vértices:

- Procesamiento de vértices por Software


- Procesamiento de vértices por Hardware
- Procesamiento de vértices Mixto
- Procesamiento de vértices puro

Cuando la tarjeta no es capaz de realizar determinadas operaciones, se puede escribir


el código que permita emular dicha característica e integrarlo en la ejecución de un
programa junto con Direct3D: es lo que se denomina “Pluggable Software Device”
(anteriormente conocido como HEL o Hardware Emulation Layer). Hoy en día, aquel
programador que desarrollar una aplicación debe escribir su capa de emulación del
hardware si desea que la aplicación se ejecute con hardware que no es capaz de ejecutar
todas las operaciones que el programa exige o incluso si no hubiese aceleración por
hardware, tratando de proporcionar una experiencia visual lo mas parecida posible sin
degradar el rendimiento enormemente.

A día de hoy son muy pocos los que se enfrentan a este reto y prefieren denegar la
ejecución del programa si el hardware no está capacitado, ya que dichas aplicaciones
son muy dependientes de lo que sea capaz de hacer la tarjeta gráfica.

Gracias a esta característica, Microsoft nos garantiza un API muy consistente capaz
de realizar operaciones alternativas cuando el computador no presente hardware
especializado. Esto se traduce en una enorme versatilidad y aislamiento del hardware.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


-5-
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

2.2. COMPONENT OBJECT MODEL (COM)

El COM es un modelo de programación orientada a objetos muy utilizada por


Microsoft y la mayoría de aplicaciones en su plataforma Win32. ¿En qué consiste?

COM es simplemente una porción de código que ofrece un determinado servicio a


través de una interfaz, dicha interfaz se compone de métodos. Un componente COM es
normalmente una librería de enlace dinámico (.DLL, Dynamic Link Library) a la que se
acceder de una forma determinada. Esto proporciona unas importantes ventajas al
programador:

1) Las interfaces de los objetos COM nunca cambian. Es lo que se conoce como
estrategia de versiones: tu objeto puede evolucionar y ofrecer nuevas interfaces, pero
nunca dejará de ofrecer las antiguas, permanecerán para proporcionar una
compatibilidad hacia atrás, garantizando que las aplicaciones siempre funcionarán a
medida que evoluciona.

2) Los objetos COM son independientes del lenguaje usado: sea cual sea el lenguaje
que se use, se podrá hacer uso de los objetos COM, ya que no son más que porciones
de código binario al cual se accede de una forma siempre constate. Esto se logra,
sobre todo, gracias a que los métodos no se llaman directamente, sino a través de una
doble indirección mediante una tabla de punteros a métodos denominada V-Table.
Por ejemplo, una vez declarada una variable de tipo Interfaz Direct3D 9, se inicializa
mediante una llamada a un método (Direct3DCreate9) que devuelve el puntero
a la interfaz de Direct3D a través de la V-Table. Luego, accediendo a través del
puntero, se pueden invocar los diversos métodos de la interfaz.

3) Son muy robustos: no se puede acceder a la información almacenada en los


objetos, solo a sus métodos.

¿En qué repercute el uso de COM sobre DirectX? Pues se podría decir que en
compatibilidad, sobre todo: si se desarrolló una aplicación en DirectX 3.0 en un ya
obsoleto computador, dicha aplicación funcionará todavía en un computador de última
generación con una tarjeta de video moderna y con la última versión de DirectX, y no
solo con la última, sino con las futuras versiones. Esto se debe a que el interfaz que se
ofrece al programador Direct3D para trabajar no ha desaparecido. En cada nueva
versión lo que se ofrece es una nueva interfaz, pero no se elimina la anterior. Por
ejemplo, la versión 9.0 de DirectX ofrece las siguientes interfaces de Direct3D:

- IDirect3D
- IDirect3D2
- IDirect3D3
- IDirect3D7
- IDirect3D8
- IDirect3D9

Así pues, gracias al modelo COM, se garantiza que toda aplicación que trabaje con
DirectX funcionará en versiones futuras, además de ayudar a encapsular la información
y a proporcionar interfaces consistentes frente a los diversos lenguajes de programación.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


-6-
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

Veamos a continuación un ejemplo que corrobore todo lo explicado: para poner una
luz en la escena, llamaremos a través de la interfaz de direct3D al método que se
encarga de ello:

hr = m_pd3dDevice -> lpVtbl -> SetLight( m_pd3dDevice, 0,


&light);

En C, se accederá a una interfaz (m_pd3dDevice) a través de un puntero a la V-


Table, que a su vez tendrá el puntero al método que queremos usar (SetLight), al
cual, además, habrá que pasarle como primer parámetro un puntero this. Con C++ los
objetos COM y los objetos C++ son compatibles a nivel binario, de modo que el
compilador maneja interfaces COM y clases abstractas de C++ del mismo modo, por lo
que no habrá que acceder a la V-Table, pues ya se hace de forma implícita, al igual que
el paso del puntero this.

hr = m_pd3dDevice -> SetLight( 0, &light);

Por lo general, podemos decir que en general, la mayoría de las llamadas a DirectX
en C++ son de la forma NOMBRE_INTERFAZ  NOMBRE_METODO.

Para poder hacer uso de los objetos COM de Direct3D, a la hora de programar
tenemos que enlazar las librerías que se van a usar, que son las siguientes:

- d3dx9dt.lib
- d3dxof.lib
- d3d9.lib
- winmm.lib
- dxguid.lib
- comctl32.lib

También se deberá incluir los ficheros de cabecera, con los prototipos de los
métodos, definiciones de tipos, etc. Todas estas librerías se proporcionan en el SDK de
DirectX creado por Microsoft, que se puede encontrar en www.microsoft.com.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


-7-
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

3. PRINCIPIOS FUNDAMENTALES DE LA PROGRAMACIÓN DE GRÁFICOS EN DIRECT3D

Antes de entrar en detalles de programación, veamos algunos fundamentos 3D con


los que trabaja el API de Microsoft.

Por defecto, el sistema de coordenadas de Direct3D es levógiro (o como encontrará


en los documentos, left-handed), con la Z positiva entrando en la pantalla:

FIGURA 2: SISTEMA DE COORDENADAS DE DIRECT3D

OpenGL, sin embargo, usa un sistema de coordenadas dextrógiro (right-handed), con


la Z positiva saliendo de la pantalla. Esto es importante pues en muchos casos interesa
transformar de un sistema de coordenadas a otro.

Los vértices son la base de los gráficos 3D, y se usan para definir nuestros objetos
en el espacio. Se definen como vectores libres cuyo origen es el origen del sistema de
coordenadas, y el final es el propio vértice. Los vectores no solo se usan para definir
vértices, también se usan para las iluminaciones o para indicar una dirección. En
Direct3D un vector se define como un tipo de dato denominado D3DVECTOR, y consta
de las componentes, x, y, z. En el caso de los vértices, estos se definen como algo más
que un vector que indica su posición. La estructura típica del tipo de dato Vertex en
Direct3D es similar a la siguiente:

Struct Vertex {
D3DVECTOR vPosition;
DWORD dwDiffuse;
D3DVECTOR vNormal;
FLOAT u, v;
}

El primer atributo indica el vector posición, el segundo un valor que indica el color
del píxel, el tercer valor es el vector normal (necesario para las iluminaciones, como por
ejemplo, la técnica del sombreado gouraud) y el cuarto valor especifica las coordenadas
de una textura para lo que se conoce como mapeado de texturas (texture-mapping).

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


-8-
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

Direct3D trabaja con vértices de esta forma, y los aloja en un buffer de vértices
(vertex-buffer) al que podrá acceder nuestro programa de aplicación, cuando
normalmente solo podía acceder el driver de la tarjeta gráfica.

El usuario podrá definir qué estructura tendrá el tipo de dato vértice, en función de la
información que nos interese alojar: si no vamos a usar iluminaciones, no nos interesará
las normales, y tampoco incorporaremos las coordenadas de las texturas si no van a ser
usadas. Así logramos optimizar el uso de memoria, que es crítico, pero en cada función
es necesario especificar que estructura tiene el vértice. Esto es una práctica habitual que
se realiza a través de banderas y macros ya definidas en las cabeceras de DirectX.

Cuando posicionamos un objeto en el espacio 3D, necesitamos especificar su


orientación, esto se consigue usando tres vectores. Estos vectores se usan para indicar:

- Hacia dónde está mirando el objeto

- Dónde es arriba para el objeto

- En qué posición se encuentra

Todo objeto 3D se compone de caras, y ya que Direct3D solo es capaz de renderizar


3 tipos de primitivas (puntos, líneas y triángulos), se encargará de descomponer el
objeto en triángulos. Para obtener un rendimiento óptimo, todo objeto que definamos
deberá poder descomponerse en triángulos, por lo que lo ideal es generar los modelos a
partir de triángulos, así sabremos que Direct3D no introducirá elementos indeseados
que ralenticen la renderización (esto se debe, sobre todo, a que hoy en día las tarjetas
gráficas hacen cálculos muy rápidamente a través de triángulos).

Cabe destacar que Direct3D hace uso de una técnica conocida como “BackFace
Culling” de forma automática, que consiste en no renderizar aquellos triángulos que no
se ven en la escena, como los que están fuera de la visión de la cámara o aquellos que
no puede ver el espectador porque están detrás de otro elemento. Esto se calcula
obteniendo el vector normal que define el plano de dos lados comunes de dos triángulos
y determinando si el vector está orientado “saliendo de la pantalla” (se renderizará) o
“entrando en la pantalla” (no se renderizará). Así se acelera enormemente la
renderización de una escena.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


-9-
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

4. ARQUITECTURA: LA TUBERÍA DE DIRECT3D (DIRECT3D-PIPELINE)

Una visión de alto nivel de cómo trabaja Direct3D podría ser la siguiente:

FIGURA 3: TUBERÍA DE DIRECT3D

Esta “tubería” se podría asemejar a una cadena de producción: al comienzo tenemos


la materia prima, a partir de la cual, a lo largo de una serie de etapas, se van procesando
para dar lugar a la imagen que deseamos. Es el planteamiento de esta tubería lo que
convierte a Direct3D en un API de gráficos 3D potente y eficiente. Veamos un breve
comentario acerca de estas etapas:

- Datos de vértices y primitivas: no es una etapa, sino la información que obtiene


como entrada la tubería a partir de la cual generará la escena. Los vértices son un
conjunto de estos sin transformar en buffers de memoria. Las primitivas son figuras
geométricas básicas (puntos, líneas, triángulos, polígonos…) que hacen referencia al
buffer de vértices mediante un buffer índice, a partir de los cuales se podrá
renderizar el objeto.

- Tessellation: Esta etapa consiste en convertir o descomponer aquellas formas o


primitivas de alto nivel en vértices sin transformar.

- Vertex Processing: Durante esta etapa se efectúan transformaciones básicas, como


las transformaciones de vista y modelo, mundo, proyección, cálculo de luces, (de
ahí que esta etapa se conozca también como “Transform & Lighting”) o incluso el
uso de los “Vertex Shaders”, que nos permite inyectar código propio para procesar
los vértices.

- Geometry Processing: Aquí se aplican una amplia diversidad de técnicas sobre los
vértices ya transformados, como por ejemplo el “Back-Culling”, evaluación de los
atributos de los vértices, clipping (relacionado con el buffer de profundidad),
rasterización (proceso por el cual transforma los vértices a píxeles con coordenadas
de dispositivo, solventando los problemas de no concordancia entre las coordenadas
del vértice y del píxel), etc.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 10 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

- Píxel Processing: Procesamiento de texturas y uso del famoso “píxel-shader”,


técnica relativamente nueva que al igual que los “vertex-shaders” permite inyectar
código propio en el procesamiento de los píxeles. Este proceso desemboca en un
conjunto de píxeles con un color calculado a partir de todos los procesos que en esta
etapa se efectúan.

- Píxel Rendering: Se aplican las últimas transformaciones sobre los píxeles, como
por ejemplo, aplicar transformaciones con la información de profundidad (z-buffer),
niebla, alfa, stencil buffer…y un gran conjunto de técnicas que producen finalmente
los píxeles para mostrar en pantalla.

Por tanto, podemos descomponer la tubería en dos grandes etapas: el procesamiento


de vértices y el procesamiento de píxeles.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 11 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

5. TUBERÍA DE TRANSFORMACIONES

En Direct3D se pueden llevar a cabo una serie de transformaciones para modificar la


escena: las transformaciones del mundo, transformaciones de vista, y
transformaciones de proyección, además de las transformaciones del modelo. Toda
escena 3D al final se convertirá en un plano 2D y todas estas transformaciones
determinan que es lo que se verá a través del puerto de vista.

La tubería de transformaciones toma los vértices como entrada, y aplica las


transformaciones de mundo, vista y proyección para transformar los vértices. Al
comienzo de la entrada, los vértices del modelo hacen referencia a un sistema de
coordenadas locales (los vértices en este estado se conocen como espacio de
coordenadas locales):

- Lo primero que se hará es transformar de las coordenadas locales a un sistema de


coordenadas mundiales, común a todos los objetos definidos en la escena. El
proceso de reorientar los vértices a las nuevas coordenadas se conoce como
transformaciones del mundo, obteniéndose el espacio de coordenadas
mundiales.

- La siguiente etapa consiste en reorientar los vértices del mundo 3D respecto a la


cámara, es decir, la aplicación toma una posición para la cámara y Direct3D
reorienta todos los puntos en coordenadas mundiales en función de lo que el
observador debería ver, proceso que se conoce como transformaciones de vista.
El conjunto de vértices transformados se conocen como espacio de vista.

- A continuación se efectúan las transformaciones de proyección. Durante este


proceso, los objetos son escalados para dar la sensación de profundidad, a causa de
que se pretende ofrecer una escena 2D de algo que ocurre en 3D, aunque no todas
las proyecciones (como la ortogonal) escalan los objetos de la escena. También
define el volumen de vista. El conjunto de vértices resultantes se conoce como
espacio de proyección.

- En la última etapa de la tubería, se eliminan los vértices que no se van a ver en la


escena, así el rasterizador no tiene que calcular colores ni sombreados para píxeles
que no se ven, proceso que se conoce como “clipping” o recortado. A
continuación, el conjunto de vértices resultantes se transforman acordes a los
parámetros del puerto de vista y se convierten en coordenadas de pantalla o
dispositivo. El conjunto de vértices resultantes, que se ven en pantalla tras la
rasterización (transformación a píxeles) y se conoce como espacio de pantalla o
de despliegue.

Se debe comentar que también se efectúan las transformaciones de modelo durante


la tubería de transformaciones, pero estas no reubican los vértices, sino que calculan,
mayormente, las componentes de iluminación difusa o especular de cada vértice. El
orden en el que se efectúe esta transformación durante la tubería es irrelevante, sin
embargo, las anteriores etapas han de realizarse en el orden descrito.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 12 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

Todas estas transformaciones se realizan a través de producto de matrices, y para


definir nuestra escena necesitaremos la matriz del mundo, la matriz de vista y la
matriz de proyección.

Antes de continuar, se debe comentar un mínimo acerca de la librería Direct3DX,


pues se verá a continuación que la mayoría de funciones y definiciones provienen de
ésta. Direct3D Extended, que es como se conoce a esta librería, posee funciones básicas
para la realización de operaciones esenciales, pues lo que nos ofrece Direct3D es de
muy bajo nivel. Por ejemplo, si no fuera por estas librerías, tendríamos que aplicar las
transformaciones componiendo nosotros nuestra propia matriz de transformación y
luego multiplicando. Gracias a Direct3DX, tendremos funciones que realicen dichas
operaciones de forma eficaz y segura. Estas funciones han sido estudiadas en
profundidad por los desarrolladores de Microsoft para que resultasen extremadamente
eficientes.

Las matrices en Direct3D se definen mediante D3DMATRIX, pero por conveniencia


usaremos la definición de Direct3DX, similar a la anterior, para la cual, por ejemplo, se
han sobrecargado los operadores, entre otras cosas.

typedef struct _D3DMATRIX {


union {
struct {
float _11, _12, _13, _14;
float _21, _22, _23, _24;
float _31, _32, _33, _34;
float _41, _42, _43, _44;

};
float m[4][4];
};
} D3DMATRIX;

Se observa que se podrá acceder a un elemento mediante _XY, donde X es la fila e Y


la columna, o bien mediante [X][Y].

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 13 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

6. TRANSFORMACIONES DEL MUNDO

Las transformaciones básicas que se pueden realizar son rotaciones, translaciones y


escalados. A partir de estas operaciones, las transformaciones del mundo se efectúan
concatenando diversas matrices de transformación para finalmente establecerla como
matriz del mundo, siendo luego Direct3D el encargado de reubicar los objetos en
funcion de esta matriz.

Crear matriz de traslación:

D3DXMATRIX *WINAPI D3DXMatrixTranslation(


D3DXMATRIX *pOut,
FLOAT x,
FLOAT y,
FLOAT z
);

Los ángulos de las rotaciones se especifican en radianes

Crear matriz de rotación en torno al eje X:

D3DXMATRIX *WINAPI D3DXMatrixRotationX(


D3DXMATRIX *pOut,
FLOAT Angle
);

Crear matriz de rotación en torno al eje Y:

D3DXMATRIX *WINAPI D3DXMatrixRotationY(

D3DXMATRIX *pOut,
FLOAT Angle
);

Crear matriz de rotación en torno al eje Z:

D3DXMATRIX *WINAPI D3DXMatrixRotationZ(

D3DXMATRIX *pOut,
FLOAT Angle
);

Crear matriz de rotación en torno a un vector determinado:

D3DXMATRIX *WINAPI D3DXMatrixRotationAxis(

D3DXMATRIX *pOut,
CONST D3DXVECTOR3 *pV,
FLOAT Angle
);

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 14 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

Crear matriz de rotación en torno a ejes Z (Roll), X (Pitch) e Y (Yaw)


consecutivamente:

D3DXMATRIX *WINAPI D3DXMatrixRotationYawPitchRoll(

D3DXMATRIX *pOut,
FLOAT Yaw,
FLOAT Pitch,
FLOAT Roll
);

Crear matriz de escalado:

D3DXMATRIX *WINAPI D3DXMatrixScaling(

D3DXMATRIX *pOut,
FLOAT sx,
FLOAT sy,
FLOAT sz
);

Para obtener el efecto de varias transformaciones a la vez podemos multiplicar las


matrices entre sí, proceso conocido como concatenación de matrices. El orden en que se
efectúan las multiplicaciones es crucial, ya que a diferencia de los valores escalares, el
producto de matrices no es conmutativo. Los efectos visuales de una determinada
concatenación de matrices se efectúan de izquierda a derecha. Por ejemplo, si deseamos
rotar y luego trasladar, se efectuará la siguiente operación:

M = R * T, siendo R la matriz de rotación y T la matriz de traslación.

Una vez obtenida y establecida la matriz de modelo y vista, las transformaciones se


observarán en pantalla en el orden de izquierda a derecha, es decir, en el orden que se
efectúan las multiplicaciones. Esto es de vital importancia, pues por ejemplo, en
OpenGL las transformaciones ocurren en el orden contrario en que se invocan las
multiplicaciones: las transformaciones ocurren de derecha a izquierda. Para
multiplicar matrices podemos usar la función D3DXMatrixMultiply().

Veamos un ejemplo para aclarar las transformaciones: En primer lugar se define la


matriz del mundo. A continuación, se calcula la matriz de traslación partiendo del
origen. Dado que D3DXMatrixTranslation genera una matriz de traslación, al
multiplicar la identidad por la matriz de traslación resulta la misma matriz de traslación,
por eso es almacenada en la variable matWorld. A continuación creamos las matrices
de rotación en torno al eje Y girando 90 grados (1.57 radianes). Finalmente se
multiplican las matrices en el orden que se desee efectuar las operaciones (rotación y
luego traslación), para luego establecer dicha matriz como la matriz del mundo. La
constante D3DTS_WORLD especifica que se va a establecer la matriz del mundo.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 15 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

D3DXMATRIX matWorld;
D3DXMatrixTranslation(&matWorld, 0,1,0);
D3DXMATRIX matRotateX;
D3DXMatrixRotationY(&matRotateY, 1.57);
D3DXMatrixMultiply(&matWorld, & matRotateY, & matWorld);

...

// en la funcion encargada del Render

m_pd3dDevice -> SetTransform(D3DTS_WORLD, matWorld);

...

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 16 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

7. TRANSFORMACIONES DE VISTA

La transformación de vista localiza al espectador en el espacio del mundo,


transformando los vértices al espacio de vista. En dicho espacio, el espectador está al
origen, mirando en sentido positivo de la dirección Z de un nuevo sistema de
coordenadas de referencia. La matriz de vista reubicará los objetos de nuestra escena en
torno a la posición y orientación de la cámara (origen del espacio de vista). Es decir, se
definirá un nuevo sistema de coordenadas, las coordenadas de vista, que establecen
como está la cámara en la escena, y en función de las cuales se reubicarán los vértices.

Hay diversas formas de crear una matriz de vista, pero en todos los casos, la cámara
tendrá una posición y orientación dentro del espacio del mundo que tomamos como
referencia inicial para su creación. Una primera forma es combinar matrices de
traslación y rotación para la orientación de cada una de las tres direcciones de nuestro
nuevo sistema de referencia. Para facilitar esta complicada labor, las librerías D3X
proporcionan unas funciones para la creación de dichas matrices.

Construir una matriz de vista con un sistema de referencia levógiro.

D3DXMATRIX *WINAPI D3DXMatrixLookAtLH(

D3DXMATRIX *pOut,
CONST D3DXVECTOR3 *pEye,
CONST D3DXVECTOR3 *pAt,
CONST D3DXVECTOR3 *pUp
);

Donde pOut es un puntero a la matriz resultante, pEye es un puntero a un vector de


3 componentes que indican las coordenadas dentro del espacio del mundo donde se
encuentra el observador, pAt es otro vector de las mismas características que el anterior
y que define la dirección en la que está mirando el espectador, y pUp define para la
cámara cual será la dirección que tomará como “arriba”.

También se proporciona una función equivalente para los sistemas de coordenadas


dextrógiros: D3DXMatrixLookAtRH

Ejemplo:

D3DXMATRIX out;
D3DXVECTOR3 eye(2,3,3);
D3DXVECTOR3 at(0,0,0);
D3DXVECTOR3 up(0,1,0);
D3DXMatrixLookAtLH(&out, &eye, &at, &up);
m_pd3dDevice -> SetTransform(D3DTS_VIEW, &out);

Para establecer una matriz de vista, accedemos al método SetTransform a través


del dispositivo asignado por el interfaz de Direct3D, donde la constante D3DTS_VIEW
establece que el cambio que se efectuará es el de la matriz de vista.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 17 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

8. TRANSFORMACIONES DE LA PROYECCIÓN

Esta es la transformación más complicada de la tubería, y podría entenderse como


una analogía con el tipo de lente que se usa en la cámara: cómo se plasmará la escena
3D que se observa en el plano 2D al que se proyecta y de qué forma se proyectará los
elementos dentro del volumen de vista.

La “instantánea” obtenida dependerá del tipo de proyección que se use. Existen


varios tipos, y las librerías D3X nos proporcionan funciones que crean matrices de
proyección tanto en perspectiva como en proyección ortogonal.

Toda proyección definirá un volumen fuera del cual los objetos no son vistos por el
espectador. Este espacio podría entenderse como el recinto existente entre dos planos:
uno cercano y otro lejano. Estableciendo la forma y tamaño de estos planos podemos
lograr cambiar la relación de aspecto de la escena a proyectar y el ángulo de visión que
tenemos de la misma escena.

Las funciones proporcionadas para crear la matriz de proyección son las siguientes:

Crea matriz de proyección levógiro:

D3DXMATRIX *WINAPI D3DXMatrixPerspectiveLH (

D3DXMATRIX *pOut,
FLOAT w,
FLOAT h,
FLOAT zn,
FLOAT zf
);

Donde pOut estable el puntero a la matriz de salida, w es el ancho del plano más
cercano que define el recinto, y h su ancho. Zn definirá la profundidad a la que se
encuentra el plano más cercano, y zf la del plano más lejano. Para esta función existe
su variante dextrógiro, D3DXMatrixPerspectiveRH. Efectúa una proyección
ortogonal y es equivalente a la función D3DXMatrixPerspectiveOffCenterLH.

Construir matriz de proyección levógiro basándose en un campo de visión

D3DXMATRIX *WINAPI D3DXMatrixPerspectiveFovLH(

D3DXMATRIX *pOut,
FLOAT fovy,
FLOAT Aspect,
FLOAT zn,
FLOAT zf
);

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 18 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

En este caso, el volumen de vista es nuevamente definido por un plano cercano y


otro lejano, pero ahora los dos planos serán diferentes, en base a un ángulo de visión en
radianes en la dirección de Y (fovy), y una relación de aspecto del volumen de vista
aspect (ancho entre alto). Esto produce que tengamos dos planos proporcionales pero
no iguales, resultando en una proyección en perspectiva. Junto a ella, las librerías
proporcionan también su variante dextrógiro D3DXMatrixPerspectiveFovRH.

Construir matriz de proyección levógiro personalizada

D3DXMATRIX *WINAPI D3DXMatrixPerspectiveOffCenterLH(

D3DXMATRIX *pOut,
FLOAT l,
FLOAT r,
FLOAT b,
FLOAT t,
FLOAT zn,
FLOAT zf
);

En esta última función, definiremos el volumen de proyección a través de un recinto


cúbico mediante sus coordenadas X mínima (l) y máxima (r), Y mínima (b) y máxima
(t), y Z mínimo (zn) y máximo (zf). Como el resto de funciones de esta librería, posee
también su variante dextrógiro D3DXMatrixPerspectiveOffCenterRH y
efectúa una proyección ortogonal.

Ejemplo:

D3DXMATRIX matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f,
1.0f, 100.0f );
g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );

Este ejemplo genera una matriz con un ángulo de visión de PI cuartos, una relación
de aspecto de 1 (uno de alto por uno de ancho), un volumen definido entre Z = 1 y Z =
100, y luego la establece como matriz de proyección mediante la constante
D3DTS_PROJECTION.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 19 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

9. PUERTO DE VISTA (VIEWPORTS)

El puerto de vista es, conceptualmente, el plano 2D sobre el que se proyecta la


escena 3D que hemos definido. En Direct3D, las coordenadas de este plano son
definidas sobre el dispositivo en que se renderiza la escena. La transformación de
proyección convierte los vértices en el sistema de coordenadas del puerto de vista.

En Direct3D, el rectángulo que define el puerto de vista se especifica a través de la


estructura D3DVIEWPORT9, la cual es usada en los métodos de manipulación
proporcionados por el dispositivo de Direct3D (IDirect3DDevice9)
GetViewport() y SetViewport(). La estructura en cuestión es como sigue:

typedef struct _D3DVIEWPORT9 {


DWORD X;
DWORD Y;
DWORD Width;
DWORD Height;
float MinZ;
float MaxZ;
} D3DVIEWPORT9;

X e Y definen las coordenadas del píxel de la esquina superior izquierda del puerto
de vista sobre el dispositivo de renderización. Width especifica su ancho y Height su
alto, y los parámetros MinZ y MaxZ referencian a los valores mínimos y máximos a
usar en lo referente a profundidad. Todos estos parámetros describen el rectángulo del
puerto de vista.

FIGURA 4: PUERTO DE VISTA

Una vez creada la matriz del puerto de vista, se le pasa como argumento al método
SetViewport() del dispositivo, y tomará efecto la próxima vez que se renderice la
escena. Si no se especifica un puerto de vista, Direct3D tomará por defecto todo el
dispositivo de renderización que se le haya asignado.

Mediante GetViewport() podemos recuperar los parámetros del puerto de vista


actual y, a través del método Clear() del dispositivo, se puede limpiar el puerto de
vista. Es común su uso para limpiar la imagen y establecer valores de inicialización del
z-buffer antes de presentar una nueva escena.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 20 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

HRESULT Clear(

DWORD Count,
const D3DRECT *pRects,
DWORD Flags,
D3DCOLOR Color,
float Z,
DWORD Stencil
);

Como se pueden definir varios rectángulos, count especifica cuantos contendrá la


estructura pRects, que un puntero a un array de rectángulos. Para indicar que se
limpiará todo el puerto de vista y no hay rectángulos definidos en este, se pone count
a cero y pRects a NULL. Flags indica que es lo que se va a limpiar, y puede ser Z-
BUFFER, RENDER TARGET (en referencia al dispositivo) o STENCIL BUFFER.
Mediante Color concretamos el color de borrado, Z es el valor por defecto del Z buffer
al borrarlo y Stencil es el valor por defecto al borrar del Stencil Buffer. Una llamada
habitual a este método podría ser el siguiente, en el cual se limpia todo el puerto de vista
en negro, y el buffer de profundidad:

d3dDevice -> Clear( 0, NULL, D3DCLEAR_TARGET |


D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0L );

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 21 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

10. DISPOSITIVOS DE DIRECT3D

Un dispositivo es un componente de Direct3D que se encarga de la renderización,


encapsulando y almacenando todo su estado. Además, el dispositivo se encarga de las
transformaciones y de las luces, así como del proceso de rasterizado de la escena en una
superficie en pantalla.

En lo referente arquitectura, podemos distinguir tres grandes módulos: el módulo de


transformaciones, el módulo de iluminaciones y el módulo de rasterizado.

FIGURA 5: ARQUITECTURA DE LOS DISPOSITIVOS DE DIRECT3D

Actualmente, Direct3D da soporte a dos tipos de dispositivos: el HAL y el dispositivo


de referencia. Ambos pueden verse como dos drivers independientes: el HAL
representa un driver hardware, el dispositivo de referencia podría ser un driver
software. Así, el HAL efectuaría trabajos a través de aceleración por hardware, y el
dispositivo de referencia podría emular características que aún no está disponible en el
hardware actual.

El dispositivo Direct3D que una aplicación cree debe estar en correspondencia


adecuada con las capacidades que presenta el hardware que usa la propia aplicación. Así
pues, Direct3D presentará unas capacidades, que o bien podrán ser fruto del trabajo
mediante hardware o bien puedes ser emulado por software.

Los dispositivos acelerados por hardware proporcionan un rendimiento muy superior


a los que se logra con emulación por software. El dispositivo HAL estará disponible
para todos aquellos computadores con tarjetas gráficas que soporten Direct3D. En la
mayoría de los casos, las aplicaciones se diseñan para computadores con aceleración por
hardware, y se apoyan en la emulación por software en aquellos computadores de baja
gama, sin embargo, lo cierto es que no siempre los dispositivos por software soportan
las mismas características que los dispositivos hardware.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 22 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

Para crear un dispositivo HAL, llamaremos al método


IDirect3D9::CreateDevice usando D3DDEVTYPE_HAL como parámetro. Si
en cambio lo que deseamos es usar un dispositivo de referencia, le pasaremos como
parámetro D3DDEVTYPE_REF. El dispositivo de referencia se usa muy poco en
aplicaciones comerciales, y se limita a propósitos de demostración o testeo.

Para crear un dispositivo, primero se ha de crear un objeto Direct3D, el encargado de


ponernos en comunicación con el API. Todos los dispositivos creados por un objeto
Direct3D comparten los mismo recursos físicos, lo cual significará que si se crea varios
dispositivos sobre un objeto Direct3D, el rendimiento se deteriorará enormemente a
causa de compartir el mismo hardware.

En primer lugar, se debe inicializar un conjunto de parámetros del dispositivo a


través de una estructura concreta. Esta estructura, D3DPRESENT_PARAMETERS tiene
los siguientes parámetros:

typedef struct _D3DPRESENT_PARAMETERS_ {


UINT BackBufferWidth, BackBufferHeight;
D3DFORMAT BackBufferFormat;
UINT BackBufferCount;
D3DMULTISAMPLE_TYPE MultiSampleType;
DWORD MultiSampleQuality;
D3DSWAPEFFECT SwapEffect;
HWND hDeviceWindow;
BOOL Windowed;
BOOL EnableAutoDepthStencil;
D3DFORMAT AutoDepthStencilFormat;
DWORD Flags;
UINT FullScreen_RefreshRateInHz;
UINT PresentationInterval;
} D3DPRESENT_PARAMETERS;

- Direct3D se apoya en un conjunto de buffers (conocidos como back buffers) que


usa para almacenar la imagen, trabajando de manera encadenada de forma similar
a la técnica del “double buffering”. BackBufferWidth y
BackBufferHeight indican el tamaño de los dichos buffers en píxeles.

- BackBufferFormat es como almacenará la información de la imagen en los


buffers. Direct3D soporta los estándares A2R10G10B10, A8R8G8B8, X8R8G8B8,
A1R5G5B5, X1R5G5B5 y R5G6B5.

- BackBufferCount indicará el número de back buffers de que dispondrá la


aplicación para el proceso de intercambio. Un valor de cero es interpretado como
uno

- MultiSampleType y MultiSampleQuality configuran la técnica de


“multisampling” aplicada cuando no hay intercambio de back buffers.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 23 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

- SwapEffect nos servirá para indicar que tipo de comportamiento tendrá el


intercambio de back buffers.

- hDeviceWindow es un manejador del dispositivo de pantalla, que es el


encargado de determinar la localización y el tamaño de los back buffers en
pantalla.

- Mediante windowed especificaremos si la aplicación corre bajo un sistema de


ventanas o a pantalla completa.

- EnableAutoDepthStencil hace que Direct3D maneje automáticamente los


buffers de profundidad Z y Stencil. Cuando el dispositivo es creado, estos buffers
son creados automáticamente, de la misma forma que son eliminados o
regenerados cuando el dispositivo es reseteado.

- AutoDepthStencilFormat establecerá el formato de los buffers automático


de profundidad.

- Flags contiene un conjunto adicional de restricciones como la desactivación de


los buffers de profundidad, bloqueo de back buffers, apoyo para video…

- FullScreen_RefreshRateInHz concreta la frecuencia de refresco de la


imagen en pantalla en hercios. Depende del modo en que se esté ejecutando la
aplicación (ventana o pantalla completa)

- PresentationInterval contiene la frecuencia máxima a la que se irán


mostrando los sucesivos back buffers especificados.

Por lo general, se pondrán toda la estructura a cero, para establecer las propiedades
menos usadas a su valor por defecto, y luego se establece aquellas características cuya
elección si es crítica.

El siguiente paso es crear el dispositivo a través del método CreateDevice():

HRESULT CreateDevice(
UINT Adapter,
D3DDEVTYPE DeviceType,
HWND hFocusWindow,
DWORD BehaviorFlags,
D3DPRESENT_PARAMETERS *pPresentationParameters,
IDirect3DDevice9 **ppReturnedDeviceInterface
);

- Adapter indica cual de los dispositivos de vídeo (varias tarjeta gráficas) usar.
Normalmente se pondrá a D3DADAPTER_DEFAULT, que siempre es el primer
dispositivo.

- DeviceType hace referencia al tipo de dispositivo usado, HAL o de referencia

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 24 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

- hFocusWindow hace referencia al foco de la ventana de nuestra de aplicación.


Por ejemplo, en pantalla completa, nuestra ventana debe ser la que esté más al
frente, en cambio, en modo ventana de daremos el valor NULL.

- BehaviorFlags permitirá combinar una o más opciones que controlan el


proceso de creación del dispositivo. Lo normal es establecer el comportamiento
del procesamiento de vértices que tendrá el dispositivo.

- pPresentationParameters es el puntero a la estructura con los parámetros


de la creación de nuestro dispositivo.

- ppReturnedDeviceInterface se trata del puntero de salida que ubicará la


dirección de nuestro interfaz con el dispositivo creado.

El siguiente ejemplo crea un dispositivo Direct3D tomando el adaptador de video por


defecto, que será de tipo HAL mediante procesamiento de vértices por software.

g_pD3D -> CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,


hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp,
&d3dDevice)

Una vez creado el dispositivo, se procedería a establecer su estado (activación de


luces, del culling…).

Direct3D proporciona algunas funciones para facilitar el proceso de detección de las


capacidades del hardware presente en la máquina. La mas usada,
CheckDeviceType(), permite determinar si el dispositivo está capacitado para
llevar a cabo cálculos con aceleración por hardware, o si permite crear varios back
buffers para la presentación de la imagen, o su capacidad para renderizar el formato de
los buffers especificado. CheckDepthStencilMatch() ayuda a conocer si el
dispositivo está capacitado para representar el formato de los buffers de profundidad
especificado, entre otras cosas.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 25 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

11. BUFFERS DE VERTICES (VERTEX BUFFERS)

Los buffers de vértices son porciones de memoria que alojan vértices (en forma de
arrays que representan un vértice). Estos vértices pueden estar transformados o no, y se
podrán procesar para realizar una transformación, iluminaciones, etc. Estos buffers se
suelen alojar en la memoria de video, desde donde se pueden efectuar los cálculos 3D
mucho más rápido. Por ejemplo, podríamos almacenar un determinado modelo, efectuar
todas las transformaciones necesarias sobre el y luego representar la escena tantas veces
como se desee sin tener que volver a efectuar las transformaciones.

Para crear un buffer de vértices, usaremos el método de la interfaz del dispositivo


IDirect3DDevice9::CreateVertexBuffer. Una primera característica
importante que se comentó acerca de los conceptos 3D básicos de Direct3D es que la
estructura de los vértices no es constante, sino que podemos variarla en función de la
información sobre ellos que queramos alojar. Los parámetros que podemos almacenar
en una estructura de vértice se especifican a través de una mascara (esta característica es
conocida como Flexible Vertex Format, o FVF). Los principales parámetro son, y
debiendo ser especificados en orden, los siguientes:

1. Posición del vértice: float x, float y, float z  D3DFVF_XYZ

2. RJW (reciprocal of homogeneus w coordinate) solo para vértices ya


transformados  D3DFVF_XYZRHW

3. Normal del vertice: float x, float y, float z  D3DFVF_NORMAL

4. Tamaño de punto del vértice  D3DFVF_PSIZE

5. Color difuso (RGBA)  D3DFVF_DIFFUSE

6. Color Specular (RGBA)  D3DFVF_SPECULAR

7. Coordenada de la textura de 1 a 8 (coordenadas u y v): pueden ser especificadas 2


coordenadas (texturas 2D) mediante D3DFVF_TEXCOORDSIZE2(n) o 3
coordenadas (texturas 3D) con D3DFVF_TEXCOORDSIZE3(n). El argumento n
representa el número de la coordenada. El número de coordenadas lo especificaremos
con D3DFVF_TEXn, siendo n el número de estas coordenadas

Estos son los principales. Un ejemplo de máscara típica sería:

#define D3DFVF_CUSTOMVERTEX
(D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 26 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

Que definiría la siguiente estructura de vértice, que también es necesario definir:

typedef struct
{
D3DVALUE x,y,z;
D3DVALUE diffuse;
D3DVALUE u,v;
} VERTICE;

Esta definición de vértice deberá se pasada como parámetro a la función


CreateVertexBuffer para que conozca el formato de vértice usado. Este método
tiene los siguientes parámetros:

HRESULT CreateVertexBuffer(
UINT Length,
DWORD Usage,
DWORD FVF,
D3DPOOL Pool,
IDirect3DVertexBuffer9** ppVertexBuffer,
HANDLE* pSharedHandle
);

- Lenght: Primero se especifica el tamaño del buffer. Un ejemplo podría ser


10 * sizeof(VERTICE).
- Usage: Conjunto de flags que especifican como serán usados los recursos
almacenados en el vértice. Por lo general, se pone a cero.
- FVF: Máscara con el formato del vértice.
- Pool: Tipo de clase de memoria donde disponer los datos. Se suele usar
D3DPOOL_DEFAULT, que referencia a la memoria de vídeo o incluso dejar que
Direct3D decida con D3DPOOL_MANAGED, más seguro aún.
- ppVertexBuffer: Aquí retorna el puntero al buffer de vértices generado.
- pSharedHandle: Es un parámetro reservado, poner a NULL.

Ejemplo:

d3dDevice->CreateVertexBuffer(3*sizeof(VERTICE),0,
D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, NULL)

Por lo general, el uso de las llamadas a funciones en Direct3D devuelve un código de


retorno que indica si ha sido válido o no u otras situaciones. Para facilitar la evaluación
de dichos parámetros, en las cabeceras se ha definido unas macros para ello. Estas
macros son SUCEEDED() para llamadas que resultaron satisfactorias y FAILED()
para llamadas que generaron error.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 27 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

Para poder acceder al buffer, primero hay que bloquearlo. Para ello se usa la función
IDirect3DVertexBuffer9::Lock, para luego rellenar el buffer con los vértices
(mediante un simple memcpy en el caso de trabajar en C) o bien leer su contenido. Esta
función acepta cuatro parámetros:

HRESULT Lock(

UINT OffsetToLock,
UINT SizeToLock,
VOID **ppbData,
DWORD Flags
);

- OffsetToLock: contiene la dirección de comienzo a partir de la cual vamos a


bloquear. Si vamos a bloquear todo el buffer, se deberá poner a cero.
- SizeToLock: Tamaño a bloquear a partir del offset.
- ppbData: Puntero al vértice (de tipo VOID)
- flags: Describe como se realizará el bloqueo de la memoria, mediante flags.
D3DLOCK_DISCARD se usa para poner el modo de escritura y
D3DLOCK_READONLY para ponerlo en modo lectura.

Pongamos por ejemplo, que se va a bloquear como escritura y a copiar todo el


contenido de un array de vértices en memoria en el buffer:

VOID* pVertices;
if (FAILED(m_pVB->Lock(0, m_dwSizeofVertices,
(BYTE**)&pVertices,0)))
return E_FAIL;
memcpy( pVertices, cvVertices, m_dwSizeofVertices);
m_pVB->Unlock();

Como era de esperar, tras finalizar el uso de un buffer de vértices, habrá que
desbloquearlo a través de IDirect3DVertexBuffer9::Unlock(). No tiene
ningún parámetro.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 28 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

12. RENDERIZAR UNA ESCENA A PARTIR DE UN BUFFER DE VÉRTICES

Para dibujar una escena a partir de un conjunto de vértice, en primer lugar se debe
especificar la fuente de los mismos, para lo cual se usa la función
IDirect3DDevice9::SetStreamSource().

HRESULT SetStreamSource(

UINT StreamNumber,
IDirect3DVertexBuffer9 *pStreamData,
UINT OffsetInBytes,
UINT Stride
);

El primer parámetro, StreamNumber, indicará el número de la fuente de


información, que se pone a cero casi siempre. El segundo parámetro, el puntero
pStreamData, es el puntero al buffer, obtenido previo bloqueo del mismo. El tercero
indica el tamaño del buffer, que no se suele indicar en la llamada, y el cuarto es el
tamaño de cada componente (de cada vértice).

Por ejemplo:

d3dDevice->SetStreamSource(0, g_pVB, sizeof(VERTICE));

Indica que el puntero al buffer g_pVB contiene elementos del tamaño de los vértices
que definimos como VERTICE.

El siguientes pasos para el dibujo de una escena sería indicar el “vertex shader” a
usar. Habrá que indicarle el formato del vértice con el que estamos tratando mediante el
método SetVertexShader():

d3dDevice -> SetVertexShader(D3DFVF_CUSTOMVERTEX);

Ya estamos en disposición de dibujar la escena. Esto se realiza a través de la función


IDirect3DDevice9::DrawPrimitive, que dibuja a partir de los vértices del
buffer una de las primitivas que Direct3D es capaz de renderizar. El conjunto de
primitivas que Direct3D puede dibujar es el siguiente:

- D3DPT_POINTLIST: Renderiza un conjunto de puntos aislados. No puede


trabajar con índices.

- D3DPT_LINELIST: Renderiza los vertices como un conjunto de líneas aisladas,


definidas mediante 2 vértices, es decir, tomará dos vértices y dibujara una línea, y
a continuación los siguientes dos vértices para dibujar otra línea.

- D3DPT_LINESTRIP: Renderiza los vertices como un conjunto de líneas


continuas, es decir, los dos primeros vértices definen una línea, el siguiente, otra
línea que parte del vértice anterior, y así sucesivamente.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 29 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

- D3DPT_TRIANGLELIST: Efectuar la renderización de los vértices como un


conjunto de triángulos aislados. Cada tres vértices define un triángulo.

- D3DPT_TRIANGLESTRIP: Se renderizará un conjunto de triángulos como una


tira.

- D3DPT_TRIANGLEFAN: Renderiza los vertices como un abanico (cada vértice


sucesivo definido define un triángulo con los dos vértices anteriores)

d3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

El primer parámetro será el tipo de primitiva, el segundo parámetro el índice del


primer vértice a usar, y el último parámetro, el número de primitivas a dibujar. Lo más
eficiente es definir las escenas mediante “Triangle Strips” o “Triangle Fans” porque se
duplican menos vértices.

FIGURA 6: TRIANGLEFAN

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 30 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

FIGURA 7: TRIANGLESTRIP

Todo el proceso de renderización se debe llevar a cabo entre la llamadas a las


funciones BeginScene() y EndScene() del dispositivo, que indican a Direct3D
que se va a renderizar la escena, y éste comprobará si el sistema está listo para ello
también. Ejemplo:

if( SUCCEEDED(d3dDevice->BeginScene())) {
d3dDevice->SetStreamSource(0, m_pVB, sizeof(VERTICE));
d3dDevice->SetVertexShader(D3DFVF_CUSTOMVERTEX );
d3dDevice->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);
d3dDevice->EndScene();
}

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 31 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

13. DIBUJAR A PARTIR DE UN BUFFER DE ÍNDICES (INDEX BUFFER)

En determinadas situaciones, dibujar a partir de un buffer de vértices limita mucho la


renderización, pues nos vemos obligados siempre a disponer los vértices en el orden que
se van a dibujar las primitivas, y eso puede complicar mucho el diseño de un modelo, y
también produce una redundancia de vértices significativa. Veamos un ejemplo:

FIGURA 8: LISTA DE TRIÁNGULOS

Si dibujamos estos dos triángulos de forma independiente, definiéndola como una


lista de triángulo sin índice, tendremos que manejar 6 vértices, cuando se ve
claramente que estos triángulos comparten dos vértices. En cambio, si los encadenamos
solo necesitaremos cuatro vértices, y el apoyo de un buffer de índices. De una forma
intuitiva, el índice debería indicar “construye el primer triángulo a partir de los vértices
V1, V2 y V3, y el segundo triángulo mediante V2, V3 y V4”.

Mediante lista de triángulos sin índice, el buffer contendrá información duplicada, y


esto produce un desaprovechamiento enorme de la memoria. El uso del buffer de
vértices se puede reducir usando un buffer de índices, y un buffer de vértices más
pequeño reduce el número de vértices que deben ser enviados al adaptador de vídeo, y
lo que es mas importante, lograremos que se almacenen en la caché de vértices del
adaptador datos que volverán a utilizar de nuevo, ya que las siguientes primitivas
poseen vértices recientemente usados, por lo que el vértice se puede obtener de la caché
en lugar de leerla del buffer de memoria de nuevo. Todo ello resulta en una gran
mejoría del rendimiento. Sin el uso de índices, además, este tipo de diseño es mucho
mas complicado, sobre todo cuando tratamos con un número considerable de triángulos.

HRESULT CreateIndexBuffer(

UINT Length,
DWORD Usage,
D3DFORMAT Format,
D3DPOOL Pool,
IDirect3DIndexBuffer9** ppIndexBuffer,
HANDLE* pSharedHandle
);

La creación de un buffer de índices exige de una serie de parámetros que defina sus
características.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 32 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

Length indica el tamaño que tendrá el buffer, en bytes. Usage concreta el uso que
se le dará al buffer, concretando determinadas compatibilidades, por ejemplo, que el
buffer sea usado por software en lugar de hardware
(D3DUSAGE_SOFTWAREPROCESSING). Format indica el tipo de dato que será el
índice. Al igual que con el buffer de vértices, habrá que especificar donde y como se
alojará la información de los índices, a través de Pool, para lo cual se recomienda
relegar esa decisión a Direct3D con D3DPOOL_MANAGED. ppIndexBuffer será
nuestro puntero al buffer, y el último parámetro es nuevamente reservado para el
sistema.

Una vez creado, el acceso al buffer exigirá de nuevo el uso de los métodos Lock()
y Unlock() para bloquearlo y poder acceder a el, de forma similar a como hacíamos
con el buffer de vértices.

Veamos un ejemplo, en el cual se crear un índice, posteriormente se bloquea y se


copia sobre el los valores de los índices, y luego se desbloquea:

LPDIRECT3DINDEXBUFFER9 m_pIB;
WORD dwIndices[] = {0, 1, 2, 0, 2, 3};
m_dwSizeofIndices = sizeof(dwIndices);

if(FAILED(d3dDevice->CreateIndexBuffer(m_dwSizeofIndices,
0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &m_pIB ) ) )
return E_FAIL;

VOID* pIndices;

if(FAILED(m_pIB->Lock( 0, m_dwSizeofIndices,
(BYTE**)&pIndices, 0)))
return E_FAIL;
memcpy( pIndices, dwIndices, sizeof(dwIndices) );
m_pIB->Unlock();

Ahora, para dibujar las primitivas, habrá que establecer en primer lugar el índice que
estamos usando mediante SetIndices(), y en segundo lugar sustituir el uso de la
función DrawPrimitive() por DrawIndexedPrimitive().

En lo referente a presentar una escena, en determinadas ocasiones necesitaremos


forzar inmediatamente a presentar la imagen. Para ello usaremos el método
Present() del dispositivo de Direct3D, que forzará a intercambiar con el siguiente
buffer dentro de la secuencia de back buffers definida. La llamada habitual, a no ser que
hayamos configurado características especiales en el buffer, será:

g_pd3dDevice->Present(NULL, NULL, NULL, NULL);

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 33 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

14. CONCLUSIÓN FINAL Y COMPARATIVA ENTRE DIRECT3D Y OPENGL

Este documento ha pretendido servir para entender las principales características de


Direct3D, así como sus principios básicos. Mucha teoría existe en torno a los gráficos
3D, pero se ha tratado abarcar lo fundamental en la medida de lo posible: conocer como
funciona este API sirve como punto de partida al enorme y siempre en crecimiento
mundo de los gráficos 3D.

Hoy en día Direct3D resulta un pilar básico en la programación de gráficos 3D en


aplicaciones y juegos. Antiguamente, se consideraba muy malo comparado con el API
dominante, OpenGL. Sin embargo, las continuas evoluciones sufridas han hecho de
Direct3D una API muy fuerte y estable.

Existe una idea generalizada de que Direct3D es el estándar de gráficos para


plataformas Windows. Esto no es cierto, ya que gran cantidad de aplicaciones han sido
desarrolladas en APIs como OpenGL o Glide. Sin embargo, si se puede decir que
Microsoft trabaja muy cerca de los fabricantes de tarjetas gráficas, a causa de su
posición dominante en el mundo de los computadores. Esto no proporciona la garantía
de que toda nueva característica que surjan en la evolución del hardware gráfico será
siempre soportado por Direct3D, de hecho, muchas veces Direct3D dispone de nuevas
características antes de que las tarjetas gráficas lo hagan. Todo ello hace de Direct3D un
API ideal para aquellos que deseen escoger un sistema fuerte y con continuo soporte
ante la rápida evolución del hardware gráfico, con la garantía de que funcionará con un
sistema operativo muy comprometido con las aplicaciones y juegos 3D como es
Microsoft Windows.

Como características principales de Direct3D, hay que recalcar la estructura basada


en objetos COM y la integración de la capa HAL.

El HAL, como ya se ha comentado, nos permite abstraernos de las peculiaridades de


cada fabricante de hardware gráfico y centrarnos en lo que interesa al programador: las
capacidades de aceleración hardware que posee el adaptador. Esto supuso un paso
importante en la programación de gráficos 3D.

Gracias al uso del COM, Microsoft ha garantizado un sistema que a pesar de estar en
continua evolución, garantizará el funcionamiento de aplicaciones desarrolladas con
versiones antiguas del API. Sin embargo, su uso puede asustar al comienzo, ya que las
cabeceras COM no son precisamente sencillas de entender, aunque el paso del tiempo
han permitido que los desarrolladores tengan a su alcance una estructura y sintaxis de
programación mas intuitiva y sencilla. Además, aquellos desarrolladores acostumbrados
a la programación orientada a objetos se sentirán cómodos con Direct3D.

Otra ventaja que proporciona Direct3D, es que gracias al modelo COM, es


independiente del lenguaje, pues los objetos COM son simples librerías de código
binario: simplemente se necesita unas cabeceras de definición y un conjunto de punteros
a métodos. Sin embargo, en contradicción con esta ventaja, Direct3D no funcionará en
otras plataformas que no sea Microsoft Windows.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 34 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

Todo esto conduce a que la programación ideal de gráficos 3D en Windows debería


hacerse mediante Direct3D, y no se trata de una idea descabellada, pues es obvio que un
API desarrollado por Microsoft funcione mejor en su plataforma que otros.

Y lo cierto es que Direct3D hace las cosas muy bien, y a causa de estar diseñado para
Windows, lo hace ideal para computadores muy variados, desde sistemas de pocos
recursos hasta computadores con lo último de hardware gráfico. Los profesionales de
los gráficos 3D preferirán una plataforma UNIX o de Sillicon Graphics.

Comentar también que no hay nada que Direct3D haga y OpenGL no pueda hacer,
pero tienen una cierta ventaja a causa de que las últimas características del hardware
gráfico necesitarán código personalizado para cada adaptador en OpenGL, mientras que
Direct3D ya estará implementado. No obstante, Direct3D resultará más complicado a la
hora de programar, porque no oculta totalmente los elementos de bajo nivel como hace
OpenGL, pero esto también desemboca en una pérdida de flexibilidad a la hora de
programar. Será el programador el que deba decidir entre flexibilidad o simplicidad. En
lo referente a flexibilidad, cabe destacar las dos mayores fuerzas de Direct3D en lo que
a programación se refiere: “Programable Píxel & Vertex Shaders”, porciones de código
propio similar al ensamblador que se inyectan en la tubería de renderización para
procesar los vértices y píxeles finales que se mostrarán en pantalla.

Las desventajas principales podrían ser:

- DirectX se actualiza cada año o más, lo cual es relativamente lento frente a la


rápida evolución del hardware gráfico.

- Direct3D requiere mucho más código para inicializarse. En versiones anteriores a


la 8, era necesario de en torno a 800 líneas de código. Hoy en día, esto se ha
reducido a 200, que aun sigue siendo considerablemente grande.

- Direct3D requerirá un buen conocimiento de cómo funciona, por lo que es mucho


más complicado de aprender a usar que OpenGL.

- No es portable

- No es de estándar abierto, por lo que Microsoft es el único que puede


implementarlo en sus sistema

- Programarlo en C puede resultar muy complicado debido a que es necesario


acceder a los objetos COM a través de las V-Tables.

Frente a esto se encuentra OpenGL, relativamente sencillo de aprender, altamente


portable, muy eficiente y fuerte también en cualquier plataforma, de estándar abierto
(cualquiera puede comprar una licencia e implementar OpenGL en su plataforma), y su
desarrollo representa un amplio rango de intereses proveniente de muchas empresas, en
contra de la política de Microsoft, lo cual le aportará una mayor flexibilidad. Además,
es reconocido como el estándar de la industria de los gráficos, como en el campo del
modelado 3D profesional, uso militar, CAD, etc, salvo en el campo de los juegos y
aplicaciones, donde Direct3D ofrece una fuerte competencia.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 35 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

Una de las principales dificultades que presenta son las extensiones, que son muy
dependientes de hardware especifico, o también su elevado número de nombres
diferentes para una misma función (Direct3D aprovecha la sobrecarga de nombres de
función propias de la programación orientada a objetos). Tampoco tiene mucho soporte
para todos los lenguajes de programación.

La programación de gráficos 3D en sí es muy complicada, y comúnmente las trabas


que se encuentran a lo largo del aprendizaje se atribuyen al API escogido, cuando lo
cierto es q a la larga ambos interfaces son igual de complicados. Si se desea aprender a
programar gráficos 3D, cualquiera de los dos APIs es una buena elección, y en cualquier
momento se podrá aprender a usar el otro, ya que las bases son las mismas. Quizás
superior complejidad de Direct3D sea a causa de su inicialización: a partir de superar
esa barrera, el funcionamiento será igual al de OpenGL.

Feature OpenGL 1.2 Core Direct3D 7 Direct3D 8


System Mechanics
Windows (9x, NT,
Operating System Windows (9x, 2000, Windows (9x,
2000), MacOS, BeOS,
Support CE) 2000)
*nix, others
API Definition Control OpenGL ARB Microsoft Microsoft
SDK/DDK
SDK
API Specification OpenGL Specification Documentation and
Documentation
DDK Reference
API Mechanism includes and libraries COM COM
Software Emulation of
Yes No No
Unaccelerated Features
Extension Mechanism Yes No Yes
Source Implementation
Yes Yes No
Available
Modeling
Fixed-Function Vertex
No Yes Yes
Blending
Programmable Vertex
No No Yes
Blending
Parametric Curve
Yes No Yes
Primitives
Parametric Surface
Yes No Yes
Primitives
Hierarchical Display
Yes No No
Lists
Rendering
Two-sided Lighting Yes No No
Point Size Rendering
Yes No Yes
Attributes

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 36 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

Line Width Rendering


Yes No No
Attributes
Programmable Pixel
No No Yes
Shading
Triadic Texture
No No Yes
Blending Operations
Cube Environment
No Yes Yes
Mapping
Volume Textures Yes No Yes
Multitexture Cascade No Yes Yes
Texture Temporary
No No Yes
Result Register
Mirror Texture
No Yes Yes
Addressing
Texture "Wrapping" No Yes Yes
Range-Based Fog No Yes Yes
Bump Mapping No Yes Yes
Modulate 2X Texture
No Yes Yes
Blend
Modulate 4X Texture
No Yes Yes
Blend
Add Signed Texture
No Yes Yes
Blend
Frame Buffer
Hardware Independent
Yes No No
Z Buffer Access
Full-Screen
Yes Yes Yes
Antialiasing
Motion Blur Yes No Yes
Depth of Field Yes No Yes
Accumulation Buffers Yes No No
Miscellaneous
Picking Support Yes No No
Multiple Monitor
Support
No Yes Yes
Stereo Rendering
Yes Yes No

FIGURA 9: “DIRECT3D VS. OPENGL: A COMPARISON”, EXTRAIDO DE


HTTP://WWW.XMISSION.COM/~LEGALIZE/D3D-VS-OPENGL.HTML

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 37 -
INTRODUCCIÓN A DIRECT3D VÍCTOR ROLDÁN BETANCORT
INFORMÁTICA GRÁFICA 2006/2007 RAÚL SÁNCHEZ RUIZ

15. BIBLIOGRAFÍA

- Microsoft DirectX 9.0 SDK Update (April 2005) Documentation

- Artículo: Direct3D vs. OpenGL: Which API to Use When, Where, and Why
by Promit Roy, GameDev.net

- Direct3D vs. OpenGL: A Comparison, http://www.xmission.com/~legalize/d3d-vs-


opengl.html

- Beginning Direct3D By Vahid Kazemi,www.codeproject.com/directx/d3d_tut1.asp

- Cutting Edge Direct 3D Programming (Publisher: The Coriolis Group) Author(s):


Stan Trujillo ISBN: 1576100502 Publication Date: 11/01/96

- Beginning Direct3D Game Programming, Second Edition 2003, Wolfgang F.


Engel, Premier Press. ISBN: 193184139x

- Tutoriales de Direct3D by Corday, 24 Octubre del 2001, basado en los textos de


Wolfgang F. Engel, http://www.geocities.com/cordayuk/Direct3D/

- http://www.programmersheaven.com/

- http://www.gamedev.net/

- http://www.chilehardware.com/guias_guia067-20061024.html

- Apuntes de Informática Gráfica de la Ingeniería Informática de la Universidad de


Salamanca creados por Dr. Juan Manuel Corchado.

INGENIERÍA INFORMÁTICA, UNIVERSIDAD DE SALAMANCA


- 38 -

Das könnte Ihnen auch gefallen