Нормальное отображение на процедурной сфере
Я учусь в видеоиграх, и мы работаем над raytracer в C++. Мы используем библиотеку наших учителей.
Мы создаем процедурные объекты (в нашем случае - сферу), Камера отправляет луч для каждого пикселя экрана, и луч отправляет обратно информацию о том, что он ударил.
Некоторые из нас решили интегрировать карты нормалей. Итак, сначала мы отправили луч на объект, посмотрели на значение текселя карты нормалей, где мы попали в сферу, преобразовали его в вектор, нормализовали и отправили обратно вместо нормали объекта. Результат был довольно хорошим, но, конечно, он больше не принимал во внимание ориентацию "лица" (она процедурная, поэтому лица нет, но она дает идею), поэтому рендер был плоским.
Мы до сих пор не знаем, как "смешать" нормали текстуры (в касательном пространстве) и нормали объекта вместе. Вот наш код:
// TGfxVec3 is part of our teachers library, and is a 3d vector like this:
// TGfxVec3( 12.7f, -13.4f, 52.0f )
// The sphere being at the origin and of radius 1, and tHit.m_tPosition being the
// exact position at the surface of the sphere where the ray hit, the normal of this
// point is the position hit by the ray.
TGfxVec3 tNormal = tHit.m_tPosition;
TGfxVec3 tTangent = Vec3CrossProduct( tNormal , m_tAxisZ );
TGfxVec3 tBiNormal = Vec3CrossProduct( tNormal , tTangent );
TGfxVec3 tTextureNorm = 2*(TGfxVec3( pNorm[0], pNorm[1], pNorm[2] )/255)-TGfxVec3( -1.0f, -1.0f, -1.0f );
// pNorm[0], pNorm[1], pNorm[2] are respectively the channels Red, Green,
// and Blue of the Normal Map texture.
// We put them in a 3D vector, divid them by 255 so their value go from 0 to 1,
// multiply them by 2, and then substract a vector, so their rang goes from -1 to +1.
tHit.m_tNorm = TGfxVec3( tTangente.x*tTextNorm.x + tCoTangente.x*tTextNorm.x +
tNorm.x*tTextNorm.x, tTangente.y*tTextNorm.y + tCoTangente.y*tTextNorm.y +
tNorm.y*tTextNorm.y, tTangente.z*tTextNorm.z + tCoTangente.z*tTextNorm.z +
tNorm.z*tTextNorm.z ).Normalize();
// Here, after some research, I came across this : http://www.txutxi.com/?p=316 ,
// that allow us to convert the normal map tangent space to the object space.
Результаты все еще не хороши. Мое главное беспокойство касаются тангенса и бинормалей. Ось взята по ссылке (здесь: m_tAxisZ
(Ось Z сферы), не верно. Но я не знаю, что взять, или даже если то, что я делаю, действительно хорошо. Поэтому я пришел сюда за помощью.
2 ответа
Вы в основном правы и совершенно не правы одновременно.
Отображение нормалей касательного пространства использует матрицу преобразования для преобразования нормали касательного пространства из текстуры в другое пространство, например объект или мировое пространство, или преобразует свет в пространстве касательных, чтобы вычислить освещение со всем в одном и том же пространстве.
Би-нормаль является распространенной ошибкой и должна быть названа би-касательной.
Иногда можно рассчитать TBN на лету по простой геометрии, как на карте высот, так как легко вывести касательную и двух касательную на регулярной сетке. Но на сфере перекрестный трюк с фиксированной осью приведет к сингулярности на полюсе, где перекрестное произведение дает вектор нулевой длины.
Наконец, даже если мы игнорируем сингулярность полюсов, TBN должен быть нормализован, прежде чем применять матрицу к касательной к нормали. Вы также можете пропустить транспозицию, поскольку обратная ортонормированная матрица 3x3 - это транспонирование, а вам нужна обратная сторона исходной матрицы TBN, если вы переходите от касательной к объекту.
Из-за всего этого мы чаще всего сохраняем TBN как дополнительную информацию в геометрии, вычисляемую из координаты текстуры (URL-адрес, на который вы ссылались, в этом описании вычисления) и интерполируем во время выполнения с другими значениями.
Rem: есть грубое упрощение, чтобы использовать нормальную геометрию как нормальный TBN, но нет никакой причины, во-первых, что они соответствуют.
Итак, мы наконец сделали это.:D Хорошо, я постараюсь быть ясным. Для этого два изображения:
(1): http://i.imgur.com/cHwrR9A.png
(2): http://i.imgur.com/mGPH1RW.png
(Мои навыки рисования не имеют себе равных, я знаю).
Итак, основной проблемой было найти касательную "Т" и би-касательную "В". У нас уже есть Нормальный "N". Наш круг всегда находится в начале координат с радиусом 1, точка на его поверхности равна нормали к этой точке (черно-красный вектор на первом изображении). Итак, мы должны найти касательную к этой точке (зеленым цветом). Для этого нам просто нужно повернуть вектор из PI/2 rad:
С N( x, y):
T = ( -N.y , N.x )
Тем не менее, мы в 3D. Так что точка не всегда будет на экваторе. Мы можем легко решить эту проблему, игнорируя положение в Y нашей точки и нормализуя вектор только с двумя другими компонентами. Итак, на втором изображении у нас есть P (мы устанавливаем его значение Y в 0), и мы нормализуем новый вектор, чтобы получить P'.
С P( x, y, z):
P' = ( P.x, 0, P.z).Normalize();
Затем мы возвращаемся к моему первому сообщению, чтобы найти T. Наконец, мы получаем B с перекрестным произведением между N и T. Наконец, мы вычисляем нормаль к этой точке, принимая во внимание карту нормалей.
С переменной "Карта", содержащей три канала (RGB) карты нормалей, каждый из которых ограничен от -1 до 1, а T, N и B являются трехмерными векторами:
( Map.R*T + Map.G*B + Map.B*N ).Normalize();
И это все, у вас есть нормаль к точке с учетом вашей карты нормалей.:) Надеюсь, что это будет полезно для других.