Nieciągłość współrzędnych tekstury z mipmapami tworzy szwy

9

Właśnie zacząłem uczyć się openGL i otrzymuję ten artefakt podczas teksturowania kuli za pomocą mipmap. Zasadniczo, gdy fragment próbkuje krawędź mojej tekstury, wykrywa nieciągłość (powiedzmy od 1 do 0) i wybiera najmniejszą mipmapę, która tworzy ten brzydki szew:

brzydki szew http://cdn.imghack.se/images/6bbe0ad0173cac003cd5dddc94bd43c7.png

Więc próbowałem ręcznie zastąpić gradienty za pomocą 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));

Teraz dostaję dwa szwy zamiast jednego. Jak mogę się ich pozbyć? I dlaczego powyższy kod generuje 2 szwy?

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

Nie widać na podstawie dwóch zdjęć, ale 2 szwy znajdują się po obu stronach oryginalnego szwu.

omikun
źródło
2
Czy twoja kula jest siatką, czy analitycznie śledzisz ją w shaderze? Jeśli jest to siatka, ludzie zwykle rozwiązują to, powielając wierzchołki wzdłuż szwu, tak aby wierzchołki z jednej strony mogły mieć u = 0, a druga strona miała u = 1.
Nathan Reed
Jeśli chodzi o to, dlaczego twój kod generuje dwa szwy, spodziewam się, że to dlatego, że tworzy dwie nieciągłości - jedną, w której skaczesz z 0,01 do 0,5, a drugą, w której skaczesz z 0,99 do 0,5. To ten sam problem, co w przypadku, gdy skaczesz od 0 do 1 - nie tak duży skok, ale wciąż duży skok.
Nathan Reed
Mam siatkę na kulę. Jest to decahedron, więc wierzchołki nie wyrównują się ze szwem. Zabawne jest to, że dwa szwy zniknęły. Ponadto dostaję te same 2 szwy, nawet jeśli dociskam do .01 lub .99.
omikun
Czy możesz opublikować zrzut ekranu skrzynki z dwoma szwami? A w jaki sposób generujesz UV (czy możesz opublikować odpowiednią część swojego kodu)? Zakładam, że generujesz je proceduralnie w module cieniującym, a nie tylko interpolujesz je z wierzchołków, w przeciwnym razie siatka dwunastościanu w ogóle by nie działała.
Nathan Reed
Zaktualizowałem pytanie obrazem 2 szwów, są one po obu stronach oryginalnego szwu, ale oryginalnego szwu nie ma. Myślę, że UV są interpolowane z wierzchołków, nie jestem pewien. Kod jest teraz w pytaniu.
omikun

Odpowiedzi:

4

W oparciu o opublikowany kod modułu cieniującego nie interpolujesz promieni UV z wierzchołków - raczej wydaje się, że interpolujesz pozycję 3D (fragVert ), a następnie obliczasz promieniowanie UV, przekształcając je we współrzędne sferyczne.

Twoja analiza jest poprawna, ponieważ najmniejszą mipmapę wybiera się, gdy występuje nieciągłość, ponieważ wybór mipmapy opiera się na pochodnych, które są szacowane liczbowo na podstawie UVs używanych w sąsiednich pikselach. Gdy jeden piksel ma u = 0, a drugi ma u = 1, otrzymujesz bardzo dużą pochodną. Twoja próba naprawy ma ten sam problem, ponieważ duże pochodne występują około u = 0,01 iu = 0,99, dlatego dwa szwy pojawiają się po obu stronach miejsca, w którym znajdował się pierwotny szew.

Stosunkowo proste podejście do rozwiązania problemu polegałoby na podjęciu decyzji, który poziom mipa użyć samemu i wywołaniu w textureLodcelu jego bezpośredniego pobrania. Jeśli planeta zawsze będzie dość blisko kamery, możesz po prostu zakodować poziom mip na 0 (lub, w tym przypadku, po prostu nie zawierać poziomów mip w teksturze). W przeciwnym razie może być oparty na log2 odległości punktu od kamery, skalowanej przez niektóre odpowiednie czynniki. Zauważ, że to skutecznie wyłączy filtrowanie anizotropowe.

Bardziej „poprawnym” podejściem byłoby obliczenie niektórych instrumentów pochodnych wyższej jakości. Zamiast używać dFdxi dFdyna UV, które mają nieciągłości z powodu atan2, możesz zastosować dFdxi dFdydo fragVert(który będzie ciągły przez całą kulę), a następnie użyj rachunku różniczkowego (reguła łańcuchowa), aby znaleźć wzór na uzyskanie pochodnych UV z pozycji instrumentów pochodnych. Będzie to bardziej skomplikowane i wolniejsze, ale ma tę zaletę, że powinno działać filtrowanie anizotropowe.

Wreszcie, ponieważ jesteś nowy w OpenGL, po prostu zauważę, że podczas obliczania UV ze współrzędnych sferycznych jest doskonale poprawnym sposobem na teksturowanie kuli, nie jest to „zwykły” sposób wybierany przez większość ludzi. Bardziej powszechne jest budowanie siatki sferycznej, która ma UV określone dla wierzchołka i po prostu przechodzi z modułu cieniującego wierzchołek do modułu cieniującego piksele (interpolowana liniowo w każdym trójkącie). Wierzchołki są umieszczone wzdłuż szwu, tak , że są dwie kopie każdego wierzchołka, dokładnie w tych samych pozycjach, ale połowa z u = 0 połączona z trójkątami po jednej stronie, a druga połowa z u = 1 połączona z trójkąty po drugiej stronie. Eliminuje to wszelkie widoczne szwy i nie wymaga żadnych sztuczek w module cieniującym piksele.

Nathan Reed
źródło