2012-06-13 10 views
7

Mam program, który generuje mapę wysokości, a następnie wyświetla ją jako siatkę w OpenGL. Kiedy próbuję dodać oświetlenie, kończy się dziwacznymi kwadratowymi kształtami pokrywającymi siatkę. Są bardziej widoczne w niektórych obszarach niż inne, ale zawsze tam są.Dziwne kwadratowe artefakty oświetleniowe w OpenGL

Używam siatki quad, ale nic się nie zmieniło po przełączeniu do siatki trójkątów. Użyłem co najmniej trzech różnych metod do obliczenia normali vertex, wszystkie z tym samym efektem. Robiłem oświetlenie ręcznie za pomocą shaderów, ale nic się nie zmienia podczas korzystania z wbudowanego systemu oświetlenia OpenGL .

Mój najnowszy kod generujący normalny (skierowana jest tablicą wskaźników do Verts tablica wierzchołków):

int i; 
for (i = 0; i < NINDEX; i += 3) { 
    vec v[3]; 
    v[0] = verts[faces[i + 0]]; 
    v[1] = verts[faces[i + 1]]; 
    v[2] = verts[faces[i + 2]]; 

    vec v1 = vec_sub(v[1], v[0]); 
    vec v2 = vec_sub(v[2], v[0]); 

    vec n = vec_norm(vec_cross(v2, v1)); 

    norms[faces[i + 0]] = vec_add(norms[faces[i + 0]], n); 
    norms[faces[i + 1]] = vec_add(norms[faces[i + 1]], n); 
    norms[faces[i + 2]] = vec_add(norms[faces[i + 2]], n); 
} 

for (i = 0; i < NVERTS; i++) { 
    norms[i] = vec_norm(norms[i]); 
} 

Mimo, że nie jest to tylko kod użyłem, więc wątpię, że to jest przyczyną problemu.

rysuję siatkę z:

I nie obecnie używam żadnych shaderów.

Co może być przyczyną?

EDIT: Bardziej wszechstronny zestaw screenów:

Na ostatnim, kod shaderów jest

Vertex:

varying vec3 lightvec, normal; 

void main() { 
    vec3 lightpos = vec3(0, 0, 100); 
    vec3 v = vec3(gl_ModelViewMatrix * gl_Vertex); 
    normal = gl_NormalMatrix * gl_Normal; 

    lightvec = normalize(lightpos - v); 

    gl_Position = ftransform(); 
} 

Fragment:

varying vec3 lightvec, normal; 

void main(void) { 
    float l = dot(lightvec, normal); 
    gl_FragColor = vec4(l, l, l, 1); 
} 
+0

Czy możesz umieścić dwa zrzuty ekranu tej samej sceny, jedną z karkasem, a drugą bez? –

+0

Czy "norms' zero-initialized? Gromadzisz wektory do niego bez uprzedniego zerowania, ale jeśli jest wyzerowany w innym miejscu programu, nie powinno to stanowić problemu. – genpfault

+0

Czy używasz płynnej interpolacji dla normalnych atrybutów w module cieniującym? Być może przejście na 'flat' może trochę pomóc w zlokalizowaniu problemu. Ponadto, oświetlenie OpenGL jest dla mnie bardzo niebezpieczne - zazwyczaj jestem bardziej pewny, że sam napisałem kod. –

Odpowiedz

1

nie mam ostateczną odpowiedź dla wersji bez cieniowania, ale chciałem dodać, że jeśli robisz za oświetlenie w pikselach twój shader fragmentu, prawdopodobnie powinieneś normalizować normalne i lightvec wewnątrz shadera fragmentów.

Jeśli tego nie zrobisz, nie będą to długość jednostki (interpolacja liniowa między dwoma znormalizowanymi wektorami niekoniecznie jest znormalizowana). To może wyjaśnić niektóre artefakty, które widzisz w wersji modułu cieniującego, ponieważ wielkość iloczynu skalarnego różni się w zależności od odległości od wierzchołków, co wygląda na to, co widzisz.

EDYCJA: Kolejna myśl, czy robisz jakieś niejednolite skalowanie (różne x, y, z) siatki podczas renderowania wersji innej niż shader? Jeśli ją skalujesz, musisz zmodyfikować wartości normalne za pomocą współczynnika skali odwrotnej lub ustawić glEnable(GL_NORMALIZE).Zobacz więcej tutaj: http://www.lighthouse3d.com/tutorials/glsl-tutorial/normalization-issues/

2

Trzeba albo znormalizować normalne w cieniującego fragmentu, tak jak poniżej:

varying vec3 lightvec, normal; 

void main(void) { 
    vec3 normalNormed = normalize(normal); 
    float l = dot(lightvec, normalNormed); 
    gl_FragColor = vec4(l, l, l, 1); 
} 

To może być drogie. W tym przypadku, w przypadku świateł kierunkowych, będzie również stosowane oświetlenie wierzchołków. Więc obliczyć wartość światła w vertex shader

varying float lightItensity; 

void main() { 
    vec3 lightpos = vec3(0, 0, 100); 
    vec3 v = vec3(gl_ModelViewMatrix * gl_Vertex); 
    normal = gl_NormalMatrix * gl_Normal; 

    lightvec = normalize(lightpos - v); 

    lightItensity = dot(normal, lightvec); 

    gl_Position = ftransform(); 
} 

i używać go w moduł cieniujący fragmentu,

varying float light; 

void main(void) { 
    float l = light; 
    gl_FragColor = vec4(l, l, l, 1); 
} 

Mam nadzieję, że rozwiązuje go, daj mi znać, jeśli nie robi.

EDIT: Herezje mały diagram, który wyjaśnia, co jest najprawdopodobniej dzieje

enter image description here

Edit2:

Jeśli to nie pomoże, należy dodać kolejne trójkąty. Interpoluj wartości swojej mapy wysokości i dodaj kilka wierzchołków pomiędzy.

Alternatywnie, spróbuj zmienić schemat tesselation. Na przykład siatka trójkątów równobocznych może sprawić, że artefakty będą mniej widoczne.

enter image description here

Będziesz musiał zrobić kilka interpolacji na mapy wysokości.

W przeciwnym razie nie mam pojęcia .. Powodzenia!

+0

Dzięki, ale niestety już próbowałem zrobić coś takiego. Zaczynam się zastanawiać, czy problem tkwi w mojej karcie graficznej (1,5-letni zintegrowany układ Intela). – sigill

+0

Bardzo w to wątpię. Kod Shadera powinien działać w taki sam sposób na dowolnej karcie graficznej, która go obsługuje. – Hannesh