Нормальное отображение OpenGL

#opengl #bump-mapping

#opengl #bump-сопоставление

Вопрос:

Я пытаюсь реализовать нормальное отображение, используя простой куб, который я создал. Я следовал этому руководству https://learnopengl.com/Advanced-Lighting/Normal-Mapping но я не могу понять, как должно выполняться нормальное отображение при рисовании 3D-объектов, поскольку в учебнике используется 2d-объект.

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

Непосредственно освещенный

непосредственно освещенный

Сторона подсвечена

сторона подсвечена

Здесь я действительно попытался вычислить свои нормали и касательные по-другому. (совершенно неверно)

еще одна попытка

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

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

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

Редактировать —

Я передаю нормаль и касательную к вершинному шейдеру и настраиваю свою матрицу TBN. Но, как вы можете видеть на первом изображении, рисуя грань за гранью моего куба, кажется, что те грани, которые примыкают к той, на которую я смотрю прямо (которая хорошо освещена), неправильно освещены, и я не знаю почему. Я думал, что я неправильно вычислял свою нормаль и касательную «на лицо». Я думал, что вычисление некоторой нормали и касательной, которая учитывает объект в целом, может быть правильным способом. Если правильно вычислить нормаль и касательную, как видно на втором изображении (зеленая нормаль, красная касательная), для настройки матрицы TBN, почему правая грань кажется плохо освещенной?

ПРАВКА 2 —

Вершинный шейдер:


 void main(){

   texture_coordinates = textcoord;
   fragment_position = vec3(model * vec4(position,1.0));

   mat3 normalMatrix = transpose(inverse(mat3(model)));
   vec3 T = normalize(normalMatrix * tangent);
   vec3 N = normalize(normalMatrix * normal);
   T = normalize(T - dot(T, N) * N);
   vec3 B = cross(N, T);
   mat3 TBN = transpose(mat3(T,B,N));
   view_position =  TBN * viewPos; // camera position
   light_position = TBN * lightPos; // light position
   fragment_position = TBN * fragment_position;
  
   gl_Position = projection * view * model * vec4(position,1.0);
}
  

В VS я настраиваю свою матрицу TBN и преобразую все векторы освещения, фрагментации и просмотра в касательное пространство; при этом мне не нужно будет выполнять какие-либо другие вычисления в шейдере фрагментов.

Фрагментный шейдер:

  void main() {
    vec3 Normal = texture(TextSamplerNormals,texture_coordinates).rgb; // extract normal
    Normal = normalize(Normal * 2.0 - 1.0); // correct range
    material_color = texture2D(TextSampler,texture_coordinates.st); // diffuse map

    vec3 I_amb = AmbientLight.color * AmbientLight.intensity;
    vec3 lightDir = normalize(light_position - fragment_position);

    vec3 I_dif = vec3(0,0,0);
    float DiffusiveFactor = max(dot(lightDir,Normal),0.0);
    vec3 I_spe = vec3(0,0,0);
    float SpecularFactor = 0.0;

    if (DiffusiveFactor>0.0) {
       I_dif = DiffusiveLight.color * DiffusiveLight.intensity * DiffusiveFactor;

       vec3 vertex_to_eye = normalize(view_position - fragment_position); 
       vec3 light_reflect = reflect(-lightDir,Normal);
       light_reflect = normalize(light_reflect);

       SpecularFactor = pow(max(dot(vertex_to_eye,light_reflect),0.0),SpecularLight.power);
       if (SpecularFactor>0.0)  {
           I_spe = DiffusiveLight.color * SpecularLight.intensity * SpecularFactor;
       }
   }

   color = vec4(material_color.rgb * (I_amb   I_dif   I_spe),material_color.a);

}
  

введите описание изображения здесь

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

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

2. Мне все еще чего-то не хватает. Но да, дайте мне время, чтобы предоставить то, что вы просили.

3. Я подозреваю, что ваши формулы взяты прямо из учебника learnopengl. Я никогда этого не делал, поэтому я склонен вычислять вещи по-другому, что проще. Вместо того, чтобы преобразовывать ваши параметры освещения в касательное пространство, передайте world normal, tnagent и bytangent модели напрямую. Затем во фрагменте ваша нормальная текстура n, преобразованная в мировое пространство n.x * B n.y * T n.z * N , равна, т.е. взвешенной сумме ортонормированного базиса модели, где веса являются коэффициентами нормали текстуры. Попробуйте это и распечатайте полученные нормали в виде цветов, пожалуйста.

4. Я добавил скриншот. Выглядит довольно странно..

Ответ №1:

Обработка прерывности против непрерывности

Вы думаете об этом неправильно.

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

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

Фактический алгоритм

  • Загрузка значений rgb нормального
  • Преобразовать в диапазон от -1 до 1
  • Поворот по матрице модели
  • Используйте новое значение в вычислениях затенения

Если вам нужны непрерывные нормали, то вам нужно убедиться, что диаграммы в текстурном пространстве, которые вы используете, подчиняются тому, что границы текстурных координат совпадают.

Математически это означает, что если U и V являются областями R ^ 2, которые отображаются на нормальное поле N вашей фигуры, то, если функция отображения равна f, это должно быть так:

Если lim S(x_1, x_2) = lim S(y_1, y_2), где {x1,x2} подмножество U и {y_1, y_2} подмножество V, то lim f(x_1, x_2) = lim f(y_1, y_2).

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

TL; DR не отображаются во фрагменте. Это то, что должно выполняться самой картой нормалей при ее выпекании, а не вами при рендеринге.

Обработка касательного пространства

У вас есть 2 варианта. Вариант n1, вы передаете касательную T и нормаль N шейдеру. В этом случае бинормальное значение B равно T X N, а базис {T, N, B} дает вам истинное пространство, в котором должны быть выражены нормали.

Предположим, что в касательном пространстве x — сторона, y — прямая, z — вверх. Ваша преобразованная нормаль становится (xB, yT, zN) .

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

(Обратите внимание, что N — нормальная модель, где (x, y, z) — нормальная карта)

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

1. Извините, но я все еще не понимаю, что мне делать. Я не пытаюсь создать карту нормалей, но мне нужно вычислить касательное пространство. Вы хотите сказать, что я должен вычислять простые нормали и касательные для каждой грани, а карта нормалей выполнит всю остальную работу, поскольку мне нужно только касательное пространство? Потому что карты нормалей обычно находятся в касательном пространстве

2. Мой плохой, я не понял вашу проблему, я добавил редактирование, дайте мне знать, если это полезно.

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