A descontinuidade de coordenadas de textura com mipmaps cria costuras

9

Comecei a aprender openGL e estou obtendo esse artefato ao texturar uma esfera com mipmaps. Basicamente, quando o fragmento mostra a borda da minha textura, ele detecta a descontinuidade (digamos 1 a 0) e escolhe o menor mapa mip, que cria essa costura feia:

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

Então, eu tentei substituir manualmente os 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));

Agora, tenho duas costuras em vez de uma. Como posso me livrar deles? E por que o código acima gera 2 costuras?

2 páginas http://cdn.imghack.se/images/44a38ef13cc2cdd801967c9223fdd2d3.png

Você não pode distinguir pelas duas imagens, mas as duas costuras estão nos dois lados da costura original.

omikun
fonte
2
Sua esfera é uma malha, ou você está traçando a esfera analiticamente no shader ou algo parecido? Se é uma malha, as pessoas costumam resolver este duplicando os vértices ao longo da costura de modo que os verts de um lado pode ter u = 0 e o outro lado tem u = 1.
Nathan Reed
Quanto ao motivo pelo qual seu código gera duas costuras, espero que seja porque ele está criando duas descontinuidades - uma em que você salta de 0,01 a 0,5 e outra em que você salta de 0,99 a 0,5. É o mesmo problema de quando você pula de 0 para 1 - não é um salto tão grande, mas ainda é um grande salto.
Nathan Reed
Eu tenho uma malha para a esfera. É um decaedro para que os vértices não se alinhem à costura. O engraçado das duas costuras é que a costura original se foi. Além disso, recebo as mesmas duas costuras, mesmo que eu a prenda em 0,01 ou 0,99.
Omikun
Você pode postar uma captura de tela do gabinete de duas costuras? E como você está gerando os UVs (você pode postar a parte relevante do seu código)? Presumo que você os esteja gerando processualmente no shader, não apenas interpolando-os dos vértices; caso contrário, sua malha de dodecaedro não funcionaria.
Nathan Reed
Atualizei a pergunta com uma imagem das duas costuras, elas estão nos dois lados da costura original, mas a costura original não está lá. Eu acho que os UV são interpolados dos vértices, não tenho certeza. O código está em questão agora.
Omikun

Respostas:

4

Com base no código de sombreador que você postou, você não está interpolando os UVs dos vértices - parece que você está interpolando a posição 3D ( fragVert) e calculando os UVs transformando em coordenadas esféricas.

Sua análise está correta, pois o menor mipmap é escolhido quando há uma descontinuidade, pois a seleção do mipmap é baseada em derivadas estimadas numericamente a partir dos UVs usados ​​nos pixels vizinhos. Quando um pixel tem u = 0 e outro tem u = 1, você obtém uma derivada muito grande. Sua tentativa de correção tem o mesmo problema: derivadas grandes ocorrem em torno de u = 0,01 e u = 0,99, e é por isso que duas costuras aparecem nos dois lados de onde estava a costura original.

Uma abordagem relativamente simples para corrigir o problema seria decidir qual nível de mip usar e chamar textureLodpara amostrá-lo diretamente. Se o planeta sempre estiver próximo da câmera, você poderá codificar o nível mip para 0 (ou, nesse caso, apenas não incluir os níveis mip na textura). Caso contrário, poderia ser baseado no log2 da distância do ponto da câmera, dimensionado por alguns fatores adequados. Observe que isso desativará efetivamente a filtragem anisotrópica.

Uma abordagem mais "correta" seria calcular alguns derivativos de maior qualidade. Em vez de usar dFdxe dFdynos UVs, que têm descontinuidades devido a atan2, você pode aplicar dFdxe dFdyao fragVert(que será contínuo por toda a esfera), depois use algum cálculo (regra da cadeia) para encontrar a fórmula para obter os derivados UV dos derivativos da posição. Isso será mais complicado e mais lento, mas tem a vantagem de que a filtragem anisotrópica deve funcionar.

Finalmente, como você é novo no OpenGL, observarei que, embora o cálculo de UVs a partir de coordenadas esféricas seja uma maneira perfeitamente válida de texturizar uma esfera, não é a maneira "usual" que a maioria das pessoas escolhe. É mais comum construir uma malha de esfera com UVs especificados por vértice e simplesmente passar do sombreador de vértice para o sombreador de pixels (interpolado linearmente em cada triângulo). Os vértices são colocados ao longo da costura, assim , de modo que haja duas cópias de cada vértice, exatamente nas mesmas posições, mas metade com u = 0 conectado aos triângulos de um lado e a outra metade com u = 1 conectado a os triângulos do outro lado. Isso elimina qualquer costura visível e não requer truques no pixel shader.

Nathan Reed
fonte