OpenGL, как управлять отрицательными нормалями? - PullRequest
0 голосов
/ 13 июня 2018

С кубом, определенным как в следующем коде, вы видите, что нормали часто отрицательны на одной оси.(даже если мы их вычислим)

OpenGL управляет им с помощью своего фиксированного конвейера, поправьте меня, если я ошибаюсь, но с программируемым конвейером это вызывает артефакты, такие как черные лица.(Мой предыдущий вопрос stackoverflow содержит код.)

Мне удалось запустить мой код с операцией на моих нормалях (normal = (0.5 + 0.5 * normal);), но даже еслирезультат выглядит хорошо, мне интересно, если мои нормали все еще действительны?(И эта операция самая лучшая?)

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

Упомянутые нормали:

const GLfloat cube_vertices[] = {
  1, 1, 1,  -1, 1, 1,  -1,-1, 1,      // v0-v1-v2 (front)
  -1,-1, 1,   1,-1, 1,   1, 1, 1,      // v2-v3-v0
  1, 1, 1,   1,-1, 1,   1,-1,-1,      // v0-v3-v4 (right)
  1,-1,-1,   1, 1,-1,   1, 1, 1,      // v4-v5-v0
  1, 1, 1,   1, 1,-1,  -1, 1,-1,      // v0-v5-v6 (top)
  -1, 1,-1,  -1, 1, 1,   1, 1, 1,      // v6-v1-v0
  -1, 1, 1,  -1, 1,-1,  -1,-1,-1,      // v1-v6-v7 (left)
  -1,-1,-1,  -1,-1, 1,  -1, 1, 1,      // v7-v2-v1
  -1,-1,-1,   1,-1,-1,   1,-1, 1,      // v7-v4-v3 (bottom)
  1,-1, 1,  -1,-1, 1,  -1,-1,-1,      // v3-v2-v7
  1,-1,-1,  -1,-1,-1,  -1, 1,-1,      // v4-v7-v6 (back)
  -1, 1,-1,   1, 1,-1,   1,-1,-1 };    // v6-v5-v4

const GLfloat cube_normalsI[] = {
  0, 0, 1,   0, 0, 1,   0, 0, 1,      // v0-v1-v2 (front)
  0, 0, 1,   0, 0, 1,   0, 0, 1,      // v2-v3-v0
  1, 0, 0,   1, 0, 0,   1, 0, 0,      // v0-v3-v4 (right)
  1, 0, 0,   1, 0, 0,   1, 0, 0,      // v4-v5-v0
  0, 1, 0,   0, 1, 0,   0, 1, 0,      // v0-v5-v6 (top)
  0, 1, 0,   0, 1, 0,   0, 1, 0,      // v6-v1-v0
  -1, 0, 0,  -1, 0, 0,  -1, 0, 0,      // v1-v6-v7 (left)
  -1, 0, 0,  -1, 0, 0,  -1, 0, 0,      // v7-v2-v1
  0,-1, 0,   0,-1, 0,   0,-1, 0,      // v7-v4-v3 (bottom)
  0,-1, 0,   0,-1, 0,   0,-1, 0,      // v3-v2-v7
  0, 0,-1,   0, 0,-1,   0, 0,-1,      // v4-v7-v6 (back)
  0, 0,-1,   0, 0,-1,   0, 0,-1 };    // v6-v5-v4

1 Ответ

0 голосов
/ 13 июня 2018

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

Нормаль может быть направлена ​​в любую сторону, а нормали часто отрицательны по одной оси совершенно естественно.Почему бы им не быть?Судя по тому, что вы описываете, вы работаете с освещением.Часть освещения использует нормаль, чтобы увидеть угол между источником света и поверхностью.Идея здесь состоит в том, что когда вы поворачиваете нормаль, луч света эффективно осветляет большую часть поверхности, что уменьшает плотность отраженного света.С базовой математикой вы можете видеть, что корреляция составляет cos(angle), поэтому параллельные векторы будут давать самую высокую яркость.Поскольку мы используем векторы, нам лучше заменить cos точечным произведением.

Так что в какой-то момент у вас есть

float factor = dot(normalize(normal), normalize(lightSource-surfacePoint))

Давайте приведем 2 примера:

normal = (0, 1, 0)
lightSource = (0, 1, 0)
surfacePoint = (0, 0, 0)
dot((0, 1, 0), (0, 1, 0)) = 0+1+0 = 1

и переверните его:

normal = (-1, 0, 0)
lightSource = (-3, 1, 0)
surfacePoint = (0, 1, 0)
dot((-1, 0, 0), normalize(-3, 0, 0)) = dot((-1, 0, 0), (1, 0, 0)) = 1+0+0 = 1

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

Единственный вопрос здесь состоит в том, что делать, когда точка продукта отрицательна.Это происходит, когда нормальные лица от света.В вашем случае у вас есть куб, и все нормали направлены наружу.Что если вам нужно быть внутри куба и при этом иметь освещение?Вы получите

normal = (0, 1, 0)
lightSource = (0, 0, 0)
surfacePoint = (0, 1, 0)
dot((0, 1, 0), (0, -1, 0)) = 0-1+0 = -1

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

fragmentColor += lightColor*dotFactor // Do nothing and your light will darken the area
fragmentColor += lightColor*abs(dotFactor) // Use absolute value to lighten even if facing away
fragmentColor += lightColor*max(0.0, dotFactor) // Clamp minimum so there are no negative values.

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

...