Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.118.126.11] |
|
Сообщ.
#1
,
|
|
|
Есть модель, состоящая из вертексов, и есть матрица преобразования этой модели. Необходимо преобразовать и зашить обратно в модель позиции и нормали.
Задачу можно упростить: Предположим, что трансформация, задаваемая матрицей - это комбинация поворотов, скейлов и переносов, без перспективных искажений, то есть m14, m24 и m34 равны нулю. D3DXVec3TransformNormal не подходит, если матрица включает не только переносы и повороты, но и скейл. Нормализация нормалей после D3DXVec3TransformNormal - тоже не панацея, даже в результате чистого скейла нормали меняют направление (и должны менять, но не так, как меняют тут). Переносы от других преобразований отделяются легко, это m41, m42 и m43. Фактически D3DXVec3TransformNormal, умножая вектор на матрицу 3*3 (входящую в состав матрицы 4*4), уже игнорирует переносы, но эта матрица 3*3 содержит повороты и скейлы в смешанном виде, элементы m11, m22 и m33 зависят и от скейлов, и от поворотов. Я решил эту задачу, отказавшись от D3DXVec3TransformNormal: 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-оф) получить случайный вектор, гарантированно не сонаправленный данному? Направленный в противоположную стороны тоже считается сонаправленным. Может есть вариант по-проще? |
Сообщ.
#2
,
|
|
|
Есть такой подход для генерации перпендикулярного вектора в 3D:
Выбрать максимальный по амплитуде компонент из (dx, dy, dz). Пусть это будет dy. Записать на его место следующий в циклическом порядке, а сам компонент - на следующее место, изменив знак. Третий компонент обнулить. Т.е. результат будет (0, dz, -dy) |
Сообщ.
#3
,
|
|
|
Цитата MBo @ Есть такой подход для генерации перпендикулярного вектора в 3D Длинно, два if-а, потом ещё определять понятие "следующий", что тоже без if-ов трудно представить. Я заменил: V1 = Vec3(Rnd, Rnd, Rnd) на: If Abs(Norm.x) < Abs(Norm.y) Then V1 = Vec3(1, 0, 0) Else V1 = Vec3(0, 1, 0) End If Наверное, это самый простой вариант. Но остаётся в силе вопрос - в целом я задачу решил оптимально, или можно проще? |
Сообщ.
#4
,
|
|
|
Цитата Нормали трансформируют транспонированной инверсной матрицей. Всего-то нужно было сделать так: 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 |
Сообщ.
#5
,
|
|
|
Цитата MBo @ Что-то не то. Вектор получается не нормальный к поверхности.Есть такой подход для генерации перпендикулярного вектора в 3D: Цитата Mikle @ Похоже не так просто подсказку найти оказалось (4 часа прошло) Вообще-то матрица преобразования нормалей получается умножением почти тех же матриц, как и матрица преобразования координат, но выбрасываются сдвиги, и вместо масштабных используются их обратные (что насчёт перспективного преобразования, не помню).Всего-то нужно было сделать так: Так что на всякий случай проверь, всегда ли правильная нормаль получается. |
Сообщ.
#6
,
|
|
|
>Что-то не то. Вектор получается не нормальный к поверхности.
Это вектор, перпендикулярный данному |
Сообщ.
#7
,
|
|
|
Цитата amk @ Вообще-то матрица преобразования нормалей получается умножением почти тех же матриц, как и матрица преобразования координат, но выбрасываются сдвиги, и вместо масштабных используются их обратные (что насчёт перспективного преобразования, не помню) Но для этого нужно иметь эти исходные трансформации по отдельности. Цитата amk @ Похоже не так просто подсказку найти оказалось (4 часа прошло) Я не привык долго искать. То, что нашёл по первым трём ссылкам, касалось преобразования параметров источника света вместо нормалей модели, это всё правильно, но этим я пользовался и раньше, а сейчас не тот случай. Поэтому я по привычке сел и написал свой велосипед, и он таки оказался правильным, но не оптимальным. Цитата amk @ Так что на всякий случай проверь, всегда ли правильная нормаль получается. В моём первом решении - всегда. В последнем результаты для всех видов трансформаций не проверял, но это общепринятый метод, который я в своё время просто умудрился пропустить. |
Сообщ.
#8
,
|
|
|
Хм.. а как быть, если матрица содержит и перспективные искажения?
И преобразования транспонированной инверсной матрицей, и мой вариант дают одинаковый неверный результат. |
Сообщ.
#9
,
|
|
|
С перспективными искажениями всё очень плохо. Лично я даже не знаю, куда там должны быть правильные нормали направлены (если те, что для расчёта освещения).
|
Сообщ.
#10
,
|
|
|
Цитата amk @ Лично я даже не знаю, куда там должны быть правильные нормали направлены (если те, что для расчёта освещения). Тут, в общем, понятно. Любая нормаль подразумевает плоскость, к которой она и является нормалью. Ищем эту плоскость, трансформируем её нашей матрицей (в данном случае не аффинной), а к полученной плоскости снова ищем нормаль - это и есть искомая величина. Мой метод так и сделан, и я уже догадываюсь, почему он не работает, попробую исправить. Добавлено Готово! Это уже не аффинное преобразование, трансформировать нормаль в отрыве от позиции было нельзя, вот так работает: 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 |