La discontinuité des coordonnées de texture avec les mipmaps crée des coutures

9

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.

omikun
la source
2
Votre sphère est-elle un maillage ou tracez-vous la sphère analytiquement dans le shader ou similaire? S'il s'agit d'un maillage, les gens résolvent généralement cela en dupliquant les sommets le long de la couture afin que les verts d'un côté puissent avoir u = 0 et que l'autre côté ait u = 1.
Nathan Reed
Quant à savoir pourquoi votre code génère deux coutures, je pense que c'est parce qu'il crée deux discontinuités - l'une où u saute de 0,01 à 0,5 et l'autre où u saute de 0,99 à 0,5. C'est le même problème que lorsque u saute de 0 à 1 - pas aussi grand qu'un saut mais toujours un gros saut.
Nathan Reed
J'ai un maillage pour la sphère. C'est un décaèdre donc les sommets ne s'alignent pas sur la couture. Ce qui est drôle avec les deux coutures, c'est que la couture d'origine a disparu. De plus, j'obtiens les mêmes 2 coutures même si je le serre à .01 ou .99.
omikun
Pouvez-vous poster une capture d'écran de l'étui à deux coutures? Et comment générez-vous les UV (pouvez-vous publier la partie pertinente de votre code)? Je suppose que vous les générez de manière procédurale dans le shader, pas seulement en les interpolant à partir des sommets, sinon votre maillage de dodécaèdre ne fonctionnerait pas du tout.
Nathan Reed
J'ai mis à jour la question avec une photo des 2 coutures, elles sont de chaque côté de la couture d'origine, mais la couture d'origine n'est pas là. Je pense que les UV sont interpolés à partir des sommets, pas sûr. Le code est maintenant en question.
omikun

Réponses:

4

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 textureLodpour 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 dFdxet dFdysur les UVs, qui ont discontinuités en raison de la atan2, vous pouvez appliquer dFdxet dFdyà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.

Nathan Reed
la source