2012-06-13 3 views
7

У меня есть программа, которая генерирует карту высот, а затем отображает ее как сетку с OpenGL. Когда я пытаюсь добавить освещение, он заканчивается странными квадратными фигурами, покрывающими сетку. Они более заметны в некоторых областях, чем другие, но всегда там.Странные квадратные артефакты освещения в OpenGL

Я использовал квадратную сетку, но после переключения на треугольную сетку ничего не изменилось. Я использовал по крайней мере три разных метода для вычисления нормалей вершин, все с одинаковым эффектом. Я делал освещение вручную с помощью шейдеров, но при использовании встроенной системы освещения OpenGL ничего не меняется.

Мой последний нормальный генерирующий код (лица представляет собой массив индексов в Verts, массив вершин):

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]); 
} 

Хотя это не единственный код, который я использовал, так что я сомневаюсь, что это является причиной проблемы.

Я рисую сетку с:

И я в настоящее время не используется никаких шейдеров.

Что может быть причиной этого?

EDIT: Более полный набор скриншотов:

Для последнего, код шейдера

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(); 
} 

Фрагмент:

varying vec3 lightvec, normal; 

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

Не могли бы вы разместить два скриншота одной и той же сцены, один с каркасом и один без? –

+0

Является ли 'norm' нулевой инициализацией? Вы накапливаете свои векторы в него, не обнуляя его сначала, хотя, если он обнуляется в другом месте программы, это не должно быть проблемой. – genpfault

+0

Вы используете гладкую интерполяцию для обычных атрибутов в шейдере? Возможно, переход на «плоский» для бит может помочь локализовать проблему. Кроме того, освещение OpenGL имеет тенденцию быть очень затруднительным для меня - я обычно более уверен в коде, который я написал сам. –

ответ

1

У меня нет окончательного ответа на версии без шейдеров, но я хотел бы добавить, что если вы делаете на освещение пиксела в ваш шейдер фрагмента, вероятно, вы, должно быть, нормализуете нормальный и lightvec внутри шейдера фрагмента.

Если вы этого не сделаете, они не являются единичной длиной (линейная интерполяция между двумя нормализованными векторами необязательно нормализована). Это может объяснить некоторые из артефактов, которые вы видите в версии шейдера, поскольку величина точечного продукта будет меняться в зависимости от расстояния от вершин, что похоже на то, что вы видите.

EDIT: Еще одна мысль: вы делаете какое-либо неравномерное масштабирование (разные x, y, z) сетки при рендеринге не-шейдерной версии? Если вы масштабируете его, вам нужно либо изменить нормали по обратному масштабному коэффициенту, либо установить glEnable(GL_NORMALIZE).Смотрите здесь больше: http://www.lighthouse3d.com/tutorials/glsl-tutorial/normalization-issues/

2

Вам необходимо либо нормализовать нормальный в пиксельный шейдер, например, так:

varying vec3 lightvec, normal; 

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

Это может быть дорого, хотя. То, что также будет работать в этом случае с направленными огнями, заключается в использовании вершинного освещения. Таким образом, вычислить значение света в вершинном шейдере

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(); 
} 

и использовать его в пиксельный шейдер,

varying float light; 

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

Я надеюсь, что это фиксирует это, дайте мне знать, если это не так.

EDIT: Heres небольшая схема, которая объясняет, что, скорее всего, происходит

enter image description here

edit2:

Если это не помогает, добавьте больше треугольников. Интерполируйте значения вашей карты высот и добавьте некоторые вершины между ними.

В качестве альтернативы попробуйте изменить схему тесселяции. Например, сетка равносторонних треугольников, например, могла бы сделать артефакты менее заметными.

enter image description here

Вы должны сделать некоторые интерполяции на ваши высоты.

В противном случае я понятия не имею .. Удачи!

+0

Спасибо, но, к сожалению, я уже пробовал делать что-то подобное. Я начинаю задаваться вопросом, есть ли проблема в моей графической карте (1,5-летняя интегрированная чип Intel). – sigill

+0

Я очень сомневаюсь. Шейдерный код должен выполняться одинаково на любой графической карте, которая его поддерживает. – Hannesh