La discontinuidad de coordenadas de textura con mipmaps crea costuras

9

Recién comencé a aprender openGL y obtengo este artefacto cuando texturizo una esfera con mipmaps. Básicamente, cuando el fragmento muestrea el borde de mi textura, detecta la discontinuidad (digamos de 1 a 0) y selecciona el mapa MIP más pequeño, lo que crea esta costura fea:

fea costura http://cdn.imghack.se/images/6bbe0ad0173cac003cd5dddc94bd43c7.png

Así que intenté anular manualmente los gradientes usando 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));

Ahora tengo dos costuras en lugar de una. ¿Cómo puedo deshacerme de ellos? ¿Y por qué el código anterior genera 2 costuras?

2 eams http://cdn.imghack.se/images/44a38ef13cc2cdd801967c9223fdd2d3.png

No se puede distinguir de las dos imágenes, pero las 2 costuras están a ambos lados de la costura original.

omikun
fuente
2
¿Es su esfera una malla, o está trazando la esfera analíticamente en el sombreador o algo así? Si se trata de una malla, las personas generalmente resuelven esto duplicando los vértices a lo largo de la costura para que los verts de un lado puedan tener u = 0 y el otro lado tenga u = 1.
Nathan Reed
En cuanto a por qué su código genera dos costuras, espero que sea porque está creando dos discontinuidades: una en la que salta de 0.01 a 0.5 y otra en la que salta de 0.99 a 0.5. Es el mismo problema que cuando saltas de 0 a 1: no es un salto tan grande, pero sigue siendo un gran salto.
Nathan Reed
Tengo una malla para la esfera. Es un decaedro, por lo que los vértices no se alinean con la costura. Lo curioso de las dos costuras es que la costura original se ha ido. Además, obtengo las mismas 2 costuras incluso si lo aprieto a .01 o .99.
omikun 01 de
¿Puedes publicar una captura de pantalla del caso de dos costuras? ¿Y cómo está generando los UV (puede publicar la parte relevante de su código)? Supongo que los está generando procesalmente en el sombreador, no solo interpolando desde los vértices, sino que su malla dodecaedro no funcionaría en absoluto.
Nathan Reed
Actualicé la pregunta con una imagen de las 2 costuras, están a ambos lados de la costura original, pero la costura original no está allí. Creo que los UV están interpolados desde los vértices, no estoy seguro. El código está en la pregunta ahora.
omikun

Respuestas:

4

Según el código de sombreador que publicó, no está interpolando los UV de los vértices, sino que parece que está interpolando la posición 3D ( fragVert), luego calculando los UV transformándolos en coordenadas esféricas.

Su análisis es correcto porque el mipmap más pequeño se elige cuando hay una discontinuidad, ya que la selección de mipmap se basa en derivados que se estiman numéricamente a partir de los UV utilizados en los píxeles vecinos. Cuando un píxel tiene u = 0 y otro tiene u = 1, obtienes una derivada muy grande. Su intento de reparación tiene el mismo problema porque las grandes derivaciones ocurren alrededor de u = 0.01 yu = 0.99, razón por la cual aparecen dos costuras a cada lado de donde estaba la costura original.

Un enfoque relativamente simple para solucionar el problema sería decidir qué nivel de mip usar y llamar textureLod para probarlo directamente. Si el planeta siempre va a estar bastante cerca de la cámara, simplemente puede codificar el nivel de mip a 0 (o, para el caso, simplemente no incluir niveles de mip en la textura). De lo contrario, podría basarse en el log2 de la distancia del punto desde la cámara, escalado por algunos factores adecuados. Tenga en cuenta que esto deshabilitará efectivamente el filtrado anisotrópico.

Un enfoque más "correcto" sería calcular algunos derivados de mayor calidad. En vez de usar dFdxy dFdysobre los UV, que tienen discontinuidades debido a la atan2, se podría aplicar dFdxy dFdypara fragVert(que será continua todo el camino alrededor de la esfera), a continuación, utilizar algunos (regla de la cadena) el cálculo para encontrar la fórmula para obtener los derivados UV desde la posición derivados. Esto será más complicado y más lento, pero tiene la ventaja de que el filtrado anisotrópico debería funcionar.

Finalmente, dado que eres nuevo en OpenGL, solo notaré que si bien calcular los UV a partir de coordenadas esféricas es una forma perfectamente válida de texturizar una esfera, no es la forma "habitual" que la mayoría de la gente elige. Es más común construir una malla de esfera que tenga UV especificados por vértice, y simplemente pase del sombreador de vértices al sombreador de píxeles (interpolado linealmente a través de cada triángulo). Los vértices se colocan a lo largo de la costura, de esta manera , de modo que hay dos copias de cada vértice, en exactamente las mismas posiciones, pero la mitad con u = 0 conectado a los triángulos en un lado, y la otra mitad con u = 1 conectado a Los triángulos del otro lado. Esto elimina cualquier costura visible y no requiere ningún truco en el sombreador de píxeles.

Nathan Reed
fuente