Войти
ПрограммированиеФорумОбщее

Инверсия матрицы 4x4 (комментарии) (2 стр)

Страницы: 1 2 3 4 5 6 Следующая »
#15
21:48, 25 янв. 2020

eDmk
> Я по книжке делал:
И в данном случае Inverse избыточен

#16
21:50, 25 янв. 2020
procedure LookAtMatrix(Eye, Target, Up: TVertex; var RM: TMatrix4);
var
  OM, TM: TMatrix4;

begin
  // Положение и ориентация
  Translation(Eye, -TM);
  Orientation(Eye, Target, Up, OM);
  Transpose(OM);

  // Умножаем и инвертируем
  MulMatrixC(TM, OM, RM);
end;
Вот тебе тоже самое но без Inverse
#17
21:56, 25 янв. 2020

eDmk
> Более универсальное решение.
Ну так тебе две страницы и говорят что универсальное решение здесь не нужно.
Если забыть про преобразование MVP - инверсия в геймдеве нужна крайне редко.

#18
(Правка: 22:00) 21:58, 25 янв. 2020

MrShoor
Да, действительно без инверсии работает :) Только вот так:

procedure LookAtMatrix(Eye, Target, Up: TVertex; var RM: TMatrix4);
var
  OM, TM: TMatrix4;

begin
  // Положение и ориентация
  Translation(-Eye, TM);
  Orientation(Eye, Target, Up, OM);
  Transpose(OM);

  // Умножаем
  MulMatrixC(TM, OM, RM);
end;
#19
21:59, 25 янв. 2020

@!!ex
> инверсия в геймдеве нужна крайне редко
Согласен, но на всякий случай лучше иметь рабочий код.

#20
22:00, 25 янв. 2020

@!!ex
> Если забыть про преобразование MVP - инверсия в геймдеве нужна крайне редко.
Я бы не сказал, что инверсия нужна крайне редко. Мне лично она нужна часто, но нужна она часто в коде, а не в рендере на каждый кадр. Например делаешь ты что-то в редакторе с моделью, и нужно это сделать в пространстве модели, а не мира. И оп, обратная матрица. Или берешь два объекта, и говоришь, что один из них будет чайлдом другого, и оп, опять нужна обратная матрица.

#21
(Правка: 22:01) 22:01, 25 янв. 2020

eDmk
> Только вот так:
Да, я минус зачем-то перед матрицей впихнул, когда хотел перед Eye.

#22
(Правка: 23:01) 23:01, 25 янв. 2020

А если для D3DXVec3Unproject(внутри эта функция считает инверсию матрицы) ?
Или тоже избыточно ?

#23
23:14, 25 янв. 2020

ronniko
> А если для D3DXVec3Unproject(внутри эта функция считает инверсию матрицы) ?
> Или тоже избыточно ?
Для конкретной проекционной матрицы обратную получить еще проще, т.к. проекционная матрица - это как правило только скейл + оффсет по Z. Но т.к. проекционные матрицы бывают разные - то проще не заморачиватья и считать через Inverse

#24
(Правка: 0:21) 0:04, 26 янв. 2020

ronniko
> внутри эта функция считает инверсию матрицы
Это же обычная пропорция. Зачем тут инверсия?

function TCamera.UnProject(X, Y: Integer): TVertex;
var
  fX, fY, K: Single;
  R: TVertex absolute Result;

begin
  // Нормализованные координаты экрана
  fX := (X / FHalf.X) + FR.l;
  fY := (Y / FHalf.Y) - FR.t;

  // Глубина
  if (FTarget.ZBufferType = ZT_SINGLE) then
    R.Z := FTarget.ZDepth32(X, Y) else
    R.Z := FTarget.ZDepth64(X, Y);

  // Коэффициент положения плоскости ZFar по глубине
  K := (R.Z / FR.f);

  // Позиция в координатах фрустума
  R.X := fX * (FV.FarSize.X * K) / FR.w;
  R.Y := fY * (FV.FarSize.Y * K) / FR.h;
  R.W := 1.0;
end;

Мой вариант переводит из ScreenSpace во ViewSpace. Не факт, что подойдет для DX.
Начертите фрустум и найдите нужные пропорции и коэффициенты. Будет вам счастье.
Мы пропорции в 4-м классе проходили :)

#25
8:11, 26 янв. 2020

MrShoor
То что ты привел - это же тоже MV матрица.
Я про то, что универсальное решение очень редко нужно. 99% задач - это преобразование модельно видовой матрицы.

#26
9:18, 26 янв. 2020

eDmk
> Pascal-версия — 1 167 024 вызовов в секунду (~2570 тактов).
То есть больше млн полноценных инверсий полностью произвольных матриц? Много что-то, надо будет проверить.

#27
(Правка: 10:58) 10:58, 26 янв. 2020

Mikle
Да не. На самом деле достаточно медленно. Умножение, например, 176 млн в секунду на невыровненных данных и 200 млн на выровненных. 800 тактов инверсия и 15 тактов умножение — получается дикая разница (в ~55 раз быстрее).

Хотя если инверсию раз на кадр вычислять, то для большинства задач вполне хватает даже такой версии. У меня SIMD-версия быстрее — 3,7 млн в секунду. Правда сравнить пока не с чем. На просторах интернета жуткий код бродит.

#28
(Правка: 13:35) 13:33, 26 янв. 2020

Можно сделать операцию обратного модельного умножения. Это будет короче чем вычислять обратную матрицу и потом умножать.

#29
(Правка: 13:52) 13:43, 26 янв. 2020

eDmk
> Хотя если инверсию раз на кадр вычислять, то для большинства задач вполне
> хватает даже такой версии. У меня SIMD-версия быстрее — 3,7 млн в секунду.
> Правда сравнить пока не с чем. На просторах интернета жуткий код бродит.
Да хоть вот, вариант простой как топор.

inline FMat inverse(FMat const& m)
{
    float mc[12];
    float rc[12];
    m.disassemble(mc);
    /*
        mc[0], mc[1],  mc[2],  mc[3],
        mc[4], mc[5],  mc[6],  mc[7],
        mc[8], mc[9], mc[10], mc[11],
    */
    float det =
        mc[0] * mc[5] * mc[10]
        + mc[1] * mc[6] * mc[8]
        + mc[2] * mc[4] * mc[9]
        - mc[0] * mc[6] * mc[9]
        - mc[1] * mc[4] * mc[10]
        - mc[2] * mc[5] * mc[8];
    if (fabsf(det) < 1e-9) {
        return FMat{};
    }
    float invdet = 1.0f / det;
    rc[0] = invdet * (mc[5] * mc[10] - mc[6] * mc[9]);
    rc[1] = invdet * (mc[2] * mc[9] - mc[1] * mc[10]);
    rc[2] = invdet * (mc[1] * mc[6] - mc[2] * mc[5]);
    rc[3] = invdet * (
        mc[1] * mc[7] * mc[10] + mc[2] * mc[5] * mc[11] + mc[3] * mc[6] * mc[9]
        - mc[1] * mc[6] * mc[11] - mc[2] * mc[7] * mc[9] - mc[3] * mc[5] * mc[10]);
    rc[4] = invdet * (mc[6] * mc[8] - mc[4] * mc[10]);
    rc[5] = invdet * (mc[0] * mc[10] - mc[2] * mc[8]);
    rc[6] = invdet * (mc[2] * mc[4] - mc[0] * mc[6]);
    rc[7] = invdet * (
        mc[0] * mc[6] * mc[11] + mc[2] * mc[7] * mc[8] + mc[3] * mc[4] * mc[10]
        - mc[0] * mc[7] * mc[10] - mc[2] * mc[4] * mc[11] - mc[3] * mc[6] * mc[8]);
    rc[8] = invdet * (mc[4] * mc[9] - mc[5] * mc[8]);
    rc[9] = invdet * (mc[1] * mc[8] - mc[0] * mc[9]);
    rc[10] = invdet * (mc[0] * mc[5] - mc[1] * mc[4]);
    rc[11] = invdet * (
        mc[0] * mc[7] * mc[9] + mc[1] * mc[4] * mc[11] + mc[3] * mc[5] * mc[8]
        - mc[0] * mc[5] * mc[11] - mc[1] * mc[7] * mc[8] - mc[3] * mc[4] * mc[9]);
    return FMat::assemble(rc);
}
Вычисляется исключительно при инициализации, поэтому на оптимизацию вообще забил. Зато работает на произвольных аффинных матрицах.
У меня рейтрейсер, который в виде матриц хранит положение треугольников сцены, а через обратные матрицы считает барицентрические координаты пересечения с лучом. Поскольку треугольники стационарны, то и матрицы рассчитываются единожды при загрузке геометрии и затем тупо умножаются на координаты лучей.
С численной стабильностью тоже не церемонимся - сразу после обращения, вычисляется mwt * inverse(mwt), и, если получившая матрица слишком далеко отходит от единичной, весь треугольник считается вырожденным и тупо выкидывается.
Страницы: 1 2 3 4 5 6 Следующая »
ПрограммированиеФорумОбщее