Skip to content

Instantly share code, notes, and snippets.

@XProger
Created August 26, 2014 07:18
Show Gist options
  • Select an option

  • Save XProger/42e12d4782405b79cf9e to your computer and use it in GitHub Desktop.

Select an option

Save XProger/42e12d4782405b79cf9e to your computer and use it in GitHub Desktop.
Simple float4x4 matrix operations
TMat4f = {$IFDEF FPC} object {$ELSE} record {$ENDIF}
private
function GetPos: TVec3f; // https://gist.github.com/XProger/da9a74ae8b37905b421a
procedure SetPos(const v: TVec3f);
function GetRot: TQuat; // https://gist.github.com/XProger/def254d40a237cc0f0b2
procedure SetRot(const q: TQuat);
public
e00, e10, e20, e30,
e01, e11, e21, e31,
e02, e12, e22, e32,
e03, e13, e23, e33: Single;
{$IFNDEF FPC}
class operator Add(const a, b: TMat4f): TMat4f;
class operator Multiply(const a, b: TMat4f): TMat4f;
class operator Multiply(const m: TMat4f; const v: TVec3f): TVec3f;
class operator Multiply(const m: TMat4f; const v: TVec4f): TVec4f;
class operator Multiply(const m: TMat4f; x: Single): TMat4f;
{$ENDIF}
procedure Identity;
function Det: Single;
function Inverse: TMat4f;
function Transpose: TMat4f;
procedure Translate(const v: TVec3f);
procedure Rotate(Angle: Single; const Axis: TVec3f);
procedure Scale(const v: TVec3f);
procedure LookAt(const Pos, Target, Up: TVec3f);
procedure Ortho(Left, Right, Bottom, Top, ZNear, ZFar: Single);
procedure Frustum(Left, Right, Bottom, Top, ZNear, ZFar: Single);
procedure Perspective(FOV, Aspect, ZNear, ZFar: Single);
property Pos: TVec3f read GetPos write SetPos;
property Rot: TQuat read GetRot write SetRot;
end;
{$IFDEF FPC}
operator + (const a, b: TMat4f): TMat4f;
operator * (const a, b: TMat4f): TMat4f;
operator * (const m: TMat4f; const v: TVec3f): TVec3f;
operator * (const m: TMat4f; const v: TVec4f): TVec4f;
operator * (const m: TMat4f; x: Single): TMat4f;
{$ENDIF}
function TMat4f.GetPos: TVec3f;
begin
Result.x := e03;
Result.y := e13;
Result.z := e23;
end;
procedure TMat4f.SetPos(const v: TVec3f);
begin
e03 := v.x;
e13 := v.y;
e23 := v.z;
end;
function TMat4f.GetRot: TQuat;
var
t, s : Single;
begin
t := e00 + e11 + e22 + 1;
with Result do
if t > EPS then
begin
s := 0.5 / sqrt(t);
w := 0.25 / s;
x := (e21 - e12) * s;
y := (e02 - e20) * s;
z := (e10 - e01) * s;
end else
if (e00 > e11) and (e00 > e22) then
begin
s := 2 * sqrt(1 + e00 - e11 - e22);
w := (e21 - e12) / s;
x := 0.25 * s;
y := (e01 + e10) / s;
z := (e02 + e20) / s;
end else
if e11 > e22 then
begin
s := 2 * sqrt(1 + e11 - e00 - e22);
w := (e02 - e20) / s;
x := (e01 + e10) / s;
y := 0.25 * s;
z := (e12 + e21) / s;
end else
begin
s := 2 * sqrt(1 + e22 - e00 - e11);
w := (e10 - e01) / s;
x := (e02 + e20) / s;
y := (e12 + e21) / s;
z := 0.25 * s;
end;
end;
procedure TMat4f.SetRot(const q: TQuat);
var
sqw, sqx, sqy, sqz, invs : Single;
tmp1, tmp2 : Single;
begin
with q do
begin
sqw := w * w;
sqx := x * x;
sqy := y * y;
sqz := z * z;
invs := 1 / (sqx + sqy + sqz + sqw);
e00 := ( sqx - sqy - sqz + sqw) * invs;
e11 := (-sqx + sqy - sqz + sqw) * invs;
e22 := (-sqx - sqy + sqz + sqw) * invs;
tmp1 := x * y;
tmp2 := z * w;
e10 := 2 * (tmp1 + tmp2) * invs;
e01 := 2 * (tmp1 - tmp2) * invs;
tmp1 := x * z;
tmp2 := y * w;
e20 := 2 * (tmp1 - tmp2) * invs;
e02 := 2 * (tmp1 + tmp2) * invs;
tmp1 := y * z;
tmp2 := x * w;
e21 := 2 * (tmp1 + tmp2) * invs;
e12 := 2 * (tmp1 - tmp2) * invs;
end;
end;
{$IFDEF FPC}operator + {$ELSE}class operator TMat4f.Add{$ENDIF}
(const a, b: TMat4f): TMat4f;
begin
with Result do
begin
e00 := a.e00 + b.e00; e10 := a.e10 + b.e10; e20 := a.e20 + b.e20; e30 := a.e30 + b.e30;
e01 := a.e01 + b.e01; e11 := a.e11 + b.e11; e21 := a.e21 + b.e21; e31 := a.e31 + b.e31;
e02 := a.e02 + b.e02; e12 := a.e12 + b.e12; e22 := a.e22 + b.e22; e32 := a.e32 + b.e32;
e03 := a.e03 + b.e03; e13 := a.e13 + b.e13; e23 := a.e23 + b.e23; e33 := a.e33 + b.e33;
end;
end;
{$IFDEF FPC}operator * {$ELSE}class operator TMat4f.Multiply{$ENDIF}
(const a, b: TMat4f): TMat4f;
begin
with Result do
begin
e00 := a.e00 * b.e00 + a.e01 * b.e10 + a.e02 * b.e20 + a.e03 * b.e30;
e10 := a.e10 * b.e00 + a.e11 * b.e10 + a.e12 * b.e20 + a.e13 * b.e30;
e20 := a.e20 * b.e00 + a.e21 * b.e10 + a.e22 * b.e20 + a.e23 * b.e30;
e30 := a.e30 * b.e00 + a.e31 * b.e10 + a.e32 * b.e20 + a.e33 * b.e30;
e01 := a.e00 * b.e01 + a.e01 * b.e11 + a.e02 * b.e21 + a.e03 * b.e31;
e11 := a.e10 * b.e01 + a.e11 * b.e11 + a.e12 * b.e21 + a.e13 * b.e31;
e21 := a.e20 * b.e01 + a.e21 * b.e11 + a.e22 * b.e21 + a.e23 * b.e31;
e31 := a.e30 * b.e01 + a.e31 * b.e11 + a.e32 * b.e21 + a.e33 * b.e31;
e02 := a.e00 * b.e02 + a.e01 * b.e12 + a.e02 * b.e22 + a.e03 * b.e32;
e12 := a.e10 * b.e02 + a.e11 * b.e12 + a.e12 * b.e22 + a.e13 * b.e32;
e22 := a.e20 * b.e02 + a.e21 * b.e12 + a.e22 * b.e22 + a.e23 * b.e32;
e32 := a.e30 * b.e02 + a.e31 * b.e12 + a.e32 * b.e22 + a.e33 * b.e32;
e03 := a.e00 * b.e03 + a.e01 * b.e13 + a.e02 * b.e23 + a.e03 * b.e33;
e13 := a.e10 * b.e03 + a.e11 * b.e13 + a.e12 * b.e23 + a.e13 * b.e33;
e23 := a.e20 * b.e03 + a.e21 * b.e13 + a.e22 * b.e23 + a.e23 * b.e33;
e33 := a.e30 * b.e03 + a.e31 * b.e13 + a.e32 * b.e23 + a.e33 * b.e33;
end;
end;
{$IFDEF FPC}operator * {$ELSE}class operator TMat4f.Multiply{$ENDIF}
(const m: TMat4f; const v: TVec3f): TVec3f;
begin
with m do
begin
Result.x := e00 * v.x + e01 * v.y + e02 * v.z + e03;
Result.y := e10 * v.x + e11 * v.y + e12 * v.z + e13;
Result.z := e20 * v.x + e21 * v.y + e22 * v.z + e23;
end;
end;
{$IFDEF FPC}operator * {$ELSE}class operator TMat4f.Multiply{$ENDIF}
(const m: TMat4f; const v: TVec4f): TVec4f;
begin
with m do
begin
Result.x := e00 * v.x + e01 * v.y + e02 * v.z + e03 * v.w;
Result.y := e10 * v.x + e11 * v.y + e12 * v.z + e13 * v.w;
Result.z := e20 * v.x + e21 * v.y + e22 * v.z + e23 * v.w;
Result.w := e30 * v.x + e31 * v.y + e32 * v.z + e33 * v.w;
end;
end;
{$IFDEF FPC}operator * {$ELSE}class operator TMat4f.Multiply{$ENDIF}
(const m: TMat4f; x: Single): TMat4f;
begin
with Result do
begin
e00 := m.e00 * x; e10 := m.e10 * x; e20 := m.e20 * x; e30 := m.e30 * x;
e01 := m.e01 * x; e11 := m.e11 * x; e21 := m.e21 * x; e31 := m.e31 * x;
e02 := m.e02 * x; e12 := m.e12 * x; e22 := m.e22 * x; e32 := m.e32 * x;
e03 := m.e03 * x; e13 := m.e13 * x; e23 := m.e23 * x; e33 := m.e33 * x;
end;
end;
procedure TMat4f.Identity;
const
IdentMat : TMat4f = (
e00: 1; e10: 0; e20: 0; e30: 0;
e01: 0; e11: 1; e21: 0; e31: 0;
e02: 0; e12: 0; e22: 1; e32: 0;
e03: 0; e13: 0; e23: 0; e33: 1;
);
begin
Self := IdentMat;
end;
function TMat4f.Det: Single;
begin
Result := e00 * (e11 * (e22 * e33 - e32 * e23) - e21 * (e12 * e33 - e32 * e13) + e31 * (e12 * e23 - e22 * e13)) -
e10 * (e01 * (e22 * e33 - e32 * e23) - e21 * (e02 * e33 - e32 * e03) + e31 * (e02 * e23 - e22 * e03)) +
e20 * (e01 * (e12 * e33 - e32 * e13) - e11 * (e02 * e33 - e32 * e03) + e31 * (e02 * e13 - e12 * e03)) -
e30 * (e01 * (e12 * e23 - e22 * e13) - e11 * (e02 * e23 - e22 * e03) + e21 * (e02 * e13 - e12 * e03));
end;
function TMat4f.Inverse: TMat4f;
var
D : Single;
begin
D := 1 / Det;
Result.e00 := (e11 * (e22 * e33 - e32 * e23) - e21 * (e12 * e33 - e32 * e13) + e31 * (e12 * e23 - e22 * e13)) * D;
Result.e01 := -(e01 * (e22 * e33 - e32 * e23) - e21 * (e02 * e33 - e32 * e03) + e31 * (e02 * e23 - e22 * e03)) * D;
Result.e02 := (e01 * (e12 * e33 - e32 * e13) - e11 * (e02 * e33 - e32 * e03) + e31 * (e02 * e13 - e12 * e03)) * D;
Result.e03 := -(e01 * (e12 * e23 - e22 * e13) - e11 * (e02 * e23 - e22 * e03) + e21 * (e02 * e13 - e12 * e03)) * D;
Result.e10 := -(e10 * (e22 * e33 - e32 * e23) - e20 * (e12 * e33 - e32 * e13) + e30 * (e12 * e23 - e22 * e13)) * D;
Result.e11 := (e00 * (e22 * e33 - e32 * e23) - e20 * (e02 * e33 - e32 * e03) + e30 * (e02 * e23 - e22 * e03)) * D;
Result.e12 := -(e00 * (e12 * e33 - e32 * e13) - e10 * (e02 * e33 - e32 * e03) + e30 * (e02 * e13 - e12 * e03)) * D;
Result.e13 := (e00 * (e12 * e23 - e22 * e13) - e10 * (e02 * e23 - e22 * e03) + e20 * (e02 * e13 - e12 * e03)) * D;
Result.e20 := (e10 * (e21 * e33 - e31 * e23) - e20 * (e11 * e33 - e31 * e13) + e30 * (e11 * e23 - e21 * e13)) * D;
Result.e21 := -(e00 * (e21 * e33 - e31 * e23) - e20 * (e01 * e33 - e31 * e03) + e30 * (e01 * e23 - e21 * e03)) * D;
Result.e22 := (e00 * (e11 * e33 - e31 * e13) - e10 * (e01 * e33 - e31 * e03) + e30 * (e01 * e13 - e11 * e03)) * D;
Result.e23 := -(e00 * (e11 * e23 - e21 * e13) - e10 * (e01 * e23 - e21 * e03) + e20 * (e01 * e13 - e11 * e03)) * D;
Result.e30 := -(e10 * (e21 * e32 - e31 * e22) - e20 * (e11 * e32 - e31 * e12) + e30 * (e11 * e22 - e21 * e12)) * D;
Result.e31 := (e00 * (e21 * e32 - e31 * e22) - e20 * (e01 * e32 - e31 * e02) + e30 * (e01 * e22 - e21 * e02)) * D;
Result.e32 := -(e00 * (e11 * e32 - e31 * e12) - e10 * (e01 * e32 - e31 * e02) + e30 * (e01 * e12 - e11 * e02)) * D;
Result.e33 := (e00 * (e11 * e22 - e21 * e12) - e10 * (e01 * e22 - e21 * e02) + e20 * (e01 * e12 - e11 * e02)) * D;
end;
function TMat4f.Transpose: TMat4f;
begin
Result.e00 := e00; Result.e10 := e01; Result.e20 := e02; Result.e30 := e03;
Result.e01 := e10; Result.e11 := e11; Result.e21 := e12; Result.e31 := e13;
Result.e02 := e20; Result.e12 := e21; Result.e22 := e22; Result.e32 := e23;
Result.e03 := e30; Result.e13 := e31; Result.e23 := e32; Result.e33 := e33;
end;
procedure TMat4f.Translate(const v: TVec3f);
var
m : TMat4f;
begin
m.Identity;
m.Pos := v;
Self := Self * m;
end;
procedure TMat4f.Rotate(Angle: Single; const Axis: TVec3f);
var
m : TMat4f;
begin
m := Mat4f(Angle, Axis);
Self := Self * m;
end;
procedure TMat4f.Scale(const v: TVec3f);
var
m : TMat4f;
begin
m.Identity;
m.e00 := v.x;
m.e11 := v.y;
m.e22 := v.z;
Self := Self * m;
end;
procedure TMat4f.LookAt(const Pos, Target, Up: TVec3f);
var
R, U, D : TVec3f;
begin
D := (Pos - Target);
D := D.Normal;
R := Up.Cross(D);
R := R.Normal;
U := D.Cross(R);
e00 := R.x; e01 := R.y; e02 := R.z; e03 := -Pos.Dot(R);
e10 := U.x; e11 := U.y; e12 := U.z; e13 := -Pos.Dot(U);
e20 := D.x; e21 := D.y; e22 := D.z; e23 := -Pos.Dot(D);
e30 := 0; e31 := 0; e32 := 0; e33 := 1;
end;
procedure TMat4f.Ortho(Left, Right, Bottom, Top, ZNear, ZFar: Single);
begin
e00 := 2 / (Right - Left);
e10 := 0;
e20 := 0;
e30 := 0;
e01 := 0;
e11 := 2 / (Top - Bottom);
e21 := 0;
e31 := 0;
e02 := 0;
e12 := 0;
e22 := -2 / (ZFar - ZNear);
e32 := 0;
e03 := -(Right + Left) / (Right - Left);
e13 := -(Top + Bottom) / (Top - Bottom);
e23 := -(ZFar + ZNear) / (ZFar - ZNear);
e33 := 1;
end;
procedure TMat4f.Frustum(Left, Right, Bottom, Top, ZNear, ZFar: Single);
begin
e00 := 2 * ZNear / (Right - Left);
e10 := 0;
e20 := 0;
e30 := 0;
e01 := 0;
e11 := 2 * ZNear / (Top - Bottom);
e21 := 0;
e31 := 0;
e02 := (Right + Left) / (Right - Left);
e12 := (Top + Bottom) / (Top - Bottom);
e22 := -(ZFar + ZNear) / (ZFar - ZNear);
e32 := -1;
e03 := 0;
e13 := 0;
e23 := -2 * ZFar * ZNear / (ZFar - ZNear);
e33 := 0;
end;
procedure TMat4f.Perspective(FOV, Aspect, ZNear, ZFar: Single);
var
x, y : Single;
begin
y := ZNear * Tan(FOV * 0.5 * deg2rad);
x := y * Aspect;
Frustum(-x, x, -y, y, ZNear, ZFar);
end;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment