Condividi tramite


Convertire il codice GLSL

API importanti

Dopo aver spostato il codice che crea e configura i buffer e gli oggetti shader, è il momento di convertire il codice all'interno di tali shader dal linguaggio GL Shader (GLSL) di OpenGL ES 2.0 a Direct3D 11 High Level Shader Language (HLSL).

In OpenGL ES 2.0 gli shader restituiscono dati dopo l'esecuzione usando oggetti intrinseci come gl_Position, gl_FragColor o gl_FragData[n] (dove n è l'indice per una destinazione di rendering specifica). In Direct3D non esistono intrinseci specifici e gli shader restituiscono dati come tipo restituito delle rispettive funzioni main().

I dati da interpolare tra le fasi dello shader, ad esempio la posizione del vertice o la normale, vengono gestiti tramite l'uso della dichiarazione variabile . Tuttavia, Direct3D non ha questa dichiarazione; invece, tutti i dati che si desidera passare tra le fasi dello shader devono essere contrassegnati con una semantica HLSL. La semantica specifica scelta indica lo scopo dei dati e è . Ad esempio, si dichiarano i dati dei vertici da interpolare tra il frammento shader come:

float4 vertPos : POSITION;

or

float4 vertColor : COLOR;

Dove POSITION è la semantica usata per indicare i dati di posizione dei vertici. POSITION è anche un caso speciale, poiché dopo l'interpolazione non è possibile accedervi dal pixel shader. Pertanto, è necessario specificare l'input per il pixel shader con SV_POSITION e i dati dei vertici interpolati verranno inseriti in tale variabile.

float4 position : SV_POSITION;

La semantica può essere dichiarata nei metodi body (main) degli shader. Per i pixel shader, SV_TARGET[n], che indica una destinazione di rendering, è obbligatorio nel metodo body. (SV_TARGET senza un suffisso numerico per impostazione predefinita per il rendering dell'indice di destinazione 0.

Si noti anche che i vertex shader sono necessari per restituire la semantica del valore di sistema SV_POSITION. Questa semantica risolve i dati della posizione dei vertici in valori di coordinate in cui x è compreso tra -1 e 1, y è compreso tra -1 e 1, z è diviso per il valore w omogeneo originale (z/w) e w è 1 diviso per il valore w originale (1/w). I pixel shader usano la semantica del valore di sistema SV_POSITION per recuperare la posizione dei pixel sullo schermo, dove x è compreso tra 0 e la larghezza della destinazione di rendering e y è compresa tra 0 e l'altezza della destinazione di rendering (ogni offset di 0,5). Il livello di funzionalità 9_x pixel shader non può leggere dal valore SV_POSITION.

I buffer costanti devono essere dichiarati con cbuffer ed essere associati a un registro iniziale specifico per la ricerca.

Direct3D 11: dichiarazione di buffer costante HLSL

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

In questo caso, il buffer costante usa il registro b0 per contenere il buffer compresso. Tutti i registri sono indicati nel formato b#. Per altre informazioni sull'implementazione HLSL di buffer costanti, registri e compressione dei dati, leggere Costanti shader (HLSL).

Istruzioni

Passaggio 1: Convertire il vertex shader

Nell'esempio openGL ES 2.0 semplice, il vertex shader ha tre input: una matrice 4x4 di proiezione del modello costante e due vettori a 4 coordinate. Questi due vettori contengono la posizione del vertice e il relativo colore. Lo shader trasforma il vettore di posizione in coordinate prospettiche e lo assegna a gl_Position intrinseco per la rasterizzazione. Il colore del vertice viene copiato anche in una variabile variabile per l'interpolazione durante la rasterizzazione.

OpenGL ES 2.0: Vertex shader per l'oggetto 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;
}

A questo punto, in Direct3D la matrice costante model-view-projection è contenuta in un buffer costante compresso in corrispondenza del registro b0 e la posizione e il colore dei vertici sono contrassegnati specificamente con la rispettiva semantica HLSL appropriata: POSITION e COLOR. Poiché il layout di input indica una disposizione specifica di questi due valori di vertice, si crea uno struct per tenerli e dichiararli come tipo per il parametro di input nella funzione corpo dello shader (main). È anche possibile specificarli come due singoli parametri, ma questo potrebbe risultare complesso. Specificare anche un tipo di output per questa fase, che contiene la posizione e il colore interpolati e dichiararlo come valore restituito per la funzione corpo del vertex shader.

Direct3D 11: Vertex shader per l'oggetto 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;
}

Il tipo di dati di output, PixelShaderInput, viene popolato durante la rasterizzazione e fornito allo shader frammento (pixel).

Passaggio 2: Convertire il frammento shader

Il frammento shader di esempio in GLSL è estremamente semplice: fornire il gl_FragColor intrinseco con il valore del colore interpolato. OpenGL ES 2.0 lo scriverà nella destinazione di rendering predefinita.

OpenGL ES 2.0: fragment shader per l'oggetto cubo (GLSL)

varying vec4 destColor;

void main()
{
  gl_FragColor = destColor;
} 

Direct3D è quasi semplice. L'unica differenza significativa è che la funzione body del pixel shader deve restituire un valore. Poiché il colore è un valore float a 4 coordinate (RGBA), si indica float4 come tipo restituito e quindi si specifica la destinazione di rendering predefinita come semantica del valore di sistema SV_TARGET.

Direct3D 11: Pixel shader per l'oggetto cubo (HLSL)

struct PixelShaderInput
{
  float4 pos : SV_POSITION;
  float3 color : COLOR;
};


float4 main(PixelShaderInput input) : SV_TARGET
{
  return float4(input.color, 1.0f);
}

Il colore per il pixel in corrispondenza della posizione viene scritto nella destinazione di rendering. Vediamo ora come visualizzare il contenuto della destinazione di rendering in Disegno sullo schermo.

Passaggio precedente

Convertire i vertex buffer e i dati

Passaggio successivo

Disegnare sullo schermo

Osservazioni:

Comprendere la semantica HLSL e la compressione dei buffer costanti consente di risparmiare un po' di mal di testa del debug, oltre a offrire opportunità di ottimizzazione. In caso affermativo, leggere la sintassi delle variabili (HLSL), Introduzione ai buffer in Direct3D 11 e Procedura: Creare un buffer costante. In caso contrario, ecco alcuni suggerimenti iniziali da tenere presenti sulla semantica e sui buffer costanti:

  • Controllare sempre il codice di configurazione Direct3D del renderer per assicurarsi che le strutture per i buffer costanti corrispondano alle dichiarazioni di struct cbuffer nell'HLSL e che i tipi scalari del componente corrispondano a entrambe le dichiarazioni.
  • Nel codice C++ del renderer usare i tipi DirectXMath nelle dichiarazioni di buffer costanti per garantire una corretta compressione dei dati.
  • Il modo migliore per usare in modo efficiente i buffer costanti consiste nell'organizzare le variabili shader in buffer costanti in base alla frequenza di aggiornamento. Ad esempio, se si dispone di dati uniformi che vengono aggiornati una volta per fotogramma e altri dati uniformi aggiornati solo quando la fotocamera si sposta, prendere in considerazione la separazione dei dati in due buffer costanti separati.
  • La semantica che hai dimenticato di applicare o che hai applicato erroneamente sarà la prima fonte di errori di compilazione shader (FXC). Controllali due volte! La documentazione può creare confusione, poiché molte pagine e esempi meno recenti fanno riferimento a versioni diverse della semantica HLSL prima di Direct3D 11.
  • Assicurarsi di conoscere il livello di funzionalità Direct3D di destinazione per ogni shader. La semantica per il livello di funzionalità 9_* è diversa da quella per 11_1.
  • La semantica SV_POSITION risolve i dati della posizione post-interpolazione associata in valori di coordinate in cui x è compreso tra 0 e la larghezza della destinazione di rendering, y è compreso tra 0 e l'altezza della destinazione di rendering, z viene diviso per il valore w omogeneo originale (z/w) e w è 1 diviso per il valore w originale (1/w).

Procedura: convertire un semplice renderer OpenGL ES 2.0 in Direct3D 11

Convertire gli oggetti shader

Convertire i vertex buffer e i dati

Disegnare sullo schermo