1
0
forked from josh/j3ml
This commit is contained in:
2024-01-12 05:17:01 -05:00
parent dea5735c87
commit 93759ba545
9 changed files with 227 additions and 21 deletions

View File

@@ -4,13 +4,10 @@ PROJECT(J3ML
LANGUAGES CXX
)
if (PROJECT_SOURCE_DIR STREQUAL PROJECT_BINARY_DIR)
message(FATAL_ERROR "In-source builds are not allowed")
endif()
set(CMAKE_CXX_STANDARD 20)
#set(CMAKE_POSITION_INDEPENDENT_CODE ON)
if (WIN32)

View File

@@ -1,3 +1,4 @@
#include <J3ML/LinearAlgebra/Vector2.h>
#include <J3ML/LinearAlgebra/Vector3.h>
#pragma once
@@ -19,19 +20,12 @@ namespace Geometry {
class Triangle2D;
class Polygon2D;
struct IntersectionResult2D {
};
struct IntersectionResult2D {};
bool Intersects2D(LineSegment2D seg, Rectangle rect);
IntersectionResult2D GetIntersection2D(LineSegment2D seg, Rectangle rect);
// A 3D axis-aligned bounding box
// This data structure can be used to represent coarse bounds of objects, in situations where detailed triangle-level
// computations can be avoided. In physics systems, bounding boxes are used as an efficient early-out test for geometry

View File

@@ -13,6 +13,12 @@ namespace LinearAlgebra
float angle;
public:
AxisAngle();
AxisAngle(const Vector3& axis, float angle);
AxisAngle(const Vector3 &axis, float angle);
EulerAngle ToEulerAngleXYZ() const;
Quaternion ToQuaternion() const;
static AxisAngle FromEulerAngleXYZ(const EulerAngle&);
};
}

View File

@@ -11,8 +11,13 @@ public:
EulerAngle();
EulerAngle(float pitch, float yaw, float roll);
EulerAngle(const Vector3& vec) : pitch(vec.x), yaw(vec.y), roll(vec.z) {}
static EulerAngle FromRadians(float radians);
static EulerAngle FromDegrees(float degrees);
AxisAngle ToAxisAngle() const;
explicit EulerAngle(const Quaternion& orientation);
explicit EulerAngle(const AxisAngle& orientation);
/// TODO: Implement separate upper and lower bounds
/// Preserves internal value of euler angles, normalizes and clamps the output.
/// This does not solve gimbal lock!!!

View File

@@ -45,14 +45,36 @@ namespace LinearAlgebra {
Vector3 GetColumn(int index) const;
float At(int x, int y) const;
/// Creates a new M3x3 that rotates about the given axis by the given angle
static Matrix3x3 RotateAxisAngle(const Vector3& rhs);
void SetRotatePart(const Vector3& a, float angle);
static Matrix3x3 RotateFromTo(const Vector3& source, const Vector3& direction);
/// Creates a new M3x3 that rotates about the given axis by the given angle
static Matrix3x3 RotateAxisAngle(const Vector3& axis, float angleRadians);
static Matrix3x3 RotateFromTo(const Vector3& source, const Vector3& direction)
{
}
void SetRow(int i, const Vector3 &vector3);
void SetColumn(int i, const Vector3& vector);
void Orthonormalize(int c0, int c1, int c2)
{
Vector3 v0 = GetColumn(c0);
Vector3 v1 = GetColumn(c1);
Vector3 v2 = GetColumn(c2);
Vector3::Orthonormalize(v0, v1, v2);
SetColumn(c0, v0);
SetColumn(c1, v1);
SetColumn(c2, v2);
}
static Matrix3x3 LookAt(const Vector3& forward, const Vector3& target, const Vector3& localUp, const Vector3& worldUp);
static Matrix3x3 FromQuat(const Quaternion& orientation);
static Matrix3x3 FromQuat(const Quaternion& orientation)
{
return Matrix3x3(orientation);
}
Quaternion ToQuat() const;

View File

@@ -1,8 +1,27 @@
#pragma once
#include <J3ML/LinearAlgebra.h>
#include <J3ML/LinearAlgebra/Quaternion.h>
namespace LinearAlgebra {
template<typename Matrix>
void SetMatrixRotatePart(Matrix &m, const Quaternion& q)
{
// See e.g. http://www.geometrictools.com/Documentation/LinearAlgebraicQuaternions.pdf .
const float x = q.x;
const float y = q.y;
const float z = q.z;
const float w = q.w;
m[0][0] = 1 - 2*(y*y + z*z); m[0][1] = 2*(x*y - z*w); m[0][2] = 2*(x*z + y*w);
m[1][0] = 2*(x*y + z*w); m[1][1] = 1 - 2*(x*x + z*z); m[1][2] = 2*(y*z - x*w);
m[2][0] = 2*(x*z - y*w); m[2][1] = 2*(y*z + x*w); m[2][2] = 1 - 2*(x*x + y*y);
}
/// A 4-by-4 matrix for affine transformations and perspective projections of 3D geometry.
/* This matrix can represent the most generic form of transformations for 3D objects,
* including perspective projections, which a 4-by-3 cannot store,
@@ -21,22 +40,50 @@ namespace LinearAlgebra {
enum { Rows = 4 };
enum { Cols = 4 };
// A constant matrix that has zeroes in all its entries
static const Matrix4x4 Zero;
// A constant matrix that is the identity.
static const Matrix4x4 Identity;
// A compile-time constant float4x4 which has NaN in each element.
// For this constant, each element has the value of quet NaN, or Not-A-Number.
// Never compare a matrix to this value. Due to how IEEE floats work, "nan == nan" returns false!
static const Matrix4x4 NaN;
Matrix4x4() {}
Matrix4x4(float val);
Matrix4x4(const Matrix3x3&);
Matrix4x4(float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23,
float m30, float m31, float m32, float m33);
Matrix4x4(const Vector4& r1, const Vector4& r2, const Vector4& r3, const Vector4& r4);
explicit Matrix4x4(const Quaternion& orientation);
void SetTranslatePart(float translateX, float translateY, float translateZ);
void SetTranslatePart(const Vector3& offset);
void SetRotatePart(const Quaternion& q);
void SetRow(int row, const Vector3& rowVector, float m_r3);
void SetRow(int row, const Vector4& rowVector);
void SetRow(int row, float m_r0, float m_r1, float m_r2, float m_r3);
Matrix4x4(const Quaternion& orientation, const Vector3& translation);
Vector4 GetRow(int index) const;
Vector4 GetColumn(int index) const;
float At(int x, int y) const;
float At(int x, int y) const
{
return elems[x][y];
}
Vector4 Diagonal() const;
Vector4 WorldX() const;
@@ -47,13 +94,20 @@ namespace LinearAlgebra {
// If the determinant is nonzero, this matrix is invertible.
float Determinant() const;
Matrix4x4 Inverse() const;
Matrix4x4 Inverse() const
{
}
Matrix4x4 Transpose() const;
Vector2 Transform(const Vector2& rhs) const;
Vector3 Transform(const Vector3& rhs) const;
Vector4 Transform(const Vector4& rhs) const;
Matrix4x4 D3DOrthoProjLH(float n, float f, float h, float v)
{
}
Vector3 GetTranslationComponent() const;
Matrix3x3 GetRotationComponent() const;

View File

@@ -1,8 +1,17 @@
#include <J3ML/LinearAlgebra/AxisAngle.h>
#include <J3ML/LinearAlgebra/Quaternion.h>
namespace LinearAlgebra {
AxisAngle::AxisAngle() : axis(Vector3::Zero) {}
AxisAngle::AxisAngle(const Vector3 &axis, float angle) : axis(axis), angle(angle) {}
Quaternion AxisAngle::ToQuaternion() const {
return {
axis.x * std::sin(angle/2),
axis.y * std::sin(angle/2),
axis.z * std::sin(angle/2),
std::cos(angle/2)
};
}
}

View File

@@ -196,5 +196,87 @@ namespace LinearAlgebra {
};
}
void Matrix3x3::SetRotatePart(const Vector3 &a, float angle) {
float s = std::sin(angle);
float c = std::cos(angle);
const float c1 = 1.f - c;
elems[0][0] = c+c1*a.x*a.x;
elems[1][0] = c1*a.x*a.y+s*a.z;
elems[2][0] = c1*a.x*a.z-s*a.y;
elems[0][1] = c1*a.x*a.y-s*a.z;
elems[1][1] = c+c1*a.y*a.y;
elems[2][1] = c1*a.y*a.z+s*a.x;
elems[0][2] = c1*a.x*a.z+s*a.y;
elems[1][2] = c1*a.y*a.z-s*a.x;
elems[2][2] = c+c1*a.z*a.z;
}
Matrix3x3 Matrix3x3::RotateAxisAngle(const Vector3 &axis, float angleRadians) {
Matrix3x3 r;
r.SetRotatePart(axis, angleRadians);
return r;
}
void Matrix3x3::SetRow(int i, const Vector3 &vec) {
elems[i][0] = vec.x;
elems[i][1] = vec.y;
elems[i][2] = vec.z;
}
Matrix3x3
Matrix3x3::LookAt(const Vector3 &forward, const Vector3 &target, const Vector3 &localUp, const Vector3 &worldUp) {
// User must input proper normalized input direction vectors
// In the local space, the forward and up directions must be perpendicular to be well-formed.
// In the world space, the target direction and world up cannot be degenerate (co-linear)
// Generate the third basis vector in the local space;
Vector3 localRight = localUp.Cross(forward).Normalize();
// A. Now we have an orthonormal linear basis {localRight, localUp, forward} for the object local space.
// Generate the third basis vector for the world space
Vector3 worldRight = worldUp.Cross(target).Normalize();
// Since the input worldUp vector is not necessarily perpendicular to the target direction vector
// We need to compute the real world space up vector that the "head" of the object will point
// towards when the model is looking towards the desired target direction
Vector3 perpWorldUp = target.Cross(worldRight).Normalize();
// B. Now we have an orthonormal linear basis {worldRight, perpWorldUp, targetDirection } for the desired target orientation.
// We want to build a matrix M that performs the following mapping:
// 1. localRight must be mapped to worldRight. (M * localRight = worldRight)
// 2. localUp must be mapped to perpWorldUp. (M * localUp = perpWorldUp)
// 3. localForward must be mapped to targetDirection. (M * localForward = targetDirection)
// i.e. we want to map the basis A to basis B.
// This matrix M exists, and it is an orthonormal rotation matrix with a determinant of +1, because
// the bases A and B are orthonormal with the same handedness.
// Below, use the notation that (a,b,c) is a 3x3 matrix with a as its first column, b second, and c third.
// By algebraic manipulation, we can rewrite conditions 1, 2 and 3 in a matrix form:
// M * (localRight, localUp, localForward) = (worldRight, perpWorldUp, targetDirection)
// or M = (worldRight, perpWorldUp, targetDirection) * (localRight, localUp, localForward)^{-1}.
// or M = m1 * m2, where
// m1 equals (worldRight, perpWorldUp, target):
Matrix3x3 m1(worldRight, perpWorldUp, target);
// and m2 equals (localRight, localUp, localForward)^{-1}:
Matrix3x3 m2;
m2.SetRow(0, localRight);
m2.SetRow(1, localUp);
m2.SetRow(2, forward);
// Above we used the shortcut that for an orthonormal matrix M, M^{-1} = M^T. So set the rows
// and not the columns to directly produce the transpose, i.e. the inverse of (localRight, localUp, localForward).
// Compute final M.
m2 = m1 * m2;
// And fix any numeric stability issues by re-orthonormalizing the result.
m2.Orthonormalize(0, 1, 2);
return m2;
}
}

View File

@@ -77,4 +77,41 @@ namespace LinearAlgebra {
Matrix4x4::Matrix4x4(const Quaternion &orientation) {
}
void Matrix4x4::SetTranslatePart(float translateX, float translateY, float translateZ) {
elems[0][3] = translateX;
elems[1][3] = translateY;
elems[2][3] = translateZ;
}
void Matrix4x4::SetTranslatePart(const Vector3 &offset) {
elems[0][3] = offset.x;
elems[1][3] = offset.y;
elems[2][3] = offset.z;
}
void Matrix4x4::SetRotatePart(const Quaternion &q) {
SetMatrixRotatePart(*this, q);
}
void Matrix4x4::SetRow(int row, const Vector3 &rowVector, float m_r3) {
SetRow(row, rowVector.x, rowVector.y, rowVector.z, m_r3);
}
void Matrix4x4::SetRow(int row, const Vector4 &rowVector) {
SetRow(row, rowVector.x, rowVector.y, rowVector.z, rowVector.w);
}
void Matrix4x4::SetRow(int row, float m_r0, float m_r1, float m_r2, float m_r3) {
elems[row][0] = m_r0;
elems[row][1] = m_r1;
elems[row][2] = m_r2;
elems[row][3] = m_r3;
}
Matrix4x4::Matrix4x4(const Quaternion &orientation, const Vector3 &translation) {
SetRotatePart(orientation);
SetTranslatePart(translation);
SetRow(3, 0, 0, 0, 1);
}
}