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.
Respostas:
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
textureLod
para 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
dFdx
edFdy
nos UVs, que têm descontinuidades devido aatan2
, você pode aplicardFdx
edFdy
aofragVert
(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.
fonte