Последовательное определение направления нормалей граней?

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

Можно ли правильно рассчитать нормали граней, учитывая список вершин и список таких граней:

v1: x_1, y_1, z_1
v2: x_2, y_2, z_2
...
v_n: x_n, y_n, z_n
f1: v1,v2,v3
f2: v4,v2,v5
...
f_m: v_j, v_k, v_l

Каждый x_i, y_i , z_i определяет положение вершин в трехмерном пространстве (но не обязательно вектор)

Каждый f_i содержит индексы трех определяющих его вершин.

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

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


person Abe    schedule 09.08.2019    source источник


Ответы (2)


В компьютерной графике это делается по правилу обмотки многоугольника. Это означает, что все грани определены, поэтому точки расположены в порядке CW (или CCW), если смотреть непосредственно на лицо. Тогда использование кросс-продукта приведет к согласованным нормам.

Однако многие сети не соответствуют правилу намотки (некоторые грани CW, другие CCW не все одинаковы), и для них это проблема. Я знаю два подхода:

  1. для простых форм (не слишком вогнутых)

    знак скалярного произведения ваших face_normal и face_center-cube_center сообщит вам, если нормальные точки находятся внутри или снаружи объекта.

    точка

    if ( dot( face_normal , face_center-cube_center ) >= 0.0 ) normal_points_out
    

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

  2. проверьте, находится ли точка над лицом внутри или нет

    просто сместите центр грани на небольшое расстояние (не слишком большое) в нормальном направлении, а затем проверьте, находится ли точка внутри многоугольной сетки или нет:

    смещение

    if ( !inside( face_center+0.001*face_normal ) ) normal_points_out
    

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

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

output_color = face_color * abs(dot(face_normal,light_direction))

некоторые API-интерфейсы gfx уже реализовали это (ищите двусторонние материалы или нормали, при их включении обычно используется значение abs ...) Например, в OpenGL:

glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
person Spektre    schedule 10.08.2019

В общем, нет никакого способа назначить нормаль "последовательно" по всему набору трехмерных граней ... рассмотрим в качестве примера знаменитую ленту Мёбиуса ...

Изображение ленты Мёбиуса

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

Тем не менее, если ваша коллекция треугольников действительно ориентируема (то есть действительно существует последовательное нормальное назначение), решение состоит в том, чтобы начать с одного треугольника, а затем распространить его на соседей, как в алгоритме заливки. Например, в Python это будет выглядеть примерно так:

active = [triangles[0]]
oriented = set([triangles[0]])
while active:
    next_active = []
    for tri in active:
        for other in neighbors(tri):
            if other not in oriented:
                if not agree(tri, other):
                    flip(other)
                oriented.add(other)
                next_active.append(other)
    active = next_active
person 6502    schedule 10.08.2019
comment
Спасибо за ответ, я бы тоже поддержал это, если бы это было возможно! - person Abe; 11.08.2019