Compartir a través de


Migrar los objetos del sombreador

API importantes

Al migrar el representador simple desde OpenGL ES 2.0, el primer paso es configurar los objetos equivalentes de sombreador de vértices y fragmentos en Direct3D 11 y asegurarse de que el programa principal pueda comunicarse con los objetos del sombreador después de compilar.

Nota:

¿Ha creado un nuevo proyecto de Direct3D? Si no es así, siga las instrucciones de Creación de un nuevo proyecto de DirectX 11 para Plataforma universal de Windows (UWP). En este tutorial se supone que ha creado los recursos DXGI y Direct3D para dibujar en la pantalla y que se proporcionan en la plantilla.

Al igual que OpenGL ES 2.0, los sombreadores compilados en Direct3D deben estar asociados con un contexto de dibujo. Sin embargo, Direct3D no tiene el concepto de un objeto de programa de sombreador por se; en su lugar, debe asignar los sombreadores directamente a un ID3D11DeviceContext. Este paso sigue el proceso de OpenGL ES 2.0 para crear y enlazar objetos de sombreador, y proporciona los comportamientos de API correspondientes en Direct3D.

Instrucciones

Paso 1: Compilar los sombreadores

En este sencillo ejemplo de OpenGL ES 2.0, los sombreadores se almacenan como archivos de texto y se cargan como datos de cadena para la compilación en tiempo de ejecución.

OpenGL ES 2.0: Compilar un sombreador

GLuint __cdecl CompileShader (GLenum shaderType, const char *shaderSrcStr)
// shaderType can be GL_VERTEX_SHADER or GL_FRAGMENT_SHADER. Returns 0 if compilation fails.
{
  GLuint shaderHandle;
  GLint compiledShaderHandle;
   
  // Create an empty shader object.
  shaderHandle = glCreateShader(shaderType);

  if (shaderHandle == 0)
  return 0;

  // Load the GLSL shader source as a string value. You could obtain it from
  // from reading a text file or hardcoded.
  glShaderSource(shaderHandle, 1, &shaderSrcStr, NULL);
   
  // Compile the shader.
  glCompileShader(shaderHandle);

  // Check the compile status
  glGetShaderiv(shaderHandle, GL_COMPILE_STATUS, &compiledShaderHandle);

  if (!compiledShaderHandle) // error in compilation occurred
  {
    // Handle any errors here.
              
    glDeleteShader(shaderHandle);
    return 0;
  }

  return shaderHandle;

}

En Direct3D, los sombreadores no se compilan durante el tiempo de ejecución; siempre se compilan en archivos CSO cuando se compila el resto del programa. Al compilar la aplicación con Microsoft Visual Studio, los archivos HLSL se compilan en archivos CSO (.cso) que la aplicación debe cargar. Asegúrese de incluir estos archivos de CSO con la aplicación al empaquetarlo.

Nota En el ejemplo siguiente se realiza la carga del sombreador y la compilación de forma asincrónica mediante la sintaxis lambda y la palabra clave auto . ReadDataAsync() es un método implementado para la plantilla que lee en un archivo CSO como una matriz de datos de bytes (fileData).

 

Direct3D 11: Compilar un sombreador

auto loadVSTask = DX::ReadDataAsync(m_projectDir + "SimpleVertexShader.cso");
auto loadPSTask = DX::ReadDataAsync(m_projectDir + "SimplePixelShader.cso");

auto createVSTask = loadVSTask.then([this](Platform::Array<byte>^ fileData) {

m_d3dDevice->CreateVertexShader(
  fileData->Data,
  fileData->Length,
  nullptr,
  &m_vertexShader);

auto createPSTask = loadPSTask.then([this](Platform::Array<byte>^ fileData) {
  m_d3dDevice->CreatePixelShader(
    fileData->Data,
    fileData->Length,
    nullptr,
    &m_pixelShader;
};

Paso 2: Crear y cargar los sombreadores de vértices y fragmentos (píxeles)

OpenGL ES 2.0 tiene la noción de un sombreador "programa", que actúa como la interfaz entre el programa principal que se ejecuta en la CPU y los sombreadores, que se ejecutan en la GPU. Los sombreadores se compilan (o se cargan desde orígenes compilados) y se asocian a un programa, lo que permite la ejecución en la GPU.

OpenGL ES 2.0: Carga de los sombreadores de vértices y fragmentos en un programa de sombreado

GLuint __cdecl LoadShaderProgram (const char *vertShaderSrcStr, const char *fragShaderSrcStr)
{
  GLuint programObject, vertexShaderHandle, fragmentShaderHandle;
  GLint linkStatusCode;

  // Load the vertex shader and compile it to an internal executable format.
  vertexShaderHandle = CompileShader(GL_VERTEX_SHADER, vertShaderSrcStr);
  if (vertexShaderHandle == 0)
  {
    glDeleteShader(vertexShaderHandle);
    return 0;
  }

   // Load the fragment/pixel shader and compile it to an internal executable format.
  fragmentShaderHandle = CompileShader(GL_FRAGMENT_SHADER, fragShaderSrcStr);
  if (fragmentShaderHandle == 0)
  {
    glDeleteShader(fragmentShaderHandle);
    return 0;
  }

  // Create the program object proper.
  programObject = glCreateProgram();
   
  if (programObject == 0)    return 0;

  // Attach the compiled shaders
  glAttachShader(programObject, vertexShaderHandle);
  glAttachShader(programObject, fragmentShaderHandle);

  // Compile the shaders into binary executables in memory and link them to the program object..
  glLinkProgram(programObject);

  // Check the project object link status and determine if the program is available.
  glGetProgramiv(programObject, GL_LINK_STATUS, &linkStatusCode);

  if (!linkStatusCode) // if link status <> 0
  {
    // Linking failed; delete the program object and return a failure code (0).

    glDeleteProgram (programObject);
    return 0;
  }

  // Deallocate the unused shader resources. The actual executables are part of the program object.
  glDeleteShader(vertexShaderHandle);
  glDeleteShader(fragmentShaderHandle);

  return programObject;
}

// ...

glUseProgram(renderer->programObject);

Direct3D no tiene el concepto de un objeto de programa de sombreador. En su lugar, los sombreadores se crean cuando se llama a uno de los métodos de creación del sombreador en la interfaz ID3D11Device (como ID3D11Device::CreateVertexShader o ID3D11Device::CreatePixelShader). Para establecer los sombreadores para el contexto de dibujo actual, los proporcionamos a id3D11DeviceContext correspondiente con un método de sombreador set, como ID3D11DeviceContext::VSSetShader para el sombreador de vértices o ID3D11DeviceContext::P SSetShader para el sombreador de fragmentos.

Direct3D 11: establezca los sombreadores para el contexto de dibujo del dispositivo gráfico.

m_d3dContext->VSSetShader(
  m_vertexShader.Get(),
  nullptr,
  0);

m_d3dContext->PSSetShader(
  m_pixelShader.Get(),
  nullptr,
  0);

Paso 3: Definir los datos que se van a proporcionar a los sombreadores

En nuestro ejemplo de OpenGL ES 2.0, tenemos un uniforme para declarar para la canalización del sombreador:

  • u_mvpMatrix: una matriz 4x4 de floats que representa la matriz final de transformación de proyección de vista de modelo que toma las coordenadas del modelo para el cubo y las transforma en coordenadas de proyección 2D para la conversión de exámenes.

Y dos valores de atributo para los datos de vértices:

  • a_position: un vector flotante de 4 para las coordenadas del modelo de un vértice.
  • a_color: vector 4-float para el valor de color RGBA asociado al vértice.

Open GL ES 2.0: definiciones de GLSL para los uniformes y atributos

uniform mat4 u_mvpMatrix;
attribute vec4 a_position;
attribute vec4 a_color;

Las variables de programa principales correspondientes se definen como campos en el objeto representador, en este caso. (Consulte el encabezado en . Cómo: portar un representador de OpenGL ES 2.0 simple a Direct3D 11). Una vez hecho esto, es necesario especificar las ubicaciones en la memoria donde el programa principal proporcionará estos valores para la canalización del sombreador, que normalmente hacemos justo antes de una llamada a Draw:

OpenGL ES 2.0: Marcar la ubicación de los datos uniformes y de atributo


// Inform the shader of the attribute locations
loc = glGetAttribLocation(renderer->programObject, "a_position");
glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, 
    sizeof(Vertex), 0);
glEnableVertexAttribArray(loc);

loc = glGetAttribLocation(renderer->programObject, "a_color");
glVertexAttribPointer(loc, 4, GL_FLOAT, GL_FALSE, 
    sizeof(Vertex), (GLvoid*) (sizeof(float) * 3));
glEnableVertexAttribArray(loc);


// Inform the shader program of the uniform location
renderer->mvpLoc = glGetUniformLocation(renderer->programObject, "u_mvpMatrix");

Direct3D no tiene el concepto de un "atributo" o un "uniforme" en el mismo sentido (o, al menos, no comparte esta sintaxis). En su lugar, tiene búferes de constantes, representados como subrecursos de Direct3D: recursos que se comparten entre el programa principal y los programas de sombreador. Algunos de estos subrecursos, como posiciones y colores de vértices, se describen como semántica de HLSL. Para obtener más información sobre los búferes de constantes y la semántica de HLSL en relación con los conceptos de OpenGL ES 2.0, lea Objetos de búfer de fotogramas de puerto, uniformes y atributos.

Al mover este proceso a Direct3D, convertimos el uniforme en un búfer de constantes de Direct3D (cbuffer) y le asignamos un registro para la búsqueda con la semántica de HLSL de registro . Los dos atributos de vértice se controlan como elementos de entrada a las fases de canalización del sombreador y también se asignan semántica de HLSL (POSITION y COLOR0) que informan a los sombreadores. El sombreador de píxeles toma un SV_POSITION, con el prefijo SV_ que indica que es un valor del sistema generado por la GPU. (En este caso, es una posición de píxel generada durante la conversión del examen). VertexShaderInput y PixelShaderInput no se declaran como búferes de constantes porque el primero se usará para definir el búfer de vértices (vea Puerto de los búferes de vértices y datos) y los datos de este último se generan como resultado de una fase anterior en la canalización, que en este caso es el sombreador de vértices.

Direct3D: definiciones de HLSL para los búferes de constantes y los datos de vértices

cbuffer ModelViewProjectionConstantBuffer : register(b0)
{
  matrix mvp;
};

// Per-vertex data used as input to the vertex shader.
struct VertexShaderInput
{
  float4 pos : POSITION;
  float4 color : COLOR0;
};

// Per-vertex color data passed through the pixel shader.
struct PixelShaderInput
{
  float4 pos : SV_POSITION;
  float3 color : COLOR0;
};

Para obtener más información sobre cómo migrar a búferes de constantes y la aplicación de semántica de HLSL, lea Port frame buffer objects, uniforms, and attributes.

Estas son las estructuras para el diseño de los datos pasados a la canalización del sombreador con un búfer de vértices o constantes.

Direct3D 11: Declarar el diseño de búferes de vértices y constantes

// Constant buffer used to send MVP matrices to the vertex shader.
struct ModelViewProjectionConstantBuffer
{
  DirectX::XMFLOAT4X4 modelViewProjection;
};

// Used to send per-vertex data to the vertex shader.
struct VertexPositionColor
{
  DirectX::XMFLOAT4 pos;
  DirectX::XMFLOAT4 color;
};

Use los tipos DirectXMath XM* para los elementos de búfer de constantes, ya que proporcionan el empaquetado y la alineación adecuados para el contenido cuando se envían a la canalización del sombreador. Si usas los tipos flotantes y matrices estándar de la plataforma Windows, debes realizar el empaquetado y la alineación por ti mismo.

Para enlazar un búfer de constantes, cree una descripción de diseño como una estructura de CD3D11_BUFFER_DESC y pásela a ID3DDevice::CreateBuffer. A continuación, en el método render, pase el búfer de constantes a ID3D11DeviceContext::UpdateSubresource antes de dibujar.

Direct3D 11: Enlazar el búfer de constantes

CD3D11_BUFFER_DESC constantBufferDesc(sizeof(ModelViewProjectionConstantBuffer), D3D11_BIND_CONSTANT_BUFFER);

m_d3dDevice->CreateBuffer(
  &constantBufferDesc,
  nullptr,
  &m_constantBuffer);

// ...

// Only update shader resources that have changed since the last frame.
m_d3dContext->UpdateSubresource(
  m_constantBuffer.Get(),
  0,
  NULL,
  &m_constantBufferData,
  0,
  0);

El búfer de vértices se crea y actualiza de forma similar, y se describe en el paso siguiente, Portar los búferes de vértices y los datos.

Paso siguiente

Portabilidad de los búferes de vértices y los datos

Cómo: migrar un representador de OpenGL ES 2.0 simple a Direct3D 11

Portabilidad de los búferes de vértices y los datos

Puerto de GLSL

Dibujar en la pantalla