Je viens de commencer à apprendre openGL et j'obtiens cet artefact lors de la texturation d'une sphère avec des mipmaps. Fondamentalement, lorsque le fragment échantillonne le bord de ma texture, il détecte la discontinuité (disons de 1 à 0) et sélectionne le plus petit mipmap, ce qui crée cette couture laide:
couture laide http://cdn.imghack.se/images/6bbe0ad0173cac003cd5dddc94bd43c7.png
J'ai donc essayé de remplacer manuellement les dégradés en utilisant textureGrad:
//fragVert is the original vertex from the vertex shader
vec2 ll = vec2((atan(fragVert.y, fragVert.x) / 3.1415926 + 1.0) * 0.5, (asin(fragVert.z) / 3.1415926 + 0.5));
vec2 ll2 = ll;
if (ll.x < 0.01 || ll.x > 0.99)
ll2.x = .5;
vec4 surfaceColor = textureGrad(material.tex, ll, dFdx(ll2), dFdy(ll2));
Maintenant, j'ai deux coutures au lieu d'une. Comment puis-je m'en débarrasser? Et pourquoi le code ci-dessus génère-t-il 2 coutures?
2 eams http://cdn.imghack.se/images/44a38ef13cc2cdd801967c9223fdd2d3.png
Vous ne pouvez pas le dire à partir des deux images, mais les 2 coutures sont de chaque côté de la couture d'origine.
Réponses:
Sur la base du code de shader que vous avez publié, vous n'interpolez pas les UV à partir des sommets - il semble plutôt que vous interpolez la position 3D (
fragVert
), puis calculez les UV en les transformant en coordonnées sphériques.Votre analyse est correcte dans la mesure où la plus petite mipmap est choisie en cas de discontinuité, car la sélection de mipmap est basée sur des dérivés estimés numériquement à partir des UV utilisés dans les pixels voisins. Quand un pixel a u = 0 et un autre a u = 1, vous obtenez une très grande dérivée. Votre tentative de correction a le même problème en ce sens que les grandes dérivées se produisent autour de u = 0,01 et u = 0,99, c'est pourquoi deux coutures apparaissent de chaque côté de l'endroit où se trouvait la couture d'origine.
Une approche relativement simple pour résoudre le problème serait de décider quel niveau de mip utiliser vous-même et d'appeler
textureLod
pour l'échantillonner directement. Si la planète va toujours être assez proche de la caméra, vous pouvez simplement coder en dur le niveau de mip à 0 (ou, d'ailleurs, ne pas inclure du tout les niveaux de mip dans la texture). Sinon, il pourrait être basé sur le log2 de la distance du point à la caméra, mis à l'échelle par certains facteurs appropriés. Notez que cela désactivera efficacement le filtrage anisotrope.Une approche plus «correcte» consisterait à calculer certains dérivés de meilleure qualité. Au lieu d'utiliser
dFdx
etdFdy
sur les UVs, qui ont discontinuités en raison de laatan2
, vous pouvez appliquerdFdx
etdFdy
àfragVert
(qui seront continus tout autour de la sphère), puis utiliser du calcul (règle de chaîne) pour trouver la formule pour obtenir les dérivés UV de la position des dérivés. Ce sera plus compliqué et plus lent, mais a l'avantage que le filtrage anisotrope devrait fonctionner.Enfin, puisque vous êtes nouveau sur OpenGL, je noterai que bien que le calcul des UV à partir de coordonnées sphériques soit un moyen parfaitement valide pour texturer une sphère, ce n'est pas la manière "habituelle" que la plupart des gens choisissent. Il est plus courant de créer un maillage de sphère dont les UV sont spécifiés par sommet et qui sont simplement passés du vertex shader au pixel shader (interpolé linéairement sur chaque triangle). Les sommets sont placés le long de la couture, comme ceci , de sorte qu'il y a deux copies de chaque sommet, exactement aux mêmes positions, mais la moitié avec u = 0 connecté aux triangles d'un côté, et l'autre moitié avec u = 1 connecté à les triangles de l'autre côté. Cela élimine toute couture visible et ne nécessite aucune astuce dans le pixel shader.
la source