Els shaders són programes que s'executen en la GPU (Unitat de Processament Gràfic) i són essencials per a la renderització moderna en temps real. En aquest mòdul, aprendrem què són els shaders, els diferents tipus de shaders i com s'utilitzen en DirectX.

Què són els Shaders?

Els shaders són petits programes escrits en llenguatges de programació especialitzats com HLSL (High-Level Shading Language) per a DirectX. Aquests programes s'executen en la GPU i s'utilitzen per a diverses tasques de renderització, com ara la transformació de geometria, l'aplicació de textures i la il·luminació.

Tipus de Shaders

  1. Vertex Shaders: Processen cada vèrtex individualment. S'utilitzen per transformar les coordenades dels vèrtexs, aplicar animacions i calcular propietats com normals i coordenades de textura.
  2. Pixel Shaders: Processen cada píxel individualment. S'utilitzen per determinar el color final de cada píxel, aplicant textures, il·luminació i altres efectes visuals.
  3. Geometry Shaders: Processen primitives (com triangles) i poden generar noves primitives. S'utilitzen per a efectes avançats com la tessellació i la generació de geometria dinàmica.
  4. Compute Shaders: S'utilitzen per a càlculs generals en la GPU que no estan directament relacionats amb la renderització. Poden ser utilitzats per a simulacions físiques, processament d'imatges, etc.

Estructura d'un Shader

Un shader típic en HLSL té la següent estructura:

// Vertex Shader
struct VS_INPUT {
    float4 Pos : POSITION;
    float4 Color : COLOR;
};

struct VS_OUTPUT {
    float4 Pos : SV_POSITION;
    float4 Color : COLOR;
};

VS_OUTPUT VSMain(VS_INPUT input) {
    VS_OUTPUT output;
    output.Pos = input.Pos;
    output.Color = input.Color;
    return output;
}

// Pixel Shader
float4 PSMain(VS_OUTPUT input) : SV_TARGET {
    return input.Color;
}

Explicació del Codi

  • VS_INPUT: Estructura que defineix les dades d'entrada per al vertex shader. En aquest cas, inclou la posició i el color del vèrtex.
  • VS_OUTPUT: Estructura que defineix les dades de sortida del vertex shader, que seran utilitzades pel pixel shader.
  • VSMain: Funció principal del vertex shader. Transforma les dades d'entrada i les passa a la sortida.
  • PSMain: Funció principal del pixel shader. Rep les dades del vertex shader i calcula el color final del píxel.

Compilació i Utilització de Shaders

Els shaders han de ser compilats abans de ser utilitzats en una aplicació DirectX. La compilació converteix el codi HLSL en codi de màquina que pot ser executat per la GPU.

Exemple de Compilació de Shaders en DirectX

ID3DBlob* vertexShaderBlob = nullptr;
ID3DBlob* pixelShaderBlob = nullptr;
ID3DBlob* errorBlob = nullptr;

// Compilar el vertex shader
HRESULT hr = D3DCompileFromFile(L"shader.hlsl", nullptr, nullptr, "VSMain", "vs_5_0", 0, 0, &vertexShaderBlob, &errorBlob);
if (FAILED(hr)) {
    if (errorBlob) {
        OutputDebugStringA((char*)errorBlob->GetBufferPointer());
        errorBlob->Release();
    }
    // Manejar l'error
}

// Compilar el pixel shader
hr = D3DCompileFromFile(L"shader.hlsl", nullptr, nullptr, "PSMain", "ps_5_0", 0, 0, &pixelShaderBlob, &errorBlob);
if (FAILED(hr)) {
    if (errorBlob) {
        OutputDebugStringA((char*)errorBlob->GetBufferPointer());
        errorBlob->Release();
    }
    // Manejar l'error
}

// Crear el vertex shader
ID3D11VertexShader* vertexShader;
hr = device->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), nullptr, &vertexShader);
if (FAILED(hr)) {
    // Manejar l'error
}

// Crear el pixel shader
ID3D11PixelShader* pixelShader;
hr = device->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), nullptr, &pixelShader);
if (FAILED(hr)) {
    // Manejar l'error
}

Explicació del Codi

  • D3DCompileFromFile: Funció que compila el shader des d'un fitxer HLSL. Els paràmetres inclouen el nom del fitxer, el punt d'entrada (funció principal) i el perfil del shader (vs_5_0 per a vertex shader, ps_5_0 per a pixel shader).
  • CreateVertexShader i CreatePixelShader: Funcions que creen els shaders compilats i els preparen per ser utilitzats en la pipeline de renderització.

Exercici Pràctic

Objectiu

Crear un shader simple que canviï el color dels vèrtexs a un color fix.

Passos

  1. Escriu un vertex shader que passi les coordenades dels vèrtexs sense canvis.
  2. Escriu un pixel shader que estableixi el color de tots els píxels a vermell.
  3. Compila i utilitza els shaders en una aplicació DirectX.

Solució

shader.hlsl

// Vertex Shader
struct VS_INPUT {
    float4 Pos : POSITION;
};

struct VS_OUTPUT {
    float4 Pos : SV_POSITION;
};

VS_OUTPUT VSMain(VS_INPUT input) {
    VS_OUTPUT output;
    output.Pos = input.Pos;
    return output;
}

// Pixel Shader
float4 PSMain(VS_OUTPUT input) : SV_TARGET {
    return float4(1.0, 0.0, 0.0, 1.0); // Color vermell
}

Codi C++ per Compilar i Utilitzar els Shaders

// Compilar i crear els shaders (mateix codi que l'exemple anterior)

// Establir els shaders en la pipeline de renderització
context->VSSetShader(vertexShader, nullptr, 0);
context->PSSetShader(pixelShader, nullptr, 0);

Conclusió

En aquesta secció, hem après què són els shaders, els diferents tipus de shaders i com s'escriuen i utilitzen en DirectX. Els shaders són una part fonamental de la programació gràfica moderna i ens permeten crear efectes visuals complexos i personalitzats. En els següents temes, aprofundirem en la creació de vertex shaders i pixel shaders més avançats.

© Copyright 2024. Tots els drets reservats