web-dev-qa-db-fra.com

Comment le fragment shader sait-il quelle variable utiliser pour la couleur d'un pixel?

Je vois beaucoup de shaders de fragments différents,

#version 130

out vec4 flatColor;

void main(void)
{
    flatColor = vec4(0.0,1.0,0.0,0.5);
}

Et ils utilisent tous une variable différente pour la "couleur de sortie" (dans ce cas flatColor). Alors, comment OpenGL sait-il ce que vous essayez de faire?

Je suppose que cela fonctionne parce que flatColor est la seule variable définie comme out, mais vous êtes autorisé à ajouter plus de variables out n'est-ce pas? Ou est-ce que ça planterait?


En fait, comme test, je viens de lancer ceci:

#version 330

in vec2 TexCoord0;

uniform sampler2D TexSampler;

out vec4 x;
out vec4 y;

void main()
{
    y = texture2D(TexSampler, TexCoord0.xy);
}

Cela a bien fonctionné, que j'utilise x ou y.


De plus, nous avons un gl_FragColor Prédéfini. Quelle est la différence et pourquoi les gens insistent-ils habituellement pour utiliser leurs propres variables?

76
mpen

De plus, nous avons un gl_FragColor prédéfini.

Commençons par ça. Non, vous n'avez pas le _ gl_FragColor. Cela a été supprimé du noyau OpenGL 3.1 et supérieur. Sauf si vous utilisez la compatibilité (dans ce cas, vos shaders 3.30 devraient indiquer #version 330 compatibility en haut), vous ne devez jamais l'utiliser.

Maintenant, revenons aux sorties de shaders de fragments définis par l'utilisateur. Mais d'abord, une rapide analogie.

Rappelez-vous comment, dans les vertex shaders, vous avez des entrées? Et ces entrées représentent des indices d'attribut de sommet, les nombres que vous passez à glVertexAttribPointer et glEnableVertexAttribArray et ainsi de suite? Vous définissez quelle entrée extrait de quel attribut. Dans GLSL 3.30, vous utilisez cette syntaxe:

layout(location = 2) in color;

Cela définit l'entrée de vertex shader color pour qu'elle provienne de l'emplacement d'attribut 2. Avant 3.30 (ou sans ARB_explicit_attrib_location), vous devez soit le configurer explicitement avec glBindAttrbLocation avant de lier ou d'interroger le programme pour l'index d'attribut avec glGetAttribLocation . Si vous ne fournissez pas explicitement un emplacement d'attribut, GLSL attribuera un emplacement arbitrairement (c'est-à-dire: d'une manière définie par l'implémentation).

Le placer dans le shader est presque toujours la meilleure option.

Dans tous les cas, les sorties de fragment shader fonctionnent presque exactement de la même manière. Les shaders de fragments peuvent écrire dans plusieurs couleurs de sortie , qui sont eux-mêmes mappés sur plusieurs tampons dans le framebuffer . Par conséquent, vous devez indiquer quelle sortie va à quelle couleur de sortie de fragment.

Ce processus commence par la valeur d'emplacement de sortie du fragment. Il est défini de manière très similaire aux emplacements d'entrée du vertex shader:

layout(location = 1) out secColor;

Il existe également les fonctions API glBindFragDataLocation et glGetFragDataLocation , qui sont analogues à glBindAttribLocation et glGetAttribLocation.

Si vous n'effectuez aucune affectation explicite, les implémentations affectent généralement l'une de vos variables de sortie à l'emplacement 0. Cependant, la norme OpenGL ne requiert pas cette comportement, vous ne devriez donc pas en dépendre non plus.

Maintenant, pour être juste, votre programme aurait dû échoué à se lier lorsque vous avez utilisé deux sorties qui n'ont pas obtenu des emplacements de sortie différents. Ce qui s'est probablement passé, c'est que votre compilateur a optimisé celui que vous n'avez pas écrit, donc il l'a un peu oublié quand est venu le temps de vérifier les erreurs de l'éditeur de liens.

134
Nicol Bolas

Je voudrais spécifier cela pour OpenGLES 3.1 qui utilise GLSL_ES_3.10 link :

§4.4.2

S'il n'y a qu'une seule sortie [dans le fragment shader], l'emplacement n'a pas besoin d'être spécifié, auquel cas il est réglé par défaut sur zéro.

8
Lorenzo Belli