На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! Правила раздела "Программирование графики"
1) Данный раздел предназначен для обсуждения проблем, возникающих при программировании задач, связанных с чтением, сохранением, обработкой, созданием, отрисовкой графической информации (в том числе - 3D [OpenGL, Direct3D] и анимации [в т.ч. VFW, DirectShow, OpenDML]).
Флэш обсуждают здесь!.

2) Если вы хотите получить совет для конкретной платформы/языка программирования, обязательно укажите их в вопросе.

3) Уважаемые новички! Мы приветствуем Ваше желание научить всех посетителей раздела правильному программированию. Но огромная просьба, перед тем, как писать поучения в старых (последний ответ - "старее" месяца, а особенно, если вопрошавший не появляется на форуме уже не первый месяц, в чем можно убедиться в его профиле) темах, хорошо подумать, будет ли кому-нибудь, кроме Вас cамих, это интересно.



Ваше мнение о модераторах: user posted imageBarazuk, user posted imageOpenGL, user posted imageMikle
Модераторы: OpenGL, Mikle
  
> Правильная трансформация нормалей.
    Есть модель, состоящая из вертексов, и есть матрица преобразования этой модели. Необходимо преобразовать и зашить обратно в модель позиции и нормали.
    Задачу можно упростить:
    Предположим, что трансформация, задаваемая матрицей - это комбинация поворотов, скейлов и переносов, без перспективных искажений, то есть m14, m24 и m34 равны нулю.

    D3DXVec3TransformNormal не подходит, если матрица включает не только переносы и повороты, но и скейл. Нормализация нормалей после D3DXVec3TransformNormal - тоже не панацея, даже в результате чистого скейла нормали меняют направление (и должны менять, но не так, как меняют тут).
    Переносы от других преобразований отделяются легко, это m41, m42 и m43.
    Фактически D3DXVec3TransformNormal, умножая вектор на матрицу 3*3 (входящую в состав матрицы 4*4), уже игнорирует переносы, но эта матрица 3*3 содержит повороты и скейлы в смешанном виде, элементы m11, m22 и m33 зависят и от скейлов, и от поворотов.

    Я решил эту задачу, отказавшись от D3DXVec3TransformNormal:
    ExpandedWrap disabled
      Public Sub Transform(Norm As D3DVECTOR, M As D3DMATRIX)
        Dim V0 As D3DVECTOR
        Dim V1 As D3DVECTOR
        Dim V2 As D3DVECTOR
       
        V1 = Vec3(Rnd, Rnd, Rnd)
        D3DXVec3Cross V1, V1, Norm
        D3DXVec3Cross V2, V1, Norm
        D3DXVec3TransformCoord V0, Vec3(0, 0, 0), M
        D3DXVec3TransformCoord V1, V1, M
        D3DXVec3TransformCoord V2, V2, M
        D3DXVec3Subtract V1, V1, V0
        D3DXVec3Subtract V2, V2, V0
        D3DXVec3Cross Norm, V2, V1
        D3DXVec3Normalize Norm, Norm
      End Sub


    Длинновато, но работает правильно, единственное - есть опасность, что случайный вектор Vec3(Rnd, Rnd, Rnd) окажется сонаправленным с исходным. Вероятность мала, но есть.
    Как проще (без if-оф) получить случайный вектор, гарантированно не сонаправленный данному? Направленный в противоположную стороны тоже считается сонаправленным.
    Может есть вариант по-проще?
      Есть такой подход для генерации перпендикулярного вектора в 3D:

      Выбрать максимальный по амплитуде компонент из (dx, dy, dz). Пусть это будет dy. Записать на его место следующий в циклическом порядке, а сам компонент - на следующее место, изменив знак. Третий компонент обнулить.

      Т.е. результат будет (0, dz, -dy)
        Цитата MBo @
        Есть такой подход для генерации перпендикулярного вектора в 3D

        Длинно, два if-а, потом ещё определять понятие "следующий", что тоже без if-ов трудно представить.
        Я заменил:
        ExpandedWrap disabled
          V1 = Vec3(Rnd, Rnd, Rnd)

        на:
        ExpandedWrap disabled
          If Abs(Norm.x) < Abs(Norm.y) Then
            V1 = Vec3(1, 0, 0)
          Else
            V1 = Vec3(0, 1, 0)
          End If

        Наверное, это самый простой вариант.
        Но остаётся в силе вопрос - в целом я задачу решил оптимально, или можно проще?
        Сообщение отредактировано: Mikle -
          Цитата
          Нормали трансформируют транспонированной инверсной матрицей.

          Всего-то нужно было сделать так:
          ExpandedWrap disabled
            Public Sub Transform(Norm As D3DVECTOR, M As D3DMATRIX)
              Dim M1 As D3DMATRIX
             
              D3DXMatrixInverse M1, M
              D3DXMatrixTranspose M1, M1
              D3DXVec3TransformNormal Norm, Norm, M
              D3DXVec3Normalize Norm, Norm
            End Sub
          Сообщение отредактировано: Mikle -
            Цитата MBo @
            Есть такой подход для генерации перпендикулярного вектора в 3D:
            Что-то не то. Вектор получается не нормальный к поверхности.
            Цитата Mikle @
            Всего-то нужно было сделать так:
            Похоже не так просто подсказку найти оказалось (4 часа прошло) Вообще-то матрица преобразования нормалей получается умножением почти тех же матриц, как и матрица преобразования координат, но выбрасываются сдвиги, и вместо масштабных используются их обратные (что насчёт перспективного преобразования, не помню).
            Так что на всякий случай проверь, всегда ли правильная нормаль получается.
              >Что-то не то. Вектор получается не нормальный к поверхности.
              Это вектор, перпендикулярный данному
                Цитата amk @
                Вообще-то матрица преобразования нормалей получается умножением почти тех же матриц, как и матрица преобразования координат, но выбрасываются сдвиги, и вместо масштабных используются их обратные (что насчёт перспективного преобразования, не помню)

                Но для этого нужно иметь эти исходные трансформации по отдельности.
                Цитата amk @
                Похоже не так просто подсказку найти оказалось (4 часа прошло)

                Я не привык долго искать. То, что нашёл по первым трём ссылкам, касалось преобразования параметров источника света вместо нормалей модели, это всё правильно, но этим я пользовался и раньше, а сейчас не тот случай.
                Поэтому я по привычке сел и написал свой велосипед, и он таки оказался правильным, но не оптимальным.
                Цитата amk @
                Так что на всякий случай проверь, всегда ли правильная нормаль получается.

                В моём первом решении - всегда. В последнем результаты для всех видов трансформаций не проверял, но это общепринятый метод, который я в своё время просто умудрился пропустить.
                Сообщение отредактировано: Mikle -
                  Хм.. а как быть, если матрица содержит и перспективные искажения?
                  И преобразования транспонированной инверсной матрицей, и мой вариант дают одинаковый неверный результат.
                    С перспективными искажениями всё очень плохо. Лично я даже не знаю, куда там должны быть правильные нормали направлены (если те, что для расчёта освещения).
                      Цитата amk @
                      Лично я даже не знаю, куда там должны быть правильные нормали направлены (если те, что для расчёта освещения).

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

                      Добавлено
                      Готово!
                      Это уже не аффинное преобразование, трансформировать нормаль в отрыве от позиции было нельзя, вот так работает:
                      ExpandedWrap disabled
                        Public Sub TransformPosNorm(Pos As D3DVECTOR, Norm As D3DVECTOR, M As D3DMATRIX)
                          Dim V1 As D3DVECTOR
                          Dim V2 As D3DVECTOR
                         
                          If Abs(Norm.x) < Abs(Norm.y) Then
                            V1 = Vec3(1, 0, 0)
                          Else
                            V1 = Vec3(0, 1, 0)
                          End If
                          D3DXVec3Cross V1, V1, Norm
                          D3DXVec3Cross V2, V1, Norm
                          D3DXVec3Add V1, V1, Pos
                          D3DXVec3Add V2, V2, Pos
                          D3DXVec3TransformCoord Pos, Pos, M
                          D3DXVec3TransformCoord V1, V1, M
                          D3DXVec3TransformCoord V2, V2, M
                          D3DXVec3Subtract V1, V1, Pos
                          D3DXVec3Subtract V2, V2, Pos
                          D3DXVec3Cross Norm, V2, V1
                          D3DXVec3Normalize Norm, Norm
                        End Sub
                      0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                      0 пользователей:


                      Рейтинг@Mail.ru
                      [ Script execution time: 0,0359 ]   [ 18 queries used ]   [ Generated: 29.03.24, 06:06 GMT ]