eDmk
Ну вот этот код для симд сложнее (по сути моя транспонированная), но наверняка есть аналог, чтобы вычисления были проще и для горизонтальной матрицы. Я потому вертикальную как в ogl и стараюсь использовать, что так меньше кода выходит. А иногда это неважно. Например для умножения транспонированных матриц достаточно их местами поменять в старом алгоритме умножения. Но увы так просто не всегда получается.
Truthfinder
Вот SIMD-вариант
eDmk отличается от твоей LookAtMatrix двумя cross. У тебя один cross.
Matrix44f lookAt(const Vec3f& from, const Vec3f& to, const Vec3f& tmp = Vec3f(0, 1, 0)) { Vec3f forward = normalize(from - to); Vec3f right = crossProduct(tmp, forward); Vec3f up = crossProduct(forward, right); Matrix44f camToWorld; camToWorld[0][0] = right.x; camToWorld[0][1] = right.y; camToWorld[0][2] = right.z; camToWorld[1][0] = up.x; camToWorld[1][1] = up.y; camToWorld[1][2] = up.z; camToWorld[2][0] = forward.x; camToWorld[2][1] = forward.y; camToWorld[2][2] = forward.z; camToWorld[3][0] = from.x; camToWorld[3][1] = from.y; camToWorld[3][2] = from.z; camToWorld[3][3] = 1.0; return camToWorld; }
ronniko
Мне кажется это неправильно.
Truthfinder
И тут тоже неправильно?
https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixlookatlh
nes
> И тут тоже неправильно?
Моё понимание происходящего. Слишком много может быть вариаций для lookat: left/right handed, transposed и так далее. Дабы не быть уже голословным:
static mtx4 lookat1(vec3 const& eye, vec3 const& at, vec3 const& up) { const vec3 z = ~( eye - at), x = ~( up ^ z), y = ~( z ^ x); return { { x.x, x.y, x.z, -( eye|x) }, // left { y.x, y.y, y.z, -( eye|y) }, // up { z.x, z.y, z.z, -( eye|z) }, // forward { 0.f, 0.f, 0.f, 1.f } }; } static mtx4 lookat2( vec3 const& eye, vec3 const& at, vec3 const& up) { // https://www.scratchapixel.com/lessons/mathematics-physics-for-computer-graphics/lookat-function const vec3 fwd = ~( eye - at), side = ~( up ^ fwd), u = fwd ^ side; return { {side.x, side.y, side.z, 0.f }, // right { u.x, u.y, u.z, 0.f }, // up { fwd.x, fwd.y, fwd.z, 0.f }, // forward { eye.x, eye.y, eye.z, 1.f } }; }
lookatRH: https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixlookatrh
lookatLH: https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixlookatlh
lookat2 = transposed(inverted(lookat1))
lookat1 = transposed(inverted(lookat2))
Не знаю как вы, а я ничо не понимаю. И при этом все правы ))
nes
> И тут тоже неправильно?
> https://docs.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixlookatlh
Ну сам посмотри на нижнюю строку, там from.x,y,z
А по ссылке dot.
Уже до lookAt добрались, для полноты картины нужна перспективная матрица:
Public Sub MatrixPerspectiveFovLH(MOut As D3DMATRIX, ByVal Fov As Single, ByVal Aspect As Single, ByVal zNear As Single, ByVal zFar As Single) Dim yScale As Single yScale = Cos(Fov * 0.5) / Sin(Fov * 0.5) MOut.m11 = yScale / Aspect: MOut.m12 = 0: MOut.m13 = 0: MOut.m14 = 0 MOut.m21 = 0: MOut.m22 = yScale: MOut.m23 = 0: MOut.m24 = 0 MOut.m31 = 0: MOut.m32 = 0: MOut.m33 = zFar / (zFar - zNear): MOut.m34 = 1 MOut.m41 = 0: MOut.m42 = 0: MOut.m43 = -zNear * zFar / (zFar - zNear): MOut.m44 = 0 End Sub
Mikle с такой матрицей Project только msdn вариант.
zaxis = normal(At - Eye) xaxis = normal(cross(Up, zaxis)) yaxis = cross(zaxis, xaxis) xaxis.x yaxis.x zaxis.x 0 xaxis.y yaxis.y zaxis.y 0 xaxis.z yaxis.z zaxis.z 0 -dot(xaxis, eye) -dot(yaxis, eye) -dot(zaxis, eye) 1
PS: Устроил подставу подстав ! :)
eDmk
А у тебя векторная библиотека ogl или d3d based?
Truthfinder
Своя солянка :) По книжкам, по учебникам и т.д.
Mikle
> для полноты картины нужна перспективная матрица:
Только для OGL матрица будет немного другая. Для reverse depth техники - опять немного другая.
Поэтому у себя я запилил более универсальное вычисление матрицы:
function CalcPerspectiveMatrix: TMat4; var w, h, Q: Single; DepthSize: Single; begin h := (cos( fFOV/2)/sin( fFOV/2)); w := fAspect * h; Q := 1.0/( NearPlane - FarPlane); DepthSize := DepthRange.y - DepthRange.x; ZeroClear( Result, SizeOf( Result)); Result.f[0, 0] := w; Result.f[1, 1] := h; Result.f[2, 2] := DepthRange.x - DepthSize * FarPlane * Q; Result.f[2, 3] := 1.0; Result.f[3, 2] := DepthSize * NearPlane * FarPlane * Q; end;
Здесь в DepthRange содержатся значения, на которые будут маппиться Near и Far плоскости. После умножения на матрицу Near примет то значение, которое было в DepthRange.x, а Far то, которое было в DepthRange.y.
Таким образом установив:
DepthRange = Vec(-1, 1) получаем матрицу под OGL
DepthRange = Vec(0, 1) получаем матрицу под DX
DepthRange = Vec(1, 0) получаем матрицу под reverse depth технику
MrShoor
> Поэтому у себя я запилил более универсальное вычисление матрицы:
Вроде как каноничная ogl матрица такая:
m[0][0] = ctg(fovy / 2) / aspect; m[1][1] = ctg(fovy / 2); m[2][2] = (N+F)/(N-F); m[2][3] = -1; m[3][2] = 2*N*F/(N-F);
Ну если aspect у тебя обратный ещё понятно (y/x вместо x/y), но m23=-1 в ogl, а у тебя всегда 1.
Truthfinder
> но m23=-1 в ogl, а у тебя всегда 1.
Потому что -1 это для правосторонней системы координат. Правосторонность никак не привязана к GAPI. Поэтому в ОГЛ можно иметь как правостороннюю, так и левостороннюю. То же самое касается и DX. Мой фреймворк заточен под правостороннюю СК, поэтому там строго 1. Но при этом он умеет в разные графические апи и техники, поэтому там DepthRange.
Тема в архиве.