Laid Out Headers

This commit is contained in:
2024-04-04 20:00:23 -04:00
parent de108630b6
commit fb7aba71b1
12 changed files with 470 additions and 26 deletions

View File

@@ -10,17 +10,17 @@
namespace J3ML::Geometry
{
using J3ML::LinearAlgebra::CoordinateFrame;
/// A frustum can be set to one of the two common different forms.
enum class FrustumType
{
Invalid,
Invalid = 0,
/// Set the Frustum type to this value to define the orthographic projection formula. In orthographic projection,
/// 3D images are projected onto a 2D plane essentially by flattening the object along one direction (the plane normal).
/// The size of the projected images appear the same independent of their distance to the camera, and distant objects will
/// not appear smaller. The shape of the Frustum is identical to an oriented bounding box (OBB).
Orthographic,
/// Set the Frustum type to this value to use the perspective projection formula. With perspective projection, the 2D
/// image is formed by projecting 3D points towards a single point (the eye point/tip) of the Frustum, and computing the
/// point of intersection of the line of the projection and the near plane of the Frustum.
@@ -29,17 +29,183 @@ namespace J3ML::Geometry
Perspective
};
class Frustum : public Shape {
public:
Plane TopFace;
Plane BottomFace;
Plane RightFace;
Plane LeftFace;
Plane FarFace;
Plane NearFace;
static Frustum CreateFrustumFromCamera(const CoordinateFrame& cam, float aspect, float fovY, float zNear, float zFar);
AABB MinimalEnclosingAABB() const;
/// The Frustum class offers choosing between the two common conventions for the value ranges in
/// post-projective space. If you are using either the OpenGL or Direct3D API, you must feed the API data that matches
/// the correct convention.
enum class FrustumProjectiveSpace
{
Invalid = 0,
/// If this option is chosen, the post-projective unit cube of the Frustum
/// is modelled after the OpenGL API convention, meaning that in projected space,
/// points inside the Frustum have the X and Y range in [-1, 1] and Z ranges in [-1, 1],
/// where the near plane maps to Z=-1 and the far plane maps to Z=1.
/// @note If you are submitting projection matrices to GPU hardware using the OpenGL API,
/// you **must** use this convention. (or otherwise more than half of the precision of the GL depth buffer is wasted)
GL,
/// If this option is chosen, the post-projective unit cube is modelled after the
/// Direct3D API convention, which differs from the GL convention that Z ranges in [0, 1] instead.
/// Near plane maps to Z=0, and far plane maps to Z=1. The X and Y ranges in [-1, 1] as is with GL.
/// @note If you are submitting projection matrices to GPU hardware using the Direct3D API,
/// you **must** use this convention.
D3D,
};
/// The handedness rule in J3ML bundles together two different conventions related to the camera:
/// * the chirality of the world and view spaces,
/// * the fixed local front direction of the Frustum.
/// @note The world and view spaces are always assumed to the same chirality, meaning that Frustum::ViewMatrix()
/// (and hence Frustum::WorldMatrix()) always returns a matrix with a positive determinant, i.e. it does not mirror.
/// If FrustumRightHanded is chosen, then Frustum::ProjectionMatrix() is a mirroring matrix, since the post-projective space
/// is always left-handed.
/// @note Even though in the local space of the camera +Y is always up, in the world space one can use any 'world up' direction
/// as one pleases, by orienting the camera via the Frustum::up vector.
enum class FrustumHandedness
{
Invalid = 0,
/// If a Frustum is left-handed, then in the local space of the Frustum (the view space), the camera looks towards +Z,
/// while +Y goes towards up, and +X goes towards right.
/// @note The fixed-pipeline D3D9 API traditionally used the FrustumLeftHanded convention.
Left,
/// If a Frustum is right-handed, then the camera looks towards -Z, +Y is up, and +X is right.
/// @note The fixed-pipeline OpenGL API traditionally used the FrustumRightHanded convention.
Right
};
/// Represents either an orthographic or a perspective viewing frustum.
class Frustum : public Shape {
public: /// Members
/// Specifies whether this frustum is a perspective or an orthographic frustum.
FrustumType type;
/// Specifies whether the [-1, 1] or [0, 1] range is used for the post-projective depth range.
FrustumProjectiveSpace projectiveSpace;
/// Specifies the chirality of world and view spaces
FrustumHandedness handedness;
/// The eye point of this frustum
Vector3 pos;
/// The normalized direction this frustum is watching towards.
Vector3 front;
/// The normalized up direction for this frustum.
/// This vector is specified in world (global) space. This vector is always normalized.
/// @note The vectors front and up must always be perpendicular to each other. This means that this up vector is not
/// a static/constant up vector, e.g. (0, 1, 0), but changes according to when the camera pitches up and down to
/// preserve the condition that front and up are always perpendicular
/// @note In the _local_ space of the Frustum, the direction +y is _always_ the up direction and cannot be changed. This
/// coincides to how Direct3D and OpenGL view and projection matrices are constructed
Vector3 up;
/// Distance from the eye point to the front plane
/// This parameter must be positive. If perspective projection is used, this parameter must be strictly positive
/// (0 is not allowed). If orthographic projection is used, 0 is possible (but uncommon, and not recommended).
/// When using the Frustum class to derive perspective projection matrices for a GPU, it should be noted that too
/// small values cause poor resolution of Z values near the back plane in post-perspective space, if non-linear
/// depth is used (which is common). The larger this value is, the more resolution there is for the Z values across the
/// depth range. Too large values cause clipping of geometry when they come very near the camera. */
float nearPlaneDistance;
/// Distance from the eye point to the back plane of the projection matrix.
/// This parameter must be strictly greater than nearPlaneDistance. The range [nearPlaneDistance, farPlaneDistance]
// specifies the visible range of objects inside the Frustum. When using the Frustum class for deriving perspective
// projection matrix for GPU rendering, it should be remembered that any geometry farther from the camera (in Z value)
// than this distance will be clipped from the view, and not rendered.
float farPlaneDistance;
union {
/// Horizontal field-of-view, in radians. This field is only valid if type == PerspectiveFrustum.
/** @see type. */
float horizontalFov;
/// The width of the orthographic frustum. This field is only valid if type == OrthographicFrustum.
/** @see type. */
float orthographicWidth;
};
union {
/// Vertical field-of-view, in radians. This field is only valid if type == PerspectiveFrustum.
/** @see type. */
float verticalFov;
/// The height of the orthographic frustum. This field is only valid if type == OrthographicFrustum.
/** @see type. */
float orthographicHeight;
};
void WorldMatrixChanged();
void ProjectionMatrixChanged();
/// Frustums are typically used in batch culling operations.
/// Therefore the matrices associated with a frustum are cached for immediate access.
Matrix4x4 worldMatrix;
Matrix4x4 projectionMatrix;
Matrix4x4 viewProjectionMatrix;
public: /// Methods
Frustum();
static Frustum CreateFrustumFromCamera(const CoordinateFrame& cam, float aspect, float fovY, float zNear, float zFar);
AABB MinimalEnclosingAABB() const;
OBB MinimalEnclosingOBB() const;
void SetKind(FrustumProjectiveSpace projectiveSpace, FrustumHandedness handedness);
void SetViewPlaneDistances(float nearPlaneDistance, float farPlaneDistance);
void SetFrame(const Vector3& pos, const Vector3& front, const Vector3& up);
void SetPos(const Vector3& pos);
void SetFront(const Vector3& front);
void SetUp(const Vector3& up);
void SetPerspective(float horizontalFov, float verticalFov);
void SetOrthographic(float orthographicWidth, float orthographicHeight);
FrustumHandedness Handedness() const { return handedness; }
FrustumType Type() const { return type; }
FrustumProjectiveSpace ProjectiveSpace() const { return projectiveSpace;}
const Vector3 &Pos() const {return pos;}
const Vector3 &Front() const { return front; }
const Vector3 &Up() const { return up; }
float NearPlaneDistance() const { return nearPlaneDistance; }
float FarPlaneDistance() const { return farPlaneDistance;}
float HorizontalFov() const { return horizontalFov;}
float VerticalFov() const { return verticalFov;}
float OrthographicWidth() const { return orthographicWidth; }
float OrthograhpicHeight() const { return orthographicHeight; }
int NumEdges() const { return 12; }
float AspectRatio() const;
void SetHorizontalFovAndAspectRatio(float horizontalFov, float aspectRatio);
Vector3 CornerPoint(int cornerIndex) const;
Vector3 NearPlanePos(float x, float y) const;
Vector3 FarPlanePos(float x, float y) const;
Vector3 WorldRight() const;
Plane TopPlane() const;
Plane BottomPlane() const;
Plane RightPlane() const;
Plane LeftPlane() const;
Plane FarPlane() const;
Plane NearPlane() const;
float NearPlaneWidth() const;
float NearPlaneHeight() const;
void Translate(const Vector3& offset);
void Transform(const Matrix3x3& transform);
void Transform(const Matrix4x4& transform);
void Transform(const Quaternion& transform);
Polyhedron ToPolyhedron() const;
bool Intersects(const Ray& ray) const;
//bool Intersects(const Line& line) const;
bool Intersects(const LineSegment& lineSegment) const;
bool Intersects(const AABB& aabb) const;
bool Intersects(const OBB& obb) const;
bool Intersects(const Plane& plane) const;
bool Intersects(const Triangle& triangle) const;
bool Intersects(const Polygon& lineSegment) const;
bool Intersects(const Sphere& aabb) const;
bool Intersects(const Capsule& obb) const;
bool Intersects(const Frustum& plane) const;
bool Intersects(const Polyhedron& triangle) const;
};
}

View File

@@ -12,5 +12,6 @@ namespace J3ML::Geometry
LineSegment(const Vector3& a, const Vector3& b);
Vector3 A;
Vector3 B;
bool Contains(const Vector3&) const;
};
}

View File

@@ -11,10 +11,19 @@ namespace J3ML::Geometry
{
public:
Plane() : Shape() {}
Plane(const Vector3& v1, const Vector3 &v2, const Vector3& v3)
{
Set(v1, v2, v3);
}
Plane(const Vector3& pos, const Vector3& norm)
: Shape(), Position(pos), Normal(norm) {}
Vector3 Position;
Vector3 Normal;
float distance = 0.f;
void Set(const Vector3& v1, const Vector3& v2, const Vector3& v3)
{
}
};
}

View File

@@ -40,6 +40,33 @@ namespace J3ML::Geometry
Vector3 Vertex(int vertexIndex) const;
bool Intersects(const LineSegment&) const;
bool Contains(const Vector3&) const;
bool Contains(const LineSegment&) const;
bool Contains(const Triangle&) const;
bool Contains(const Polygon&) const;
bool Contains(const AABB&) const;
bool Contains(const OBB&) const;
bool Contains(const Frustum&) const;
bool Contains(const Polyhedron&) const;
bool ContainsConvex(const Vector3&, float epsilon = 1e-4f) const;
bool ContainsConvex(const LineSegment&) const;
bool ContainsConvex(const Triangle&) const;
bool Intersects(const Ray&) const;
bool Intersects(const Plane&) const;
bool Intersects(const Polyhedron&) const;
bool Intersects(const AABB&) const;
bool Intersects(const OBB&) const;
bool Intersects(const Triangle&) const;
bool Intersects(const Polygon&) const;
bool Intersects(const Frustum&) const;
bool Intersects(const Sphere&) const;
bool Intersects(const Capsule&) const;
protected:
private:
};

View File

@@ -14,6 +14,8 @@ namespace J3ML::Geometry
bool Intersects(const AABB& aabb) const;
AABB BoundingAABB() const;
bool Contains(const Vector3&) const;
};

View File

@@ -132,7 +132,6 @@ namespace J3ML::LinearAlgebra {
Vector2 operator * (const Vector2& rhs) const;
Vector3 operator * (const Vector3& rhs) const;
Vector4 operator * (const Vector4& rhs) const;
Matrix3x3 operator * (const Matrix3x3& rhs) const;
Matrix4x4 operator * (const Matrix4x4& rhs) const;
Matrix3x3 Mul(const Matrix3x3& rhs) const;

View File

@@ -25,10 +25,10 @@ namespace J3ML::LinearAlgebra {
return {x, y, z};
}
float GetX() const;
float GetY() const;
float GetZ() const;
float GetW() const;
float GetX() const { return x; }
float GetY() const { return y; }
float GetZ() const { return z; }
float GetW() const { return w; }
#if MUTABLE
void SetX(float newX) { x = newX;}
void SetY(float newY) { y = newY;}
@@ -39,12 +39,21 @@ namespace J3ML::LinearAlgebra {
static const Vector4 NaN;
float operator[](std::size_t index) const;
float &operator[](std::size_t index);
bool IsWithinMarginOfError(const Vector4& rhs, float margin=0.0001f) const;
bool IsNormalized(float epsilonSq = 1e-5f) const;
bool IsZero(float epsilonSq = 1e-6f) const;
bool IsFinite() const;
bool IsPerpendicular(const Vector4& other, float epsilonSq=1e-5f) const;
bool IsPerpendicular(const Vector4& other, float epsilonSq=1e-5f) const
{
float dot = Dot(other);
return dot*dot <= epsilonSq * LengthSquared() * other.LengthSquared();
}
bool IsPerpendicular3(const Vector4& other, float epsilonSq = 1e-5f) const
{
}
bool operator==(const Vector4& rhs) const;
bool operator!=(const Vector4& rhs) const;

View File

@@ -1,5 +1,8 @@
#include <J3ML/Geometry/Common.h>
#include <J3ML/Geometry/Frustum.h>
#include <cmath>
#include "J3ML/Geometry/AABB.h"
#include <J3ML/Geometry/Polyhedron.h>
namespace J3ML::Geometry
{
@@ -10,12 +13,120 @@ namespace J3ML::Geometry
const Vector3 frontMultFar = cam.Front * zFar;
frustum.NearFace = Plane{cam.Position + cam.Front * zNear, cam.Front};
frustum.FarFace = Plane{cam.Position + frontMultFar, -cam.Front};
frustum.RightFace = Plane{cam.Position, Vector3::Cross(frontMultFar - cam.Right * halfHSide, cam.Up)};
frustum.LeftFace = Plane{cam.Position, Vector3::Cross(cam.Up, frontMultFar+cam.Right*halfHSide)};
frustum.TopFace = Plane{cam.Position, Vector3::Cross(cam.Right, frontMultFar - cam.Up * halfVSide)};
frustum.BottomFace = Plane{cam.Position, Vector3::Cross(frontMultFar + cam.Up * halfVSide, cam.Right)};
// frustum.NearFace = Plane{cam.Position + cam.Front * zNear, cam.Front};
// frustum.FarFace = Plane{cam.Position + frontMultFar, -cam.Front};
// frustum.RightFace = Plane{cam.Position, Vector3::Cross(frontMultFar - cam.Right * halfHSide, cam.Up)};
// frustum.LeftFace = Plane{cam.Position, Vector3::Cross(cam.Up, frontMultFar+cam.Right*halfHSide)};
// frustum.TopFace = Plane{cam.Position, Vector3::Cross(cam.Right, frontMultFar - cam.Up * halfVSide)};
// frustum.BottomFace = Plane{cam.Position, Vector3::Cross(frontMultFar + cam.Up * halfVSide, cam.Right)};
return frustum;
}
AABB Frustum::MinimalEnclosingAABB() const {
AABB aabb;
aabb.SetNegativeInfinity();
for(int i = 0; i < 8; ++i)
aabb.Enclose(CornerPoint(i));
return aabb;
}
Vector3 Frustum::CornerPoint(int cornerIndex) const {
assert(0 <= cornerIndex && cornerIndex <= 7);
switch(cornerIndex)
{
default: // For release builds where assume() is disabled, return always the first option if out-of-bounds.
case 0: return NearPlanePos(-1, -1);
case 1: return FarPlanePos(-1, -1);
case 2: return NearPlanePos(-1, 1);
case 3: return FarPlanePos(-1, 1);
case 4: return NearPlanePos(1, -1);
case 5: return FarPlanePos(1, -1);
case 6: return NearPlanePos(1, 1);
case 7: return FarPlanePos(1, 1);
}
}
Vector3 Frustum::NearPlanePos(float x, float y) const {
assert(type == FrustumType::Perspective || type == FrustumType::Orthographic);
if (type == FrustumType::Perspective)
{
float frontPlaneHalfWidth = std::tan(horizontalFov*0.5f)*nearPlaneDistance;
float frontPlaneHalfHeight = std::tan(verticalFov*0.5f)*nearPlaneDistance;
x = x * frontPlaneHalfWidth; // Map [-1,1] to [-width/2, width/2].
y = y * frontPlaneHalfHeight; // Map [-1,1] to [-height/2, height/2].
Vector3 right = WorldRight();
return pos + front * nearPlaneDistance + x * right + y * up;
}
else
{
Vector3 right = WorldRight();
return pos + front * nearPlaneDistance
+ x * orthographicWidth * 0.5f * right
+ y * orthographicHeight * 0.5f * up;
}
}
Vector3 Frustum::FarPlanePos(float x, float y) const {
assert(type == FrustumType::Perspective || type == FrustumType::Orthographic);
if (type == FrustumType::Perspective)
{
float farPlaneHalfWidth = std::tan(horizontalFov*0.5f)*farPlaneDistance;
float farPlaneHalfHeight = std::tan(verticalFov*0.5f)*farPlaneDistance;
x = x * farPlaneHalfWidth;
y = y * farPlaneHalfHeight;
Vector3 right = WorldRight();
return pos + front * farPlaneDistance + x * right + y * up;
} else {
Vector3 right = WorldRight();
return pos + front * farPlaneDistance
+ x * orthographicWidth * 0.5f * right
+ y * orthographicHeight * 0.5f * up;
}
}
Polyhedron Frustum::ToPolyhedron() const {
// Note to maintainer: this function is an exact copy of AABB::ToPolyhedron() and OBB::ToPolyhedron().
Polyhedron p;
// Populate the corners of this Frustum.
// They will be in the order 0: ---, 1: --+, 2: -+-, 3: -++, 4: +--, 5: +-+, 6: ++-, 7: +++.
for (int i = 0; i < 8; ++i)
{
p.v.push_back(CornerPoint(i));
}
// generate the 6 faces of this Frustum. The function Frustum::GetPlane() has a convention of returning
// the planes in order near, far, left, right, top, bottom, so follow the same convention here.
const int faces[6][4] =
{
{ 0, 4, 6, 2 }, // Z-: near plane
{ 1, 3, 7, 5 }, // Z+: far plane
{ 0, 2, 3, 1 }, // X-: left plane
{ 4, 5, 7, 6 }, // X+: right plane
{ 7, 3, 2, 6 }, // Y+: top plane
{ 0, 1, 5, 4 }, // Y-: bottom plane
};
for (int f = 0; f < 6; ++f)
{
Polyhedron::Face face;
if (this->handedness == FrustumHandedness::Left)
{
for (int v = 0; v < 4; ++v)
face.v.push_back(faces[f][3-v]);
} else {
for (int v = 0; v < 4; ++v)
face.v.push_back(faces[f][v]);
}
p.f.push_back(face);
}
return p;
}
bool Frustum::Intersects(const Ray &ray) const {
return this->ToPolyhedron().Intersects(ray);
}
}

View File

@@ -1,5 +1,8 @@
#include <J3ML/Geometry/Polyhedron.h>
#include <J3ML/Geometry/AABB.h>
#include <J3ML/Geometry/Triangle.h>
#include <J3ML/Geometry/LineSegment.h>
#include "J3ML/Geometry/Ray.h"
namespace J3ML::Geometry
{
@@ -15,5 +18,62 @@ namespace J3ML::Geometry
return v[vertexIndex];
}
bool Polyhedron::Contains(const Vector3 &point) const {
if (v.size() <= 3) {
if (v.size() == 3)
return Triangle(Vector3(v[0]), Vector3(v[1]), Vector3(v[2])).Contains(point);
else if (v.size() == 2)
return LineSegment(Vector3(v[0]), Vector3(v[1])).Contains(point);
else if (v.size() == 1)
return Vector3(v[0]).Equals(point);
else
return false;
}
int bestNumIntersections = 0;
float bestFaceContainmentDistance = 0.f;
// For N > 4 Order Polyhedra
// General strategy: pick a ray from the query point to a random direction, and count the number of times the ray intersects a face.
// If it intersects an odd number of times, the given point must have been inside the polyhedron.
// But unfortunately for numerical stability, we must be smart with the choice of the ray direction. If we pick a ray direction
// which exits the polyhedron precisely at a vertex, or at an edge of two adjoining faces, we might count those twice. Therefore
// Try to pick a ray direction that passes safely through a center of some face. If we detect that there was a tricky face that
// the ray passed too close to an edge, we have no choice but to pick another ray direction and hope that it passes through
// the polyhedron in a safe manner.
// Loop through each face to choose the ray direction. If our choice was good, we only do this once and the algorithm
// after the first iteration at j == 0. If not, we iterate more faces of the polyhedron to try to find one that is safe for
// ray-polyhedron examination.
for (int j = 0; j < (int)f.size(); ++j)
{
if (f[j].v.size() < 3)
continue;
// Accumulate how many times the ray intersected a face of the polyhedron.
int numIntersections = 0;
// Track a pseudo-distance of the closest edge of a face that the ray passed through. If this distance ends up being too small,
// we decide not to trust the result we got, and proceed to another iteration of j, hoping to guess a better-behaving direction
// for the test ray.
float faceContainmentDistance = INFINITY;
Vector3 Dir = ((Vector3)v[f[j].v[0]] + (Vector3)v[f[j].v[1]] + (Vector3)v[f[j].v[2]]) * 0.333333333333f - point;
//if (Dir.Normalize() <= 0.f)
//continue;
Ray r(Vector3(), Dir);
for (int i = 0; i < (int)f.size(); ++i)
{
Plane p((Vector3)v[f[i].v[0]] - point, (Vector3)v[f[i].v[1]] - point, (Vector3)v[f[i].v[2]] - point);
float d;
}
}
}
}

View File

@@ -426,5 +426,35 @@ namespace J3ML::LinearAlgebra {
return GetColumn(index);
}
Matrix4x4 Matrix3x3::operator*(const Matrix4x4 &rhs) const {
auto lhs = *this;
Matrix4x4 r;
r[0][0] = lhs.At(0, 0) * rhs.At(0, 0) + lhs.At(0, 1) * rhs.At(1, 0) + lhs.At(0, 2) * rhs.At(2, 0);
r[0][1] = lhs.At(0, 0) * rhs.At(0, 1) + lhs.At(0, 1) * rhs.At(1, 1) + lhs.At(0, 2) * rhs.At(2, 1);
r[0][2] = lhs.At(0, 0) * rhs.At(0, 2) + lhs.At(0, 1) * rhs.At(1, 2) + lhs.At(0, 2) * rhs.At(2, 2);
r[0][3] = lhs.At(0, 0) * rhs.At(0, 3) + lhs.At(0, 1) * rhs.At(1, 3) + lhs.At(0, 2) * rhs.At(2, 3);
r[1][0] = lhs.At(1, 0) * rhs.At(0, 0) + lhs.At(1, 1) * rhs.At(1, 0) + lhs.At(1, 2) * rhs.At(2, 0);
r[1][1] = lhs.At(1, 0) * rhs.At(0, 1) + lhs.At(1, 1) * rhs.At(1, 1) + lhs.At(1, 2) * rhs.At(2, 1);
r[1][2] = lhs.At(1, 0) * rhs.At(0, 2) + lhs.At(1, 1) * rhs.At(1, 2) + lhs.At(1, 2) * rhs.At(2, 2);
r[1][3] = lhs.At(1, 0) * rhs.At(0, 3) + lhs.At(1, 1) * rhs.At(1, 3) + lhs.At(1, 2) * rhs.At(2, 3);
r[2][0] = lhs.At(2, 0) * rhs.At(0, 0) + lhs.At(2, 1) * rhs.At(1, 0) + lhs.At(2, 2) * rhs.At(2, 0);
r[2][1] = lhs.At(2, 0) * rhs.At(0, 1) + lhs.At(2, 1) * rhs.At(1, 1) + lhs.At(2, 2) * rhs.At(2, 1);
r[2][2] = lhs.At(2, 0) * rhs.At(0, 2) + lhs.At(2, 1) * rhs.At(1, 2) + lhs.At(2, 2) * rhs.At(2, 2);
r[2][3] = lhs.At(2, 0) * rhs.At(0, 3) + lhs.At(2, 1) * rhs.At(1, 3) + lhs.At(2, 2) * rhs.At(2, 3);
r[3][0] = rhs.At(3, 0);
r[3][1] = rhs.At(3, 1);
r[3][2] = rhs.At(3, 2);
r[3][3] = rhs.At(3, 3);
return r;
}
Vector2 Matrix3x3::operator*(const Vector2 &rhs) const {
return Transform(rhs);
}
}

View File

@@ -634,4 +634,16 @@ namespace J3ML::LinearAlgebra {
return IsRowOrthogonal3(epsilon);
}
bool Matrix4x4::IsColOrthogonal3(float epsilon) const {
return GetColumn(0).IsPerpendicular(GetColumn(1), epsilon)
&& GetColumn(0).IsPerpendicular(GetColumn(2), epsilon)
&& GetColumn(1).IsPerpendicular(GetColumn(2), epsilon);
}
bool Matrix4x4::IsRowOrthogonal3(float epsilon) const {
return GetRow(0).IsPerpendicular(GetRow(1), epsilon)
&& GetRow(0).IsPerpendicular(GetRow(2), epsilon)
&& GetRow(1).IsPerpendicular(GetRow(2), epsilon);
}
}

View File

@@ -164,6 +164,24 @@ Vector4 Vector4::operator-(const Vector4& rhs) const
std::abs(w - _w) < epsilon;
}
float Vector4::operator[](std::size_t index) const {
assert(index < 4);
if (index==0) return x;
if (index==1) return y;
if (index==2) return z;
if (index==3) return w;
return 0;
}
float &Vector4::operator[](std::size_t index) {
assert(index < 4);
if (index == 0) return x;
if (index == 1) return y;
if (index == 2) return z;
if (index == 3) return w;
}
}
#pragma endregion