Microsoft DirectX: Procesamiento de Imágenes en 3D con Direct3D.
Diferencias entre una misma imagen generada con DirectX 9 y con DirectX 10. |
DirectX 10, incluido por primera vez en Windows Vista, incluía una nueva versión de la librería Direct3D, denominada Direct3D 10, que añade capacidades de programación y de virtualización de la memoria al subsistema gráfico y elimina la capacidad anterior de DirectX de poder utilizar la capacidad de bits (capability bits) para poder detectar las funciones que están activas en el hardware que se está utilizando. Sin embargo, Direct3D 10 define un nivel mínimo de capacidades de hardware que debe ser apoyado por un sistema gráfico compatible con Direct3D 10.
Con esto, el objetivo de Microsoft fue crear un entorno para desarrolladores y diseñadores en los que pueden estar seguros que el diseño o desarrollo que diseñaron o programaron será renderizado exactamente igual y de la misma manera en cualquier tarjeta gráfica que esté soportada por esta versión de DirectX. Este ha sido un problema recurrente con el modelo de DirectX 9, debido a que diferentes tarjetas gráficas producían resultados diferentes, por lo que requerían soluciones concretas de los fabricantes de tarjetas gráficas específicas para ser programadas por los desarrolladores.
Hasta ahora, y todas las versiones anteriores a DirectX 10, la principales librerías de DirectX incluían Direct3D, utilizado para el procesamiento, programación y renderizado de gráficos en tres dimensiones (una de las características más usadas de DirectX), Direct2D, para procesar, programar y renderizar imágenes en dos dimensiones, DirectInput, para procesar dispositivos de entrada como el teclado, el ratón, controladores para juegos, etc., DirectPlay, librería para comunicaciones de red, DirectSound, para la reproducción, mezcla, efectos y grabación de sonido, DirectWrite para el manejo de tipografías, fuentes (tipos de letra), etc. En DirectX 10 prácticamente solo se han revisado, mejorado y añadido todas las características y funcionalidad de Direct3D. Para Microsoft el resto de librerías como DirectDraw, DirectMusic, DirectPlay, DirectSound y DirectShow han quedado obsoletas, se mantienen por compatibilidad y se recomienda no utilizarlas en nuevos desarrollos. Para utilizar la funcionalidad que se contenía en estas librerías, Microsoft recomienda utilizar otras nuevas como XInput, XAudio2, etc., y otras librerías que se encuentran fuera de DirectX y que bien son librerías propias de Windows o bien son librerías de desarrollo de la consola XBox 360 compatibles con Windows.
Por todo esto se puede considerar que Direct3D es la principal librería de DirectX y prácticamente DirectX se define según las características, potencia y rendimiento de Direct3D. Para poder explicar todo esto, primero hay que entender como funciona Direct3D para procesar imágenes en 3D. Básicamente a todo este proceso se le denomina renderizado y a todo el conjunto de procesos, técnicas y tecnologías utilizadas para realizar el renderizado se le denomina "Proceso o Canal de Interpretación, Dibujado o Renderizado (Rendering Pipeline)" que se explica a continuación en detalle.
Del inglés "rendering", renderizar, renderizado, renderización o interpretar/interpretación en español, también denominado rasterizar, del inglés "Rastering" o "Raster". La renderización es el proceso de generar (dibujar) una imagen (mapas de bits) a partir de un modelo (vectorial), usando una aplicación informática. El modelo es una descripción en dos o tres dimensiones de objetos en un lenguaje o estructura de datos estrictamente definidos. La información almacenada del modelo en ese lenguaje o estructura de datos contiene vectores, geometría, punto de vista, textura e información de iluminación, etc. y al proceso de interpretar todos estos datos y generar una imagen (mapa de bits) se le denomina renderización. La imagen (mapa de bits) resultado de la renderización es una imagen digital denominada "raster (en inglés)". En resumen, la renderización es el proceso de convertir (dibujar, interpretar, procesar) unos datos vectoriales (geometría, texturas, iluminación, etc.) en una imagen de mapa de bits.
Para realizar un renderizado existe todo un proceso denominado "Proceso de Renderizado (Rendering Pipeline)" que lo realiza un motor de renderizado. En este caso, se podría decir que, entre otras muchas más cosas, Direct3D es un motor de renderizado.
El proceso de renderizado consta de varias etapas que varían según el motor de renderizado que se esté utilizando. La imagen siguiente muestra diferentes procesos de renderizado según los diferentes motores de renderizado:
Proceso de Renderizado según diferentes motores de renderizado.
En líneas generales, las principales etapas del proceso de renderizado estándar son las siguientes (más adelante veremos en detalle las etapas de Direct3D):
En esta etapa, se introducen los datos del modelo provisto, es decir, la geometría del objeto con los vértices, aristas y caras que constituyen toda la escena. Después se aplican las transformaciones lineales a este modelo como son el escalado, la rotación y la traslación así como las transformaciones de visión (visión del mundo y visión espacial).
El modelo en la escena 3D completa se ilumina de acuerdo a las ubicaciones definidas de las fuentes de luz y la reflectancia y otras propiedades de la superficie. La implementación actual del proceso de renderizado de una tarjeta gráfica procesa la iluminación solo en los vértices de los polígonos siendo estos renderizados (dibujados). Después, los valores de iluminación entre los vértices son interpolados durante la generación de la imagen (rasterización). La iluminación por fragmento, es decir, por píxel de iluminación se puede hacer directamente en las tarjetas gráficas actuales como un proceso posterior a la rasterización por medio de un programa de sombreado o sombreador (shader).
Los objetos son transformados de coordenadas en un mundo 3D a un sistema de coordenadas 3D basadas en la posición y orientación de una cámara virtual. Esto resulta en la escena 3D original vista desde la perspectiva de la cámara, definida en lo que se denomina espacio visual o espacio de cámara.
Después de la transformación, se generan nuevas primitivas (datos originales) a partir de las primitivas que fueron enviadas al principio del proceso de renderizado.
En el caso de una proyección de una perspectiva, los objetos que están más alejados de la cámara se hacen más pequeños. En una proyección ortográfica, los objetos conservan su tamaño original, independientemente de la distancia de la cámara. En esta etapa del proceso de renderizado, el modelo es transformado desde el espacio visual de la cámara de renderizado en un espacio de coordenadas 3D especiales llamados Espacio Homogéneo de Recorte (Homogeneus Clip Space), un espacio de coordenadas especial para recortar la imagen. Este espacio de recorte suele oscilar entre [-1, 1] en X, Y, Z, aunque esto puede variar según la librería o motor gráfico (Direct3D u OpenGL). La transformación según la proyección es responsable de asignar los planos del volumen de visualización de la cámara (o Tronco, Frustum) a los planos del bloque que hacen posible el espacio de recorte (Clip Space).
Las primitivas geométricas que ahora quedan fuera del tronco (Frustum) de visión no serán visibles y se descartan en este momento. El recorte no es necesario para lograr una salida de la imagen correcta, pero acelera el proceso de renderizado, eliminando la rasterización y post-procesamiento innecesarios de los objetos (primitivas) que no van a aparecer de todos modos.
Los vértices ya cortados (post-clip) son transformados una vez más en el espacio de la ventana. En la práctica, esta transformación es muy simple: la aplicación de una escala (multiplicar por el ancho de la ventana) y un sesgo (agregando a la posición desde el origen de la pantalla). En este punto, los vértices tienen coordenadas que se relacionan directamente con los píxeles de un mapa.
La rasterización es el proceso mediante el cual la representación del espacio de la imagen en 2D de la escena se convierte en una imagen de mapa de bits (formato raster), y se determinan los valores correctos de los pixeles resultantes.
En esta etapa del proceso, a los fragmentos individuales (o pre-píxeles) se les asigna un color basado en los valores interpolados a partir de los vértices durante la rasterización o los de una textura almacenada en la memoria.
Los píxeles coloreados finales ya pueden ser mostrados en un monitor o cualquier otra pantalla.
El proceso de renderizado se realiza sobre el hardware de aceleración gráfica de tal forma que los datos se envían a la tarjeta gráfica en forma de vértices. A continuación estos vértices se someten a la transformación e iluminación por vértice. En este punto, en el proceso de renderizado de las tarjetas gráficas actuales, se utiliza un programa personalizado de sombreador de vértices (vertex shader) para manipular los vértices 3D antes de la rasterización. Una vez transformados e iluminados, los vértices son recortados y rasterizados resultando en fragmentos. Un segundo programa personalizado de sombreador puede ser ejecutado en cada fragmento antes que el valor final del pixel se envíe al buffer de ventana, para ser mostrado en una pantalla.
Todo este proceso gráfico es el adecuado para el proceso de renderizado, ya que permite a la tarjeta gráfica funcionar como un procesador stream puesto que todos los vértices y fragmentos pueden ser considerados como independientes. Esto permite que todas las etapas del proceso de renderizado puedan ser utilizadas simultáneamente por distintos vértices o fragmentos y trabajar a su manera a través de todo el proceso de renderizado. Aparte del proceso de vértices y fragmentos, su independencia permite a los procesadores gráficos utilizar unidades de procesamiento en paralelo para procesar múltiples vértices o fragmentos en una sola etapa del proceso de renderizado al mismo tiempo.
La tecnología de sombreador (shader) es cualquier unidad escrita en un lenguaje de sombreador que se puede compilar independientemente. Es una tecnología reciente y que ha experimentado una gran evolución destinada a proporcionar al programador una interacción con el procesador gráfico (GPU) hasta ahora imposible. Los sombreadores (shaders) son utilizados para realizar transformaciones y crear efectos especiales, como por ejemplo iluminación, fuego o niebla. Para su programación los sombreadores (shaders) utilizan lenguajes específicos de alto nivel que permitan la independencia del hardware.
En el año 2.000 la serie 2 de tarjetas GeForce permitía al procesador gráfico (GPU) hacerse cargo de funciones de transformación e iluminación que hasta ahora debía hacerlas el procesador del ordenador (CPU), sin embargo no fue hasta la GeForce 3 (2001) que se incluyó la posibilidad de programarlas con la primera versión del modelo de sombreador (shader model). Existen numerosas versiones, se debe tener en cuenta que cuanto más reciente es la versión más limita el número de tarjetas gráficas sobre las que el programa puede operar correctamente.
Para la escritura de esas instrucciones, los programadores hacen uso de lenguajes de programación diseñados específicamente para ello. Cada uno de estos lenguajes de programación necesita enlazarse mediante una librería, DirectX u OpenGL entre otras. Aunque existen diferentes lenguajes, los siguientes son los más conocidos y utilizados:
El Lenguaje de Sombreador de Alto Nivel (High Level Shader Language - HLSL), explicado en detalle más adelante, es la implementación propiedad de Microsoft, la cual colaboró junto a nVidia para crear un lenguaje de sombreador. Este lenguaje se debe utilizar junto a DirectX (la primera versión para la que se puede utilizar es DirectX 8.0). Anteriormente al DirectX 8 (DirectX 7, 6, 5...) se utilizaba otro método el cual era más complicado y complejo para ser utilizado (entre lo que era el lenguaje, creación de objetos, sonidos, partículas, entre otras).
GLSL es el acrónimo de OpenGL Shading Language (Lenguaje de Sombreado de OpenGL), un lenguaje desarrollado por el grupo Khronos. Está diseñado específicamente para su uso dentro del entorno de OpenGL. Sus diseñadores afirman que se ha hecho un gran esfuerzo para lograr altos niveles de paralelismo. Su diseño se basa en C y RenderMan como modelo de lenguaje de sombreador.
CG (C for Graphics - Lenguaje de Programación C para Gráficos) es un lenguaje propiedad de la empresa nVidia resultante de su colaboración con Microsoft para el desarrollo de un lenguaje de sombreador. Su principal ventaja es que puede ser usado por las librería de OpenGL y DirectX. Otra ventaja de este lenguaje es el uso de perfiles. Estos lenguajes no son totalmente independientes del hardware por lo tanto es recomendable crear programas específicos para diferentes tarjetas gráficas. Los perfiles de CG se encargan de elegir para su ejecución el más adecuado de los programas disponibles para el hardware.
A continuación se presentan los diferentes tipos de sombreador que procesa y ejecuta el procesador gráfico (GPU). Los principales, casi desde los inicios del sombreador son los Sombreadores de Vértices (Vertex Shaders - VS), los Sombreadores de Pixel (Pixel Shader - PS), también conocidos como Sombreadores de Fragmento (Fragment Shaders - FS), y los Sombreadores de Geometría (Geometric Shaders - GS). Los tipos de sombreador crecen con celeridad entre generaciones de gráficas.
El Modelo Unificado de Sombreador (Unified Shader Model) unifica estos tres mencionados sombreadores tanto en la librería Direct3D 10 de DirectX, como en la librería OpenGL (explicadas en detalle más adelante).
El programador envía un conjunto de vértices que forman su escena gráfica a través de un lenguaje de propósito general. Todos los vértices pasan por el sombreador de vértices (vertex shader) donde pueden ser transformados y se determina su posición final. El siguiente paso es el sombreador de geometría (geometric shader) donde se pueden eliminar o añadir vértices. Posteriormente los vértices son ensamblados formando primitivas que son rasterizadas, proceso en el cual las superficies se dividen en puntos que corresponden a píxeles de la pantalla. El sombreador de pixel/fragmentos (píxel/fragment shader) se encarga de modificar estos puntos. Por último se producen ciertos tests, entre ellos el de profundidad (Z-Buffer) que determina que punto es dibujado en pantalla.
Explicándolo de un modo muy resumido, los sombreadores trabajan de la siguiente manera dentro del proceso de renderizado:
OpenGL es una especificación estándar que define una librería multilenguaje y multiplataforma para escribir aplicaciones que produzcan gráficos 2D y 3D. La interfaz consiste en más de 250 funciones diferentes que pueden usarse para dibujar escenas tridimensionales complejas a partir de primitivas geométricas simples, tales como puntos, líneas y triángulos. Fue desarrollada originalmente por Silicon Graphics Inc. (SGI) en 1.992 y se usa ampliamente en CAD, realidad virtual, representación científica, visualización de información y simulación de vuelo. También se usa en desarrollo de videojuegos, donde compite con Direct3D en plataformas Microsoft Windows.
Las principales nuevas características de Direct3D 10 son las siguientes:
El siguiente vídeo, un tráiler del juego Stalker: Clear Sky, muestra la potencia y las capacidades de las nuevas características de DirectX 10 / Direct3D 10,, como los rayos del sol, movimiento suave y realista del agua, fuego volumétrico, humo volumétrico dinámico, superficies mojadas dinámicas, mapa de lluvia : mapa de sombreador para el efecto de la lluvia y el agua de la lluvia fluyendo por las superficies:
Direct3D 10 requiere del nuevo modelo de controladores gráficos para Windows WDDM (Windows Display Driver Model) para funcionar y hardware gráfico que lo soporte, es decir, tarjetas gráficas certificadas para funcionar con DirectX 10. La tarjeta gráfica tiene que soportar multitarea preventiva para permitir que múltiples y diferentes hilos de proceso puedan utilizar la GPU (procesador gráfico) a la vez. La tarjeta gráfica tiene que ofrecer además paginación de memoria gráfica.
DirectX 10 ofrece además, para compatibilidad con programas, aplicaciones y juegos anteriores, una versión de Direct3D 9 denominada Direct3D 9Ex. Esta librería modificada de Direct3D 9 utiliza también el nuevo modelo de controladores gráficos para Windows WDDM (Windows Display Driver Model) para poder acceder a algunas de las características disponibles en DirectX 10, como superficies compartidas a través de procesos, memoria gráfica gestionada, priorización de recursos, texto suavizado (antialiasing), funciones de gamma avanzadas y gestión de eliminación del dispositivo.
Según Microsoft, Direct3D 10 es capaz de mostrar unos gráficos hasta 8 veces más rápido que con DirectX 9.0c gracias al nuevo y mejorado WDDM (Windows Display Driver Model). Además, Direct3D 10 incorpora el Lenguaje de Sombreador de Alto Nivel de Microsoft versión 4.0 (Microsoft High Level Shader Language 4.0) (explicado en detalle más adelante).
Sin embargo, Direct3D 10 no es compatible con las versiones anteriores de DirectX, algo que sí ocurría en todas las versiones anteriores de DirectX que sí eran compatibles con todas las versiones anteriores. Esto significa que la misma aplicación o juego no será compatible con Direct3D 10 y Direct3D 9 o versiones anteriores. Las aplicaciones o juegos tienen que ser desarrollados tanto para las librerías de Direct3D 9 si se quiere que funcione en Windows XP o versiones anteriores de Windows, y otra versión con Direct3D 10 si se quiere aprovechar todas las nuevas funciones y características de DirectX 10 pero que sólo funcionaría en Windows Vista y versiones superiores como Windows 7. Hay que tener en cuenta que las versiones desarrolladas en Direct3D 9 pueden funcionar en modo de compatibilidad en Windows Vista con DirectX 9 y versiones superiores, sin embargo, no aprovecharían todas las nuevas capacidades y funciones del nuevo DirectX 10.
Direct3D 10 incluye un modelo de sombreador (shader model) actualizado, la versión 4.0. En este modelo, los sombreadores siguen consistiendo en etapas fijas como en las versiones anteriores, pero todas las etapas ofrecen ahora un interfaz unificado, así como un acceso unificado para recursos como texturas y constantes de sombreador.
En adición a las etapas anteriores de sombreador de pixel (pixel shader) y sombredor de vértices (vertex shader), Direct3D 10 incluye una nueva etapa de sombreador de geometría (geometric shader) que rompe con el modelo anterior de un vértice de entrada para un vértice de salida, permitiendo que la geometría sea generada desde el sombreador, lo cual se realiza completamente desde el procesador gráfico (GPU), siendo capaz de realizar geometrías muy complejas y con mucho mayor rendimiento.
El Modelo de Sombreador versión 4.0 (Shader Model 4.0) es la nueva versión ampliada y actualizada del modelo de sombreador incluido en Direct3D 10 de DirectX 10. Consiste en tres sombreadores programables dentro del proceso de renderizado (rendering pipeline):
Todas las etapas del sombreador ofrecen la misma funcionalidad base, la cual es implementada por el núcleo común del Modelo de Sombreador versión 4.0 (Shader Model 4.0). Además, cada una de estas tres etapas de sombreador (vertex, pixel y geometric shaders) ofrecen su propia funcionalidad única dentro de su propia etapa, aparte de la común que integran las tres.
En esta nueva versión del Modelo de Sombreador versión 4.0 (Shader Model 4.0) destacan el soporte completo para los enteros y los operadores bit a bit entre otras muchas de las nuevas características.
En anteriores versiones del modelo de sombreador (shader model) así como en otros programas sombreadores, toda la funcionalidad y programación de estas tres etapas se realizaba en un lenguaje ensamblador intermedio. Ahora, en la versión 4.0 del Modelo de Sombreador (Shader Model 4.0) toda la funcionalidad y programación se pueden realizar en el nuevo lenguaje estilo C llamado Lenguaje de Sombreador de Alto Nivel de DirectX (DirectX High Level Shader Language - HLSL).
El Lenguaje de Sombreador de Alto Nivel (High Level Shader Language - HLSL) es un lenguaje de sombreador desarrollado por Microsoft para su uso con la librería de Microsoft, Direct3D. En esta nueva versión, el lenguage ha sido ampliado para ser más expresivo, incluyendo operaciones con enteros, un conjunto de instrucciones mucho mayor, y mayores construcciones de lenguaje con una sintaxis y estructura similar a la del lenguaje de programación C.
Los programas desarrollados con el Lenguaje de Sombreador de Alto Nivel (High Level Shader Language - HLSL) funcionan con estas tres tecnologías descritas anteriormente que se procesan y ejecutan en el procesador gráfico (GPU) dentro del proceso de renderizado (rendering pipeline):
Un Sombreador de Vértices (Vertex Shaders - VS) es ejecutado para cada vértice dado por la aplicación, y es el principal responsable para transformar el vértice de un objeto en el espacio, a un objeto de vista, generando las coordenadas de las texturas y calculando los coeficientes de iluminación, como la tangente del vértice y vectores normales y binormales. Cuando un grupo de vértices (normalmente 3, para formar un triángulo) pasan a través de un Sombreador de Vértices (Vertex Shaders - VS), su posición de salida es interpolada para formar píxeles dentro de su área. Este proceso se conoce como rasterización. Cada uno de estos píxeles pasan a través del Sombreador de Pixel (Pixel Shaders - PS), donde se calcula el resultado del color de la pantalla. Opcionalmente, una aplicación que use una interfaz Direct3D 10 y un hardware compatible con este, puede especificar un Sombreador de Geometría, (Geometric Shaders - GS). Este sombreador toma como entrada los tres vértices de un triángulo y usa esta información para generar (o realizar un teselado) triángulos adicionales, que son enviados al proceso de renderizado (rendering pipeline).
La librería Direct3D 10 introduce los Sombreadores de Vértices (Vertex Shaders - VS) y los Sombreadores de Pixel (Pixel Shaders - PS) unificados.
El Sombreador de Vértices (Vertex Shader - VS) es una etapa de procesamiento gráfico dentro del proceso de renderizado (rendering pipeline), utilizada para añadir efectos especiales a los objetos en un entorno 3D. Estos se ejecutan una vez para cada vértice dado al procesador gráfico. El objetivo es transformar la posición 3D de cada vértice en el espacio virtual para la coordinación de 2D, la que aparece en pantalla, así como un valor de profundidad para la memoria temporal (buffer) de profundidad (Z-Buffer) (explicado a continuación en detalle). Pueden manipular también las propiedades tales como la posición, color y coordinación de texturas, pero no puede crear nuevos vértices.
Todo esto da libertad a los programadores para realizar diferentes efectos, desde la deformación de un objeto hasta la recreación de las olas del mar. En caso de representaciones gráficas de pelo se basaría en los vértices de la malla dando un efecto más realista al resultado, lo que conlleva una rápida ejecución de la imagen puesto que se utiliza el hardware especifico, en este caso el de las tarjetas gráficas.
Lo que en realidad pretende esta herramienta es añadir a una malla de polígonos, elementos que se alojan en los vértices de dichos polígonos o simplemente modificarlos.
Se denomina "Z-Buffer" o "Z-Buffering" a la gestión de profundidad de las coordenadas de una imagen en tres dimensiones (3D) que generalmente se realiza por hardware, en los núcleos de procesamiento de las tarjetas gráficas. Aunque también se realiza por software en el caso que la tarjeta gráfica no lo soporte o que esté específicamente programado para ello.
Se trata de una solución al problema de la visibilidad, que es el problema de decidir qué elementos de una escena renderizada son visibles y cuales son los que están ocultos debido a que en la perspectiva existen otros objetos que están delante y lo tapan, o bien debido a que el elemento están tan lejos en el plano, que nunca se vería. El "Algoritmo del Pintor" es otra solución común que, aunque menos eficiente, también puede manejar elementos de una escena no opacos.
Cuando un objeto se representa por una tarjeta gráfica 3D, la profundidad de un píxel generado (coordenada z) se almacena en una ubicación de la memoria denominada en inglés "buffer", por lo que al almacenamiento de esta profundidad de pixel se la denomina "Z-Buffer" o "Memoria Temporal (Buffer) de Profundidad".
Esta memoria temporal se coloca normalmente como una matriz de dos dimensiones (x-y) con un elemento por cada pixel de la pantalla. Si otro objeto de la escena debe ser renderizado en el mismo pixel, la tarjeta gráfica compara las dos profundidades y elige el más cercano al observador. La profundidad elegida se guarda ahora en la memoria temporal de profundidad (Z-Buffer), reemplazando a la antigua. Al final, la memoria temporal de profundidad (Z-Buffer) permitirá que la tarjeta gráfica pueda reproducir correctamente la percepción de profundidad: un objeto cercano oculta a otro más lejano. A esto se le llama Sacrificio de Profundidad (Z-Culling).
La granularidad de la memoria temporal de profundidad (Z-Buffer) tiene una gran influencia en la calidad de la escena: una memoria temporal de profundidad (Z-Buffer) de 16-bit puede provocar errores cuando dos objetos están muy cerca uno del otro. A esto se le llama Lucha de Profundidad (Z-Fighting). A 24-bit o 32-bit la memoria temporal de profundidad (Z-Buffer) se comporta mucho mejor, aunque el problema no puede ser totalmente eliminado sin algoritmos adicionales. Una memoria temporal de profundidad (Z-Buffer) de 8-bit casi nunca se utiliza, debido a que tiene una precisión muy pequeña.
El Sombreador de Píxel (Pixel Shader - PS) es una etapa del núcleo de programación de la unidad de procesamiento gráfico (GPU) dentro del proceso de renderizado (rendering pipeline) que calcula el color y otros atributos de cada píxel. Sus funciones van desde producir siempre el mismo color, hasta la aplicación de valores de iluminación, Mapeado de Relieves (Bump Mapping) (explicado a continuación en detalle), sombras, luces especulares, transparencia y otros efectos. Pueden alterar la profundidad del píxel (para la memoria temporal de profundidad Z-Buffer), o la salida de más de un color si hay varios destinos de renderizado activos.
Un Sombreador de Píxel (Pixel Shader - PS) por sí solo no puede producir efectos muy complejos sin el conocimiento de la geometría de una escena, ya que sólo funciona en un solo píxel.
A la izquierda una esfera sin Mapeado de Relieve (Bump Mapping). En el centro, el mapa de relieve que va a aplicarse a la esfera mediante la técnica de Mapeado de Relieve (Bump Mapping). A la derecha puede verse la esfera con el mapa aplicado que le da un aspecto a la superficie moteada parecido a una naranja. Los mapas de relieve consiguen este efecto cambiando la forma de como un objeto iluminado reacciona ante la luz sin modificar el tamaño o la geometría de la superficie. |
El Mapeado de Relieves (Bump Mapping), es una técnica de gráficos de ordenador en 3D creada por James F. Blinn en 1978. Consiste en dar un aspecto rugoso a las superficies de los objetos. Se emplea para dar un efecto de relieve en las superficies de los objetos.
Esta técnica modifica las normales de la superficie sin cambiar su geometría. Las normales originales de la superficie seguirán perpendiculares a la misma. El Mapeado de Relieves (Bump Mapping) cambia la perpendicularidad por otras normales para lograr el efecto deseado, todo ello sin modificar la topología ni la geometría del objeto. El resultado es razonablemente rico y detallado, y pueden lograrse grandes parecidos a elementos naturales (como la textura de una naranja como muestra la imagen superior izquierda).
La técnica de Mapeado de Relieves (Bump Mapping) consiste en aplicar un mapa de relieve ("Bump Map"), un mapa o patrón que contiene la textura, relieve, o imagen del aspecto que se le quiere dar a la superficie. Los mapas de relieve ("Bump Map") consiguen este efecto cambiando la forma de como un objeto iluminado reacciona ante la luz sin modificar el tamaño o la geometría de la superficie.
Podemos ver un ejemplo claro de Mapeado de Relieves (Bump Mapping) en la imagen superior izquierda donde se puede ver una esfera lisa, un mapa de relieve, y la esfera con el mapa de relieve aplicado mediante Mapeado de Relieves (Bump Mapping).
El Mapeado de Relieves (Bump Mapping) es limitado debido a que al no modificar la forma del objeto subyacente, ni su silueta ni su sombra se ven afectados como muestra la esfera de la izquierda. La esfera de la derecha utiliza un mapa de relieve similar pero con una función de "Mapeado de Desplazamiento (Displacement Mapping)" o una función "isosurface" para modificar el tamaño y la geometría de la esfera subyacente. Como se puede observar en la imagen de la derecha, tanto la silueta como la sombra están afectadas. |
La diferencia entre la técnica de Mapeado de Desplazamiento (Displacement Mapping) y Mapeado de Relieves (Bump Mapping) es que con este último no se perturba la geometría, solo la dirección del campo normal, como ya se ha explicado anteriormente.
En la imagen de la derecha podemos observar las limitaciones del Mapeado de Relieves (Bump Mapping), debido a que al no modificar la forma del objeto subyacente, ni su silueta ni su sombra se ven afectados, como muestra la esfera de la izquierda. La esfera de la derecha utiliza un mapa de relieve similar pero con una función de Mapeado de Desplazamiento (Displacement Mapping) o una función "isosurface" (análogo tridimensional de una isolínea, superficie que representa los puntos de un valor constante como presión, temperatura, velocidad, densidad, dentro de un volumen del espacio, es decir, se trata de un nivel establecido de una función continua cuyo dominio es el espacio tridimensional) para modificar el tamaño y la geometría de la esfera subyacente. Como se puede observar en la imagen superior de la derecha, con el Mapeado de Desplazamiento (Displacement Mapping) tanto la silueta como la sombra están afectadas.
Además, Direct3D 10 también soporta Sombreador de Geometría (Geometric Shader - GS), que opera en todas las primitivas geométricas (puntos, líneas y triángulos), y permite también cálculos basados en primitivas adyacentes. La salida del Sombreador de Geometría (Geometric Shader - GS) puede pasar directamente al principio del proceso de renderizado (rendering pipeline) para la interpolación y el sombreador de píxel (pixel shader), o escribir en un búfer de vértice (conocido como 'stream out') que se alimenta de nuevo en el comienzo del proceso de renderizado (rendering pipeline).
El Sombreador de Geometría (Geometric Shader - GS) es un modelo de programación de sombreador introducido en DirectX 10 con el Modelo de Sombreador versión 4.0 (Shader Model 4.0). Las primeras tarjetas gráficas en soportar el Sombreador de Geometría (Geometric Shader - GS) fueron los modelos GeForce 8800 de nVidia.
Un Sombreador de Geometría (Geometric Shader - GS) puede generar nuevas primitivas gráficas, como los puntos, las líneas o los triángulos. Estas primitivas creadas son enviadas al principio del proceso de renderizado (rendering pipeline). Los programas del Sombreador de Geometría (Geometric Shader - GS) son ejecutados después de los sombreadores de vértices (vertex shaders). Toman como entrada un conjunto de primitivas, posiblemente con información adjunta.
Por ejemplo, cuando se opera en triángulos, los tres vértices son la entrada del Sombreador de Geometría (Geometric Shader - GS). El sombreador puede emitir cero o más primitivas, que son renderizadas y sus fragmentos al final son pasados al sombreador de píxel (pixel shader).
Algunos de los típicos usos del Sombreador de Geometría (Geometric Shader - GS) son, por ejemplo, la generación de un punto de sprite, teselado geométrico, extrusión de la sombra del volumen y el renderizado de un solo paso a un Mapa de Cubo (Cube Map), explicado en detalle más adelante. Un ejemplo típico y muy usado de los beneficios que aporta el Sombreador de Geometría (Geometric Shader - GS) podría ser la compleja modificación automática de una malla. Una serie de líneas representan los puntos de control para una curva que es pasada al Sombreador de Geometría (Geometric Shader - GS) y dependiendo de la complejidad requerida, el sombreador (shader) automáticamente puede generar líneas extra, cada una de las cuales permiten obtener una mejor aproximación de la curva.
La imagen inferior izquierda muestra una escena con un punto de vista o cámara marcados con un punto negro. La imagen superior muestra la red del mapeado de cubo (cube mapping) tal y como se verá desde ese punto de vista o cámara, y la imagen inferior derecha muestra el cubo superpuesto a la escena original. |
El Mapeado de Cubo (Cube Mapping), es un método de mapeo o diseño de un entorno que utiliza un cubo de seis caras como la forma del mapa. El entorno se proyecta sobra las seis caras de un cubo y se almacena como seis texturas cuadradas o se despliega en seis regiones de una textura única. El mapa del cubo (cube map) se genera primero renderizando la escena seis veces desde un punto de vista, con las vistas definidas por una vista de tronco (Frustum) ortogonal de 90 grados, que representan a cada cara o lado del cubo.
En la mayoría de los casos, se prefiere el mapeado de cubo (cube mapping) antes que el método antiguo del mapeado de esfera (sphere mapping) debido a que el mapeado de cubo (cube mapping) elimina muchos de los problemas inherentes al mapeado de esfera (sphere mapping), como son la distorsión de la imagen, dependencia del punto de vista o cámara, o problemas de rendimiento o eficiencia.
Además el mapeado de cubo (cube mapping) provee mucha más capacidad para soportar renderizados en tiempo real frente al mapeado de esfera (sphere mapping) porque la combinación de ineficiencia de este último junto con una dependencia del punto de vista o cámara limita de una manera importante y radical la habilidad de aplicar el mapeado de esfera cuando hay un punto de vista o cámara que están cambiando constantemente.
Esta imagen muestra una línea muy fina sin antialiasing donde se puede apreciar, si uno se fija de cerca, los bordes de sierra, a su lado a la derecha la misma línea ampliada, y en el cuadro de la derecha de la misma imagen se aprecia la misma línea con antialiasing donde se consigue mediante un filtro y desenfocando en este caso lo bordes, que se pierda ese efecto de sierra y parezca a nuestros ojos una línea perfecta. |
Por aliasing, traducido por algunos autores como solapamiento, se conoce a un fallo producido en la representación de los gráficos debido a que la resolución final es finita y es mostrada siempre en una resolución inferior, por lo que se producen interferencias (defectos o artificios). Esto ocurre debido a los problemas de muestreo (a resoluciones muy altas) y reconstrucción (a resoluciones mucho más bajas).
Existen diferentes tipos de aliasing visual, pero normalmente nos referimos al aliasing geométrico, efecto que consiste en la presencia de dientes de sierra en los bordes de los polígonos. El efecto de aliasing da a las imágenes una apariencia tosca, que reduce la calidad de las imágenes generadas dando una sensación de irrealidad (artificialidad) de las mismas en los gráficos generados.
Por antialiasing se conoce al procedimiento de eliminar o disimular el efecto producido por el aliasing. Esto se consigue filtrando la imagen para suavizar los bordes y disimular los bordes de los polígonos, consiguiendo una apariencia mucho más realista. La imagen superior de la derecha muestra a la izquierda una línea muy fina sin antialiasing donde se puede apreciar, si uno se fija de cerca, los bordes de sierra, al lado de esta imagen a la derecha la misma línea ampliada; y a la derecha se muestra la misma línea con antialiasing conseguido mediante un filtro y desenfocando en este caso lo bordes, para eliminar ese efecto de sierra y que parezca ante nuestros ojos una línea perfecta.
En imágenes reales este efecto se traduce en ver los bordes de los objetos con dientes de sierra. La siguiente imagen muestra 3 ejemplos de un mismo dibujo. Sin antialiasing, con antialiasing 2x y con antialiasing 4x. Fijarse en los bordes de la chimenea así como en el palo que sujeta los dos estandartes.
Esta imagen muestra 3 ejemplos de un mismo dibujo. Sin antialiasing, con antialiasing 2x y con antialiasing 4x. Fijarse en los bordes de la chimenea así como en el palo que sujeta los dos estandartes. |
La técnicas para hacer antialiasing son muchas y muy diversas pero nos centraremos en las principales:
El Supermuestreo de Patrón Ordenado (Supersampling Ordered Grid) consiste en escalar la imagen multiplicando la resolución de los ejes X e Y por un número entero (2X, 4X, 8X, etc.), para renderizarla a mayor tamaño del original. Tras realizar este proceso, se pasa al tamaño original mediante un filtro de reducción, por lo que varios píxeles de la imagen renderizada a mayor resolución se utilizan para calcular el valor de los píxeles de la resolución final. De este modo se consiguen transiciones más suaves. El valor de color se da en función del número de puntos centrales de los subpíxeles que quedan dentro del triángulo, en cada pixel.
El Supermuestreo de Patrón Rotado (Supersampling Rotated Grid) es una forma de realizar el antialiasing en la cual se puede conseguir mejores resultados visuales que con el Supermuestreo de Patrón Ordenado con el mismo coste en rendimiento, mediante la elección de una mejor posición del punto de muestreo en los subpíxeles. Posteriormente se explicará el motivo por el cual es mejor un patrón rotado a la hora de elegir los subpíxeles que uno ordenado, con un ejemplo aplicado al multimuestreo.
La figura (a) de la imagen superior muestra un patrón ordenado mientras la figura (b) muestra un patrón rotado. |
El Multimuestreo es una de la nuevas formas de antialiasing y según muchas especificaciones se refiere al mismo como una optimización específica del supermuestreo. La diferencia radica en que solo se calcula un valor de la textura por pixel, en vez de un valor por cada subpixel como en el supermuestreo. Mientras que en el supermuestreo se renderiza la imagen al completo a mayor resolución de la original, en el multimuestreo solo se hace para la geometría, no para las texturas. Esto ahorra tanto tasa de relleno como ancho de banda. El ahorro es menor en ancho de banda debido a que aunque solo se genera un valor de color por pixel, lo que ahorra tasa de relleno, este valor debe ser almacenado por separado para cada subpixel.
Por todo esto el multimuestreo consigue hacer antialiasing mucho más rápido y el coste en rendimiento es mucho mejor. Aunque consigue eliminar todo el aliasing de los bordes de los polígonos, podría no conseguir eliminar todo el aliasing dentro un polígono.
A la hora de posicionar los subpíxeles, se puede elegir entre un patrón ordenado o un patrón rotado.
La ventaja de utilizar un patrón rotado es que se obtienen degradados de color más suaves, lo que permite una calidad muy superior con la misma pérdida de rendimiento. Un patrón 4x ordenado dobla la exactitud a la hora de realizar el muestreo en ambos ejes respecto a no utilizar antialiasing, mientras que con un patrón 4x rotado obtenemos cuatro veces la exactitud de muestreo de una imagen sin antialiasing.
Con el patrón rotado se consigue una transición más suave, por lo que se obtiene una imagen de mayor calidad con el mismo consumo de recursos. Con un patrón rotado 2x se consigue una exactitud de muestreo similar a la que se obtiene con un patrón ordenado 4x, pero tomando únicamente la mitad de muestras, lo que permite una calidad similar con mucho menor pérdida de rendimiento.
Las tarjetas gráficas de nVidia anteriores a la serie GeForce 6 utilizaban un patrón ordenado para hacer el antialiasing, desde la serie GeForce 6 y posteriores utilizan un patrón rotado. En el caso de las tarjetas gráficas de ATI, las tarjetas anteriores al modelo Radeon 9500 utilizaban un patrón ordenado, y ya desde el modelo Radeon 9500 utilizan un patrón rotado para hacer el antialiasing.
Para solucionar el problema del aliasing en las texturas transparentes, tanto nVidia como ATI han desarrollado técnicas de antialiasing mixtas, que realizan supermuestreo (supersampling) únicamente en las texturas alfa.
Los llamados antialiasing transparente (en la serie 7 de las tarjetas GeForce) y el antialiasing adaptativo (en las tarjetas de ATI desde la 9500) realizan este proceso, con un consumo de tasa de relleno proporcional a la utilización de texturas transparentes en pantalla. A mayor utilización de texturas transparentes, mayor será la reducción de prestaciones que tendremos.
La ventaja es que conseguimos una calidad de imagen muy similar a la del supermuestreo (supersampling), pero con un rendimiento muy superior. Esto hace que en las tarjetas modernas se esté abandonando el supermuestreo (supersampling) debido a que la mejora en calidad visual no compensa frente a la pérdida de rendimiento que conlleva esta técnica.
Desde los inicios del 3D por hardware (procesador gráfico - GPU), cuando esta aplica texturas a los polígonos, aplica además un filtrado a toda la escena, que en sus inicios era del tipo Bilinear. Luego, cuando la potencia de estas fue aumentando se empezó a aplicar un método más avanzado llamado Trilinear, y que resultaba en una mejor calidad final en las texturas con un rendimiento que ya empezaba a ser aceptable.
Pero donde entra la calidad del tipo de filtrado, es en el número de muestras que este coge de la textura, y de si el filtro se aplica isotrópicamente (en una dirección) o anisotrópicamente (en todas las direcciones). Pero esto tiene un coste en cuestión de rendimiento y por eso la primera tarjeta gráfica en usar filtro trilinear anisotrópico de 8 muestras (8x) a velocidad aceptable fue la nVidia GeForce256. Con el tiempo y debido al increíble aumento del potencial de las tarjetas gráficas, se ha ido aumentando el número de muestras de anisotropía hasta 32 ó 64 muestras.
El filtrado anisotrópico mezcla la función de aplicar una textura en todas sus dimensiones, implementando filtrados bilineales o trilineales de forma mucho más precisa para difuminar las líneas de los píxeles, en función del ángulo y la distancia desde la que se visualizan. En definitiva, logra que las texturas tengan un aspecto más realista y evita que se produzcan "bailes de píxeles" o aliasing con texturas que están a mayor distancia o en ángulos oblicuos desde nuestra perspectiva. Merece la pena activarlo en entornos bajo OpenGL o Direct3D, aunque sólo si dispones de una tarjeta de última generación, ya que sino puede afectar gravemente el rendimiento.
Como podéis observar en las imágenes siguientes, en la de la izquierda el filtro anisotrópico está desactivado y se aprecia fácilmente en la calidad de la textura del suelo ya que en la distancia pierde mucha definición y se vuelve muy borrosa en comparación con la calidad de la textura de ese mismo suelo que está más cerca de nosotros. Sin embargo, en la imagen de la derecha el filtrado anisotrópico está activado y podemos ver que la textura mantiene la misma calidad en la primera parte del suelo (más cerca de nosotros) que al final (en la distancia).
En una palabra, que sin filtro anisotrópico una textura pierde calidad y se vuelve borrosa en la lejanía y con el filtro anisotrópico activado no.
En la imagen de la izquierda el filtro anisotrópico está desactivado y se aprecia fácilmente en la calidad de la textura del suelo ya que en la distancia pierde mucha definición y se vuelve muy borrosa en comparación con la calidad de la textura de ese mismo suelo que está más cerca de nosotros. Sin embargo, en la imagen de la derecha el filtrado anisotrópico está activado y podemos ver que la textura mantiene la misma calidad en la primera parte del suelo (más cerca de nosotros) que al final (en la distancia). |
El Renderizado de Alto Rango Dinámico (High Dynamic Range Rendering - HDRR) es un método de renderizado que utiliza la tecnología de Alto Rango Dinámico (High Dynamic Range - HDR) para calcular la iluminación de las escenas con precisión y realismo mediante la realización de cálculos de iluminación en un rango dinámico mucho mayor. Esto permite la preservación de detalles que se pueden perder debido a la limitación de la relación de contraste.
nVidia resume esta característica en tres puntos:
El Renderizado de Alto Rango Dinámico (High Dynamic Range Rendering - HDRR) no fue posible hasta DirectX 9.0c en Agosto de 2004, que incluía el Modelo de Sombreador en su versión 3.0 (Shader Model 3.0) y permite una precisión de iluminación de 32 bits con cálculos en coma flotante. El Modelo de Sombreador versión 4.0 (Shader Model 4.0) incluido en DirectX 10, permite renderizados de Alto Rango Dinámico (High Dynamic Range) de 128-bit y el Modelo de Sombreador versión 5.0 (Shader Model 5.0), incluido en DirectX 11, permite además una compresión de 6 a 1 en las texturas de Alto Rango Dinámico (High Dynamic Range) sin ninguna pérdida apreciable.
En la siguiente imagen podemos apreciar la clara diferencia de la iluminación en un renderizado con Alto Rango Dinámico (HDR) comparando la imagen de la izquierda (renderizada sin Alto Rango Dinámico) con la de la derecha (renderizada con Alto Rango Dinámico):
En esta imagen podemos apreciar la clara diferencia de la iluminación en un renderizado con Alto Rango Dinámico comparando la imagen de la izquierda (renderizada sin Alto Rango Dinámico) con la de la derecha (renderizada con Alto Rango Dinámico). |
DirectX 10.1 fue lanzado por Microsoft como una actualización menor al poco tiempo de haber lanzado DirectX 10 y estaba incluido en el Service Pack 1 de Windows Vista y requería también de hardware específico para DirectX 10.1.
En un principio solo ATI tuvo disponibles sus tarjetas Radeon HD de las series 3000 y 4000 preparadas para DirectX 10.1. Mucho más tarde nVidia solo tuvo una pequeña selección de su gama más baja de tarjetas gráficas de la serie GeForce 200 preparadas para DirectX 10.1. Otras gráficas como las Chrome 430/440GT de S3 estaban también preparadas para DirectX 10.1. Sin embargo, los chips gráficos de Intel GMA nunca soportaron DirectX 10.1.
A diferencia de Direct3D 10, que requiere estrictamente de hardware (tarjetas gráficas) y controladores que estén diseñados y certificados para DirectX 10, Direct3D 10.1 puede funcionar en hardware diseñado solo para DirectX 10.0 usando un concepto nuevo de "niveles de rendimiento". Pero las nuevas características de DirectX 10.1 solo serán soportadas en hardware (tarjetas gráficas) y controladores que estén diseñados y certificados para DirectX 10.1.
Direct3D 10.1 estableció un nuevo estándar de calidad gráfica un poco mayor para los fabricantes de tarjetas gráficas y permitió un mayor control de los programadores y desarrolladores sobre la calidad de la imagen. Entre las nuevas características se incluye un control más fino y ajustado del antialiasing (tanto por multimuestreo, multisampling, como por supermuestreo, supersampling, con sombreador por muestra y control de la aplicación a través de la posición de la muestra) y mayor flexibilidad en algunas de las características ya existentes en Direct3D 10 (como las matrices de mapas de cubo e independientes modos de fusión).
Direct3D 10.1 ofrece entre un 20% y un 25% más de rendimiento como se puede observar en el siguiente vídeo que compara los fotogramas por segundo frente a DirectX 10. En este vídeo, la mejora de calidad gráfica es prácticamente inapreciable.
Para DirectX 10.1 / Direct3D 10.1 se tienen que soportar las siguientes características a nivel de hardware:
El Modelo de Sombreador versión 4.1 (Shader Model 4.1) tiene entre las nuevas características la capacidad para seleccionar el patrón de muestra para realizar el antialiasing por multimuestreo (MSAA) para un recurso de una paleta de patrones y recuperar las posiciones de la muestra correspondiente.
De hecho, la tarjeta gráfica tiene que soportar un antialising multimuestra (MSAA) de 2x, 4x y 8x y con exactamente los mismos patrones de muestra, lo que implica un muy significativo aumento del rendimiento y de la calidad.
Además, el Modelo de Sombreador versión 4.1 (Shader Model 4.1) incluye una serie de características nuevas de representación, como la dinámica de las matrices de texturas de cubo y bloque comprimido de texturas.
El Modelo de Sombreador versión 4.1 (Shader Model 4.1) soporta además el filtro de texturas de alta calidad Gather4, un nuevo muestreo de texturas disponible en Direct3D 10.1 que ya estaba expuesto anteriormente en Direct3D 9 con el nombre de Fetch4 a través de códigos específicos FOURCC independientes del hardware.
Con el muestreo fluctuado, los gráficos en 3D pueden aplicar sombras mucho más suaves y detalladas o filtros de texturas personalizados más eficientemente.