2014-12-16 10 views
5

Chcę uczynić planetę jak kulę. Ogólna idea jest następująca:Analityczne normalne do kuli wypartej szumem simpleksowym

  • Generuje pęczek wierzchołków długości jednostki, które tworzą kulę.
  • Podczas renderowania sfery moduł cieniujący ocenia szum 3D w punkcie sfery jednostki.
  • Wynik jest używany jako "wysokość", aby przesunąć bieżący wierzchołek wzdłuż jego kierunku.

Do tego czasu wszystko działa tak, jak powinno.

Teraz chcę dodać oświetlenie i dlatego potrzebuję normalnych powierzchni.

Realizując części oświetleniowych związane szybko dodaje metodę szacowania normalne na terenie z wykorzystaniem pochodnych cząstkowych w cieniującego fragment jak to:

vec3 X = dFdx(ins.position); 
vec3 Y = dFdy(ins.position); 
vec3 normal = normalize(cross(X,Y)); 

gdzie ins.position jest interpolowaną pozycji na świecie.

Mimo że działa to nie wygląda bardzo dobrze, ponieważ w zasadzie skutkuje normalnych na twarzy.

Bad normal approximation

teraz do rzeczywistych pytań:

  • Obliczanie spowodowałoby per-vertex normalne w normalnych gładkich, w przeciwieństwie do obrazu, prawda?
  • Jedną z zalet Simplex Noise over Perlin Noise jest to, że ma "dobrze zdefiniowany i ciągły gradient wszędzie, gdzie można go obliczyć dość tanio" (aby zacytować znakomity Simplex Noise demystified) i przy gradiencie powinno być możliwe obliczenie normalny, poprawny?

Jeśli pytanie sekunda jest „tak” Mam dwa problemy:

  • Algorytm hałas simplex zostało zrobione z popular source, która niestety nie obejmuje obliczanie gradientu. Opublikuję moją próbę dodania go poniżej, ale nie mam pojęcia, czy to jest poprawne.
  • Nawet gdybym miał gradient, utknąłem na wyprowadzeniu normalnego stamtąd.

Każda pomoc jest bardzo doceniana!

Mój strzał w realizacji gradientu (zastąpiony przez ostatnie kilka linijek snoise):

float snoise(vec3 v, out vec3 grad) 
{ 
    ...... 

    // Mix final noise value 
    vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); 
    vec4 m2 = m * m; 
    vec4 m4 = m2 * m2; 

    vec4 pdotx = vec4(dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3)); 

    vec4 temp = m2 * m * pdotx; 
    grad = -8.0 * (temp.x * x0 + temp.y * x1 + temp.z * x2 + temp.w * x3); 
    grad += m4.x * p0 + m4.y * p1 + m4.z * p2 + m4.w * p3; 
    grad *= 42.0; 

    return 42.0 * dot(m4, pdotx); 
} 

UPDATE:

Część o obliczaniu powierzchni normalny z gradientem została tutaj odpowiedział: Surface normal to point on displaced sphere.

Pozostaje pytanie, jak zaimplementować obliczenia gradientowe w GLSL wersji 3D Simplex Noise, ponieważ moja implementacja wydaje się mieć problemy.

UPDATE 2:

Obliczanie gradientu wydaje się być prawie rację, tylko skalowanie wydaje się być wyłączony.
Zamiast mnożenia przez 42, dzielenie przez 5 daje całkiem dobre wyniki, ale zostało to wykryte metodą prób i błędów. Właściwy współczynnik skalowania byłby miły.

+0

Aby odpowiedzieć na pierwsze pytanie: tak i nie. Wartości normalne dla jednego z wierzchołków mogą być gładkie, jeśli masz informacje o sąsiadujących trójkątach lub mogą być płaskie, jeśli obliczysz je za pomocą jednego trójkąta. Używając shaderów geometrii i trójkątnego paska z przyległością, można uzyskać do 4 współdzielonych trójkątów na jeden wierzchołek, co *** może *** (biorąc pod uwagę, że to * nie * w rzeczywistości jest liczbą trójkątów, do których należy każdy wierzchołek) wystarczy obliczyć przybliżoną gładkość na każdy wierzchołek normalny. Będziesz musiał uporządkować swoje wskaźniki wierzchołków wejściowych w bardzo określonej kolejności, aby to osiągnąć i wymaga GL 3.2+. –

+0

Jeśli zrozumiałem to poprawnie, wynikowe wartości normalne będą gładkie, jeśli normalny dla danego wierzchołka jest taki sam, bez względu na to, jaka twarz jest aktualnie przetwarzana. Zakładając, że obliczenia przebiegają tak, jak opisałem, tak będzie, ponieważ normalne będą zależeć tylko od informacji o pojedynczym wierzchołku, do którego należą. – Gigo

+0

Cóż, (gładka) normalność per-vertex zależy od pozostałych 2 wierzchołków w każdym trójkącie, który dzieli ten wierzchołek. Patrzę na twoją siatkę i zauważam niektóre wierzchołki z aż dziesięcioma trójkątami dzielącymi ten sam wierzchołek. Jeśli chcesz poprawnie wygładzić te normalne wierzchołki, musisz obliczyć twarz normalną dla wszystkich 10 z tych trójkątów. Dlatego nie wydaje się to praktyczne. –

Odpowiedz

1

W porządku, okazało się, że mój problem był prawie wyłącznie związany z matematyką.

Jeśli ktokolwiek jest zainteresowany:
Implementacja gradientu GLSL zamieszczona w pytaniu jest całkowicie poprawna.
Obliczanie normalnych bezpośrednio z gradientu jest możliwe zgodnie z opisem here.

A wynik wygląda dokładnie tak jak chciałem go mieć, jestem zadowolony;) ​​

Smooth per-vertex normals