Puerto de GLSL
API importantes
Una vez que haya pasado por el código que crea y configura los búferes y los objetos de sombreador, es el momento de portar el código dentro de esos sombreadores de OpenGL ES 2.0 del Lenguaje de sombreador GL (GLSL) a Direct3D 11's High-Level Shader Language (HLSL).
En OpenGL ES 2.0, los sombreadores devuelven datos después de la ejecución mediante intrínsecos como gl_Position, gl_FragColor o gl_FragData[n] (donde n es el índice de un destino de representación específico). En Direct3D, no hay ningún intrínseco específico y los sombreadores devuelven datos como el tipo de valor devuelto de sus respectivas funciones main().
Los datos que desea interpolar entre las fases del sombreador, como la posición del vértice o la normal, se controlan mediante el uso de la declaración variable . Sin embargo, Direct3D no tiene esta declaración; en su lugar, los datos que desee pasar entre las fases del sombreador deben marcarse con una semántica de HLSL. La semántica específica elegida indica el propósito de los datos y es. Por ejemplo, declararía datos de vértices que desea interpolar entre el sombreador de fragmentos como:
float4 vertPos : POSITION;
o
float4 vertColor : COLOR;
Donde POSITION es la semántica usada para indicar los datos de posición de vértices. POSITION también es un caso especial, ya que después de la interpolación, el sombreador de píxeles no puede acceder a él. Por lo tanto, debe especificar la entrada en el sombreador de píxeles con SV_POSITION y los datos de vértices interpolados se colocarán en esa variable.
float4 position : SV_POSITION;
La semántica se puede declarar en los métodos body (main) de los sombreadores. En el caso de los sombreadores de píxeles, SV_TARGET[n], que indica un destino de representación, es necesario en el método body. (SV_TARGET sin un sufijo numérico predeterminado para representar el índice de destino 0).
Tenga en cuenta también que los sombreadores de vértices son necesarios para generar la semántica del valor del sistema SV_POSITION. Esta semántica resuelve los datos de posición de vértice para coordinar los valores en los que x está entre -1 y 1, y está comprendido entre -1 y 1, z se divide por el valor homogéneo original w (z/w) y w es 1 dividido por el valor w original (1/w). Los sombreadores de píxeles usan la semántica de valor del sistema de SV_POSITION para recuperar la ubicación del píxel en la pantalla, donde x está entre 0 y el ancho de destino de representación e y está entre 0 y el alto de destino de representación (cada desplazamiento por 0,5). El nivel de característica 9_x sombreadores de píxeles no puede leer del valor de SV_POSITION.
Los búferes de constantes deben declararse con cbuffer y estar asociados a un registro inicial específico para la búsqueda.
Direct3D 11: una declaración de búfer de constantes HLSL
cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
matrix mvp;
};
Aquí, el búfer de constantes usa el registro b0 para contener el búfer empaquetado. Se hace referencia a todos los registros con el formato b#. Para obtener más información sobre la implementación de HLSL de búferes de constantes, registros y empaquetado de datos, lea Constantes de sombreador (HLSL) .
Instrucciones
Paso 1: Migrar el sombreador de vértices
En nuestro sencillo ejemplo de OpenGL ES 2.0, el sombreador de vértices tiene tres entradas: una matriz de proyección de vista de modelo constante 4x4 y dos vectores de 4 coordenadas. Estos dos vectores contienen la posición del vértice y su color. El sombreador transforma el vector de posición en coordenadas de perspectiva y lo asigna al gl_Position intrínseco para la rasterización. El color del vértice también se copia en una variable variable para la interpolación durante la rasterización.
OpenGL ES 2.0: sombreador de vértices para el objeto de cubo (GLSL)
uniform mat4 u_mvpMatrix;
attribute vec4 a_position;
attribute vec4 a_color;
varying vec4 destColor;
void main()
{
gl_Position = u_mvpMatrix * a_position;
destColor = a_color;
}
Ahora, en Direct3D, la matriz de proyección de vista de modelo constante se encuentra en un búfer de constantes empaquetado en el registro b0, y la posición y el color del vértice se marcan específicamente con la semántica HLSL correspondiente: POSITION y COLOR. Dado que nuestro diseño de entrada indica una disposición específica de estos dos valores de vértice, se crea una estructura para contenerlos y se declara como el tipo para el parámetro de entrada en la función body del sombreador (main). (También puede especificarlos como dos parámetros individuales, pero eso podría resultar complicado). También se especifica un tipo de salida para esta fase, que contiene la posición interpolada y el color, y se declara como el valor devuelto para la función body del sombreador de vértices.
Direct3D 11: sombreador de vértices para el objeto de cubo (HLSL)
cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
matrix mvp;
};
// Per-vertex data used as input to the vertex shader.
struct VertexShaderInput
{
float3 pos : POSITION;
float3 color : COLOR;
};
// Per-vertex color data passed through the pixel shader.
struct PixelShaderInput
{
float3 pos : SV_POSITION;
float3 color : COLOR;
};
PixelShaderInput main(VertexShaderInput input)
{
PixelShaderInput output;
float4 pos = float4(input.pos, 1.0f); // add the w-coordinate
pos = mul(mvp, projection);
output.pos = pos;
output.color = input.color;
return output;
}
El tipo de datos de salida, PixelShaderInput, se rellena durante la rasterización y se proporciona al sombreador de fragmentos (píxeles).
Paso 2: Portar el sombreador de fragmentos
Nuestro sombreador de fragmentos de ejemplo en GLSL es extremadamente sencillo: proporcione el gl_FragColor intrínseco con el valor de color interpolado. OpenGL ES 2.0 lo escribirá en el destino de representación predeterminado.
OpenGL ES 2.0: sombreador de fragmentos para el objeto de cubo (GLSL)
varying vec4 destColor;
void main()
{
gl_FragColor = destColor;
}
Direct3D es casi tan simple. La única diferencia significativa es que la función body del sombreador de píxeles debe devolver un valor. Dado que el color es un valor flotante de 4 coordenadas (RGBA), se indica float4 como tipo de valor devuelto y, a continuación, se especifica el destino de representación predeterminado como semántica de valor del sistema SV_TARGET.
Direct3D 11: sombreador de píxeles para el objeto de cubo (HLSL)
struct PixelShaderInput
{
float4 pos : SV_POSITION;
float3 color : COLOR;
};
float4 main(PixelShaderInput input) : SV_TARGET
{
return float4(input.color, 1.0f);
}
El color del píxel en la posición se escribe en el destino de representación. Ahora, veamos cómo mostrar el contenido de ese destino de representación en Draw en la pantalla.
Paso anterior
Portabilidad de los búferes de vértices y los datos
Paso siguiente
Comentarios
Comprender la semántica de HLSL y el empaquetado de búferes de constantes puede ahorrarle un poco de dolor de cabeza de depuración, así como proporcionar oportunidades de optimización. Si tiene una oportunidad, lea la sintaxis de variables (HLSL), Introducción a los búferes en Direct3D 11 y Cómo: Crear un búfer de constantes. Sin embargo, si no es así, estas son algunas sugerencias de inicio que se deben tener en cuenta sobre la semántica y los búferes de constantes:
- Compruebe siempre el código de configuración de Direct3D del representador para asegurarse de que las estructuras de los búferes de constantes coinciden con las declaraciones de struct de cbuffer en HLSL y que los tipos escalares del componente coinciden en ambas declaraciones.
- En el código de C++ del representador, use los tipos DirectXMath en las declaraciones de búfer de constantes para garantizar el empaquetado de datos adecuado.
- La mejor manera de usar de forma eficaz los búferes de constantes es organizar las variables del sombreador en búferes de constantes en función de su frecuencia de actualización. Por ejemplo, si tiene algunos datos uniformes que se actualizan una vez por fotograma y otros datos uniformes que se actualizan solo cuando la cámara se mueve, considere la posibilidad de separar esos datos en dos búferes de constantes independientes.
- La semántica que ha olvidado aplicar o que ha aplicado incorrectamente será la primera fuente de errores de compilación del sombreador (FXC). ¡Compruébalos! Los documentos pueden ser un poco confusos, ya que muchas páginas y ejemplos anteriores hacen referencia a diferentes versiones de la semántica de HLSL antes de Direct3D 11.
- Asegúrese de saber qué nivel de característica de Direct3D está destinado a cada sombreador. La semántica del nivel de característica 9_* es diferente de la de 11_1.
- La semántica de SV_POSITION resuelve los datos de posición posterior a la interpolación asociados para coordinar los valores en los que x está comprendido entre 0 y el ancho del destino de representación, y está entre 0 y el alto del destino de representación, z se divide por el valor w de coordenada homogéneo original (z/w) y w es 1 dividido por el valor w original (1/w).
Temas relacionados
Cómo: migrar un representador de OpenGL ES 2.0 simple a Direct3D 11
Migrar los objetos del sombreador
Portabilidad de los búferes de vértices y los datos