Comment un shader HLSL affecte-t-il réellement la sortie de rendu?

11

Je comprends la syntaxe de HLSL, par exemple supposons que je l'ai comme HLSL:

struct VOut
{
    float4 position : SV_POSITION;
    float4 color : COLOR;
};

VOut VShader(float4 position : POSITION, float4 color : COLOR)
{
    VOut output;

    output.position = position;
    output.position.xy *= 0.7f;    // "shrink" the vertex on the x and y axes
    output.color = color;

    return output;
}


float4 PShader(float4 position : SV_POSITION, float4 color : COLOR) : SV_TARGET
{
    return color;
}

et je le compile comme ceci:

D3DX11CompileFromFile(L"shaders.hlsl", 0, 0, "VShader", "vs_5_0", 0, 0, 0, &VS, 0, 0);
D3DX11CompileFromFile(L"shaders.hlsl", 0, 0, "PShader", "ps_5_0", 0, 0, 0, &PS, 0, 0);

Comment ça aime ... savoir changer ... Je ne sais pas exactement quel est le pipeline entre HLSL et les pixels / sommets réels à l'écran.

Est-ce bien cela qui les "applique"?

dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS);
dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS);

// set the shader objects
devcon->VSSetShader(pVS, 0, 0);
devcon->PSSetShader(pPS, 0, 0);

Gardez à l'esprit que je suis comme un débutant littéral dans ce genre de choses. Quelqu'un peut-il peut-être expliquer ce qu'il fait? Je suppose que la fonction de sommet HLSL passe par chaque sommet, puis les change en tout ce que j'ai dans la fonction, et la sortie est ce qui a été changé ... et de même pour le pixel shader?

Autre confusion, je sais ce qu'est un pixel et je comprends ce qu'est un sommet ... mais que fait exactement le pixel shader?


la source
C'est ok, personne ne le fait
bobobobo

Réponses:

10

Comment ça aime ...... savoir changer .... Im confus exactement au niveau du pipeline entre HLSL et les Pixels / Vertex réels sur l'écran.

Cela fonctionne à peu près comme ceci: lorsque vous émettez un appel de dessin (DrawPrimitives, DrawIndexedPrimitives dans D3D, Draw dans 10+, et cetera), les données de géométrie que vous avez liées au pipeline (vos tampons de vertex) sont traitées. Pour chaque sommet, le vertex shader est exécuté pour produire un sommet de sortie dans l'espace de clip.

Le GPU exécute ensuite certaines fonctions fixes sur ce sommet de l'espace d'écrêtage, telles que le découpage / élimination et le placement du sommet dans l'espace d'écran, où il commence à pixelliser les triangles. Lors de la pixellisation de chaque triangle, le GPU interpole les attributs de sommet sur la surface de ce triangle, alimentant chaque attribut interpolé au pixel shader pour produire une couleur semi-finale pour ce pixel (le mélange est appliqué après l'exécution du pixel shader, donc "semi- final").

c'est ce qui les "applique" réellement:

Le code que vous avez publié compile d'abord les shaders, puis les lie au pipeline où ils restent actifs pour tous les appels de tirage ultérieurs jusqu'à ce qu'ils soient modifiés. Cela ne provoque pas leur exécution.

Quelqu'un peut-il expliquer ce qu'il fait, en supposant que la fonction Vertex HLSL passe par chaque sommet (en tant que position d'entrée: POSITION et couleur: COULEUR), puis les modifie en tout ce que j'ai dans la fonction, et la sortie est ce qui a été modifié. ... (il en va de même pour Pixel Shader).

Une autre confusion, je sais ce qu'est un pixel, et je comprends ce qu'est un sommet ..... mais que fait exactement le pixel shader ......

Le vertex shader est responsable de la transformation des sommets de l'espace objet en espace clip.

Le pixel shader est responsable du calcul de l'avant-dernière couleur / profondeur pour un pixel sur la base des attributs de sommet interpolés.


la source
9

Je vais essayer d'expliquer comment les choses fonctionnent sans utiliser beaucoup de jargon.

Si la simplicité plutôt que la vitesse interactive est votre préoccupation, une surface 3D dans l'ordinateur ne serait qu'un énorme nuage de points dans l'espace, suffisamment dense pour que nous puissions simplement rendre chaque point individuellement, sans espaces entre eux.

Vous ne voulez stocker un modèle qu'une seule fois en mémoire, mais vous devez l'afficher à différentes tailles et sous différents angles, donc lorsque vous effectuez le rendu d'un modèle 3D, vous devez "transformer" tous les points lorsque vous les lisez de la mémoire. Par exemple, pour rendre le modèle 50% plus grand, vous devez redimensionner les positions des points de moitié:

out.position = in.position * 0.5;
out.color = in.color;

C'est presque le "vertex shader" le plus simple que l'on puisse concevoir: une position de sommet entre en mémoire et une nouvelle position de sommet, à moitié aussi grande. Le sommet à moitié aussi grand n'est pas stocké en mémoire - il est utilisé immédiatement pour le rendu, puis jeté.

Bien qu'une simplification flagrante qui manque de concepts clés , cela dans l'esprit décrit les aspects de la façon dont les films font des graphiques.

Les graphiques interactifs (jeux) ne peuvent pas se permettre d'être aussi simples, car ils doivent rendre les graphiques plusieurs ordres de grandeur plus rapidement qu'un film.

Dans les jeux, nous ne pouvons pas nous permettre de rendre un point pour chaque pixel à l'écran, plus des extras pour combler les lacunes. Donc, à titre de compromis, l'écart entre chacun des trois points voisins est rendu sous la forme d'un triangle qui, pour diverses raisons techniques, préfère avoir au moins 10 pixels de large à l'écran.

Un triangle 3D peut être projeté sur un écran 2D, puis divisé en une pile de lignes 1D, chacune pouvant être divisée en une pile de 0D pixels. Nous pouvons ainsi diviser et conquérir le problème du rendu d'un triangle 3D en un problème plus simple de rendu de beaucoup de pixels 0D de manière isolée. Un ordinateur peut résoudre des problèmes plus simples en moins de temps.

Un pixel shader est un petit programme que nous exécutons sur chaque pixel généré par le démontage d'un triangle.

out.color = in.color;

C'est presque le "pixel shader" le plus simple que l'on puisse concevoir: dedans va un mélange des couleurs de trois sommets triangulaires, et dehors va la même couleur. Les entrées proviennent des sorties du "vertex shader" et les sorties sont écrites sur l'écran en mémoire.

Ainsi, le "vertex shader" est un programme qui s'exécute à l'intérieur de la puce GPU. Son entrée est un "vertex buffer" dans la mémoire GPU, et sa sortie est directement alimentée dans un "pixel shader". Un "pixel shader" est également un programme qui s'exécute à l'intérieur de la puce GPU. Ses entrées sont un mélange de trois sommets du vertex shader, et sa sortie est un pixel à l'écran.

bmcnett
la source
-2

Ne vous inquiétez pas pour un pixel shader en ce moment. Si vous êtes un débutant complet, vous devriez être bonjour au monde de GLSL / HLSL avec des shaders de vertex et de fragment uniquement. Une fois que vous êtes familier et que vous commencez à comprendre les mouvements variables et autres, élargissez vos horizons.

Je recommande fortement un livre de texte pour comprendre le fonctionnement de l'API. Les livres OpenGL illustrent également bien comment les choses ont changé au fil des ans, passant du pipeline fixe au pipeline programmable dynamique.

Allez champion!

Bryan C
la source
1
Un fragment shader remplit la même fonction qu'un pixel shader.
1
Je ne pense pas que nous puissions dire à partir de la question de savoir si l'OP est un débutant dans la programmation de tous les jeux - il a seulement déclaré qu'il était un débutant dans l'écriture de code de shader. Apprendre à écrire des shaders est un outil très important à avoir dans le hangar d'un développeur de jeux, je ne me contenterais pas de les ignorer à moins que vous ne soyez qu'au tout début de l'apprentissage du développement de jeux.
Olhovsky