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