Created
August 26, 2014 07:18
-
-
Save XProger/42e12d4782405b79cf9e to your computer and use it in GitHub Desktop.
Simple float4x4 matrix operations
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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