#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. Да, чувак… Я уже делаю все, что вы сказали … это сводит меня с ума… Смотрите, я отредактировал вопрос, добавив туда немного кода.