Небольшая проблема при вычислении нормалей вершин (OpenGL ES)

#opengl-es #light #normals

#opengl-es #light #нормали

Вопрос:

У меня небольшая проблема с нормалью к вершинам.

Результат кажется немного странным. Сначала взглянем на изображения:

Оригинальная модель в программном обеспечении 3D.

Освещение для каждого фрагмента с сеткой, импортированной непосредственно из OBJ-файла (с использованием нормалей из файла).

Освещение для каждого фрагмента, вычисление нормалей с помощью моей собственной процедуры.

Вы заметили? При использовании нормалей из OBJ-файла все в порядке. Но когда я использую свою собственную процедуру для вычисления нормалей на основе вершин, что-то кажется неправильным.

Нормали кажутся странными именно тогда, когда Z становится отрицательным (при использовании правой ориентации). В других частях объекта все в порядке, но только одна воображаемая линия через сетку кажется странной. Эта проблема сохраняется на других сетках, всегда в одном и том же месте, Z = 0.

Моя процедура вычисления нормалей — это та, которую все знают, предполагающая треугольник с вершинами ABC:

 vec3 normal = normalize(cross(C - A, B - A));
  

А затем добавление нормального результата в уже вычисленный нормальный буфер.

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

Вы видели это раньше? Вы знаете, как это решить?

Вот некоторый код:

 // Looping at each triangle
vec3 distBA = vec3Subtract(vB, vA);
vec3 distCA = vec3Subtract(vC, vA);

vec3 normal = vec3Cross(distBA, distCA);

// Each normalBuffer represents one vertex.
normalBuffer[i1] = vec3Add(normal, normalBuffer[i1]);
normalBuffer[i2] = vec3Add(normal, normalBuffer[i2]);
normalBuffer[i3] = vec3Add(normal, normalBuffer[i3]);

// After pass through all faces/triangles.

// Looping at each Vertex structure.
normal = vec3Normalize(normalBuffer[i]);
  

Комментарии:

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

2. Кроме того, я не уверен, что понял, почему вы добавляете нормали в обычный буфер, а не просто устанавливаете их?

3. Шейдеры одинаковы в обоих случаях (нормали из OBJ и вычисленные мной). С нормалями из OBJ все работает, поэтому я не думаю, что проблема здесь. Буфер предназначен для суммирования нормалей одной и той же вершины, но из разных треугольников, таких как смежные треугольники. Я действительно не могу понять, почему это происходит.

4. Но проблема может заключаться в обеих частях кода, например, шейдер может быть недостаточно надежен для обработки некоторых проблем с входными данными (например, ненормализованные нормали, хотя я вижу, что вы действительно их нормализуете). Еще один тест, который я бы сделал: просто используйте первую вычисленную нормаль, а не добавляйте normalizing, это исключает любую проблему с этой частью кода.

5. Еще один тест для выполнения: визуализируйте один треугольник, пересекающий z=0 линию. Это ясно покажет, связана ли часть проблемы с затенением или нет. Также: отключите зеркальность. В общем, постарайтесь максимально упростить тестовый пример, чтобы исключить всевозможные «отвлекающие факторы».

Ответ №1:

В зависимости от того, как вы вычисляете освещение для каждого фрагмента (т. Е. устанавливаете ли вы скалярное произведение в диапазоне 0-1 или нет), то, что вы видите, может быть просто проблемой инвертированных нормалей. В зависимости от того, как вы выбираете A , B , C , нормаль в вершине может указывать в любом направлении. Чтобы отличить внешнюю сторону треугольника от внутренней, вам обычно требуется дополнительная информация, например, расположение вершин. Вы принимаете это во внимание?

Комментарии:

1. Я уже перепробовал все комбинации вычислений с A, B, C… Остальные результаты абсолютно неверны… Я все еще ищу решение..

2. Я имел в виду что-то немного другое. Я не говорю, что вы подбираете A, B, C в неправильном порядке. Я говорю, что порядок может зависеть от некоторой другой информации, которая может быть правильной для половины чайника и неправильной для другой половины. Поэтому я бы не ожидал, что какая-либо конкретная комбинация будет правильной в этом случае. В любом случае, если попытка использовать все из них не дала вам никакого дополнительного понимания, это, вероятно, не в правильном направлении.

Ответ №2:

Вы нормализуете результат «, а затем добавляете нормальный результат в уже вычисленный нормальный буфер.». Я не уверен, что вам нужно, но добавить это не помешает. И, пока вы этим занимаетесь, проверьте наличие NaN и бесконечности.

Проверяете ли вы в своей функции нормализации, если длина входящего вектора больше 0?

У меня есть подозрение, что у вас где-то в вашей векторной библиотеке есть неприятная ошибка, тем более что проблема возникает только для оси Z.

Комментарии:

1. Да, чувак… Я уже делаю все, что вы сказали … это сводит меня с ума… Смотрите, я отредактировал вопрос, добавив туда немного кода.