mirror of
https://github.com/HandmadeMath/HandmadeMath.git
synced 2025-12-28 07:34:32 +00:00
Drop Projection Matrix Config; Make explicit. (#154)
* Add N0/Z0 projection Remove configuration macro * Update update_hmm.c Co-authored-by: Ben Visness <bvisness@users.noreply.github.com>
This commit is contained in:
121
HandmadeMath.h
121
HandmadeMath.h
@@ -26,20 +26,6 @@
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
By default, Handmade Math's projection matrices use a Normalized Device
|
||||
Coordinates (NDC) range of X: [-1, 1], Y: [-1, 1], Z: [-1, 1], as is standard
|
||||
in OpenGL. However, other graphics APIs require the range with Z: [0, 1], as
|
||||
this has better numerical properties for depth buffers.
|
||||
|
||||
To use NDC with Z: [0, 1], you must define HANDMADE_MATH_USE_NDC_Z01 before
|
||||
including this header, which will make HMM_Perspective and HMM_Orthographic
|
||||
functions project Z to [0, 1]:
|
||||
|
||||
#define HANDMADE_MATH_USE_NDC_Z01
|
||||
#include "HandmadeMath.h"
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Handmade Math ships with SSE (SIMD) implementations of several common
|
||||
operations. To disable the use of SSE intrinsics, you must
|
||||
define HANDMADE_MATH_NO_SSE before including this file:
|
||||
@@ -1711,10 +1697,10 @@ static inline HMM_Mat4 HMM_InvGeneralM4(HMM_Mat4 Matrix)
|
||||
* Common graphics transformations
|
||||
*/
|
||||
|
||||
COVERAGE(HMM_Orthographic_RH, 1)
|
||||
static inline HMM_Mat4 HMM_Orthographic_RH(float Left, float Right, float Bottom, float Top, float Near, float Far)
|
||||
COVERAGE(HMM_Orthographic_N0_RH, 1)
|
||||
static inline HMM_Mat4 HMM_Orthographic_N0_RH(float Left, float Right, float Bottom, float Top, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Orthographic_RH);
|
||||
ASSERT_COVERED(HMM_Orthographic_N0_RH);
|
||||
|
||||
HMM_Mat4 Result = {0};
|
||||
|
||||
@@ -1725,23 +1711,49 @@ static inline HMM_Mat4 HMM_Orthographic_RH(float Left, float Right, float Bottom
|
||||
Result.Elements[3][0] = (Left + Right) / (Left - Right);
|
||||
Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top);
|
||||
|
||||
#ifdef HANDMADE_MATH_USE_NDC_Z01
|
||||
Result.Elements[2][2] = 1.0f / (Near - Far);
|
||||
Result.Elements[3][2] = (Near) / (Near - Far);
|
||||
#else
|
||||
Result.Elements[2][2] = 2.0f / (Near - Far);
|
||||
Result.Elements[3][2] = (Far + Near) / (Near - Far);
|
||||
#endif
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_Orthographic_LH, 1)
|
||||
static inline HMM_Mat4 HMM_Orthographic_LH(float Left, float Right, float Bottom, float Top, float Near, float Far)
|
||||
COVERAGE(HMM_Orthographic_Z0_RH, 1)
|
||||
static inline HMM_Mat4 HMM_Orthographic_Z0_RH(float Left, float Right, float Bottom, float Top, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Orthographic_LH);
|
||||
ASSERT_COVERED(HMM_Orthographic_Z0_RH);
|
||||
|
||||
HMM_Mat4 Result = HMM_Orthographic_RH(Left, Right, Bottom, Top, Near, Far);
|
||||
HMM_Mat4 Result = {0};
|
||||
|
||||
Result.Elements[0][0] = 2.0f / (Right - Left);
|
||||
Result.Elements[1][1] = 2.0f / (Top - Bottom);
|
||||
Result.Elements[3][3] = 1.0f;
|
||||
|
||||
Result.Elements[3][0] = (Left + Right) / (Left - Right);
|
||||
Result.Elements[3][1] = (Bottom + Top) / (Bottom - Top);
|
||||
|
||||
Result.Elements[2][2] = 1.0f / (Near - Far);
|
||||
Result.Elements[3][2] = (Near) / (Near - Far);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_Orthographic_N0_LH, 1)
|
||||
static inline HMM_Mat4 HMM_Orthographic_N0_LH(float Left, float Right, float Bottom, float Top, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Orthographic_N0_LH);
|
||||
|
||||
HMM_Mat4 Result = HMM_Orthographic_N0_RH(Left, Right, Bottom, Top, Near, Far);
|
||||
Result.Elements[2][2] = -Result.Elements[2][2];
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_Orthographic_Z0_LH, 1)
|
||||
static inline HMM_Mat4 HMM_Orthographic_Z0_LH(float Left, float Right, float Bottom, float Top, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Orthographic_Z0_LH);
|
||||
|
||||
HMM_Mat4 Result = HMM_Orthographic_Z0_RH(Left, Right, Bottom, Top, Near, Far);
|
||||
Result.Elements[2][2] = -Result.Elements[2][2];
|
||||
|
||||
return Result;
|
||||
@@ -1765,43 +1777,68 @@ static inline HMM_Mat4 HMM_InvOrthographic(HMM_Mat4 OrthoMatrix)
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_Perspective_RH, 1)
|
||||
static inline HMM_Mat4 HMM_Perspective_RH(float FOV, float AspectRatio, float Near, float Far)
|
||||
COVERAGE(HMM_Perspective_N0_RH, 1)
|
||||
static inline HMM_Mat4 HMM_Perspective_N0_RH(float FOV, float AspectRatio, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Perspective_RH);
|
||||
ASSERT_COVERED(HMM_Perspective_N0_RH);
|
||||
|
||||
HMM_Mat4 Result = {0};
|
||||
|
||||
// See https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml
|
||||
|
||||
float Cotangent = 1.0f / HMM_TanF(FOV / 2.0f);
|
||||
|
||||
Result.Elements[0][0] = Cotangent / AspectRatio;
|
||||
Result.Elements[1][1] = Cotangent;
|
||||
|
||||
Result.Elements[2][3] = -1.0f;
|
||||
|
||||
#ifdef HANDMADE_MATH_USE_NDC_Z01
|
||||
Result.Elements[2][2] = (Far) / (Near - Far);
|
||||
Result.Elements[3][2] = (Near * Far) / (Near - Far);
|
||||
#else
|
||||
Result.Elements[2][2] = (Near + Far) / (Near - Far);
|
||||
Result.Elements[3][2] = (2.0f * Near * Far) / (Near - Far);
|
||||
#endif
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_Perspective_Z0_RH, 1)
|
||||
static inline HMM_Mat4 HMM_Perspective_Z0_RH(float FOV, float AspectRatio, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Perspective_Z0_RH);
|
||||
|
||||
HMM_Mat4 Result = {0};
|
||||
|
||||
// See https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml
|
||||
|
||||
float Cotangent = 1.0f / HMM_TanF(FOV / 2.0f);
|
||||
Result.Elements[0][0] = Cotangent / AspectRatio;
|
||||
Result.Elements[1][1] = Cotangent;
|
||||
Result.Elements[2][3] = -1.0f;
|
||||
|
||||
Result.Elements[2][2] = (Far) / (Near - Far);
|
||||
Result.Elements[3][2] = (Near * Far) / (Near - Far);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_Perspective_LH, 1)
|
||||
static inline HMM_Mat4 HMM_Perspective_LH(float FOV, float AspectRatio, float Near, float Far)
|
||||
COVERAGE(HMM_Perspective_N0_LH, 1)
|
||||
static inline HMM_Mat4 HMM_Perspective_N0_LH(float FOV, float AspectRatio, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Perspective_LH);
|
||||
ASSERT_COVERED(HMM_Perspective_N0_LH);
|
||||
|
||||
HMM_Mat4 Result = HMM_Perspective_RH(FOV, AspectRatio, Near, Far);
|
||||
Result.Elements[2][2] = -Result.Elements[2][2];
|
||||
HMM_Mat4 Result = HMM_Perspective_N0_RH(FOV, AspectRatio, Near, Far);
|
||||
Result.Elements[2][2] = -Result.Elements[2][2];
|
||||
Result.Elements[2][3] = -Result.Elements[2][3];
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
return (Result);
|
||||
COVERAGE(HMM_Perspective_Z0_LH, 1)
|
||||
static inline HMM_Mat4 HMM_Perspective_Z0_LH(float FOV, float AspectRatio, float Near, float Far)
|
||||
{
|
||||
ASSERT_COVERED(HMM_Perspective_Z0_LH);
|
||||
|
||||
HMM_Mat4 Result = HMM_Perspective_Z0_RH(FOV, AspectRatio, Near, Far);
|
||||
Result.Elements[2][2] = -Result.Elements[2][2];
|
||||
Result.Elements[2][3] = -Result.Elements[2][3];
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
COVERAGE(HMM_InvPerspective, 1)
|
||||
|
||||
@@ -249,7 +249,7 @@ TEST(InvMatrix, InvGeneral)
|
||||
TEST(InvMatrix, Mat4Inverses)
|
||||
{
|
||||
{
|
||||
HMM_Mat4 Matrix = HMM_Orthographic_RH(-160+100, 160+100, -90+200, 90+200, 10, 10000);
|
||||
HMM_Mat4 Matrix = HMM_Orthographic_N0_RH(-160+100, 160+100, -90+200, 90+200, 10, 10000);
|
||||
HMM_Mat4 Expect = HMM_M4D(1.0f);
|
||||
HMM_Mat4 Inverse = HMM_InvOrthographic(Matrix);
|
||||
HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse);
|
||||
@@ -272,10 +272,10 @@ TEST(InvMatrix, Mat4Inverses)
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][0], Expect.Elements[3][0]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][1], Expect.Elements[3][1]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][2], Expect.Elements[3][2]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][3], Expect.Elements[3][3]);
|
||||
EXPECT_FLOAT_EQ(Result.Elements[3][3], Expect.Elements[3][3]);
|
||||
}
|
||||
{
|
||||
HMM_Mat4 Matrix = HMM_Perspective_RH(HMM_AngleDeg(120), 16.0/9.0, 10, 10000);
|
||||
HMM_Mat4 Matrix = HMM_Perspective_N0_RH(HMM_AngleDeg(120), 16.0/9.0, 10, 10000);
|
||||
HMM_Mat4 Expect = HMM_M4D(1.0f);
|
||||
HMM_Mat4 Inverse = HMM_InvPerspective(Matrix);
|
||||
HMM_Mat4 Result = HMM_MulM4(Matrix, Inverse);
|
||||
|
||||
@@ -3,47 +3,66 @@
|
||||
TEST(Projection, Orthographic)
|
||||
{
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Orthographic_RH(-10.0f, 10.0f, -5.0f, 5.0f, 0.0f, -10.0f);
|
||||
|
||||
HMM_Vec3 original = HMM_V3(5.0f, 5.0f, -5.0f);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, HMM_V4V(original, 1));
|
||||
HMM_Mat4 projection = HMM_Orthographic_N0_RH(-10.0f, 10.0f, -5.0f, 5.0f, 1.0f, 10.0f);
|
||||
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, -1.0f, 1.0);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, original);
|
||||
|
||||
EXPECT_FLOAT_EQ(projected.X, 0.5f);
|
||||
EXPECT_FLOAT_EQ(projected.Y, 1.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, -2.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, -1.0f);
|
||||
EXPECT_FLOAT_EQ(projected.W, 1.0f);
|
||||
|
||||
/* Z0 */
|
||||
projection = HMM_Orthographic_Z0_RH(-10.0f, 10.0f, -5.0f, 5.0f, 1.0f, -10.0f);
|
||||
projected = HMM_MulM4V4(projection, original);
|
||||
EXPECT_FLOAT_EQ(projected.Z, 0.0f);
|
||||
}
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Orthographic_LH(-10.0f, 10.0f, -5.0f, 5.0f, 0.0f, 10.0f);
|
||||
|
||||
HMM_Vec3 original = HMM_V3(5.0f, 5.0f, -5.0f);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, HMM_V4V(original, 1));
|
||||
|
||||
HMM_Mat4 projection = HMM_Orthographic_N0_LH(-10.0f, 10.0f, -5.0f, 5.0f, 1.0f, -10.0f);
|
||||
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, 1.0f, 1.0);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, original);
|
||||
|
||||
EXPECT_FLOAT_EQ(projected.X, 0.5f);
|
||||
EXPECT_FLOAT_EQ(projected.Y, 1.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, -2.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, -1.0f);
|
||||
EXPECT_FLOAT_EQ(projected.W, 1.0f);
|
||||
|
||||
/* Z0 */
|
||||
projection = HMM_Orthographic_Z0_LH(-10.0f, 10.0f, -5.0f, 5.0f, 1.0f, -10.0f);
|
||||
projected = HMM_MulM4V4(projection, original);
|
||||
EXPECT_FLOAT_EQ(projected.Z, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Projection, Perspective)
|
||||
{
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Perspective_RH(HMM_AngleDeg(90.0f), 2.0f, 5.0f, 15.0f);
|
||||
HMM_Vec3 original = HMM_V3(5.0f, 5.0f, -15.0f);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, HMM_V4V(original, 1));
|
||||
HMM_Mat4 projection = HMM_Perspective_N0_RH(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
|
||||
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, -1.0f, 1.0f);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, original);
|
||||
EXPECT_FLOAT_EQ(projected.X, 2.5f);
|
||||
EXPECT_FLOAT_EQ(projected.Y, 5.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, 15.0f);
|
||||
EXPECT_FLOAT_EQ(projected.W, 15.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, -1.0f);
|
||||
EXPECT_FLOAT_EQ(projected.W, 1.0f);
|
||||
|
||||
/* Z0 */
|
||||
projection = HMM_Perspective_Z0_RH(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
|
||||
projected = HMM_MulM4V4(projection, original);
|
||||
EXPECT_FLOAT_EQ(projected.Z, 0.0f);
|
||||
}
|
||||
|
||||
{
|
||||
HMM_Mat4 projection = HMM_Perspective_LH(HMM_AngleDeg(90.0f), 2.0f, 5.0f, 15.0f);
|
||||
HMM_Vec3 original = HMM_V3(5.0f, 5.0f, 15.0f);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, HMM_V4V(original, 1));
|
||||
HMM_Mat4 projection = HMM_Perspective_N0_LH(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
|
||||
HMM_Vec4 original = HMM_V4(5.0f, 5.0f, 1.0f, 1.0f);
|
||||
HMM_Vec4 projected = HMM_MulM4V4(projection, original);
|
||||
EXPECT_FLOAT_EQ(projected.X, 2.5f);
|
||||
EXPECT_FLOAT_EQ(projected.Y, 5.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, 15.0f);
|
||||
EXPECT_FLOAT_EQ(projected.W, 15.0f);
|
||||
EXPECT_FLOAT_EQ(projected.Z, -1.0f);
|
||||
EXPECT_FLOAT_EQ(projected.W, 1.0f);
|
||||
|
||||
/* Z0 */
|
||||
projection = HMM_Perspective_Z0_LH(HMM_AngleDeg(90.0f), 2.0f, 1.0f, 15.0f);
|
||||
projected = HMM_MulM4V4(projection, original);
|
||||
EXPECT_FLOAT_EQ(projected.Z, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -482,8 +482,15 @@ Str8List update_file_content(Arena* arena, str8 file_content) {
|
||||
|
||||
chr8 check = file_content.str[i+1];
|
||||
if (check == '(') {
|
||||
printf("\t[%u]: Find: %.*s, Appending: _RH for old default handedness.\n", Line, str8_PRINTF_ARGS(Find[t]));
|
||||
Str8List_add(arena, &out, str8_first(file_content, i + 1));
|
||||
|
||||
if (t == HAND_PERSPECTIVE || t == HAND_ORTHO) {
|
||||
printf("\t[%u]: Appending _N0 for old default NDC.\n", Line, str8_PRINTF_ARGS(Find[t]));
|
||||
Str8List_add(arena, &out, str8_lit("_N0"));
|
||||
}
|
||||
|
||||
printf("\t[%u]: Find: %.*s, Appending: _RH for old default handedness.\n", Line, str8_PRINTF_ARGS(Find[t]));
|
||||
|
||||
Str8List_add(arena, &out, str8_lit("_RH("));
|
||||
file_content = str8_skip(file_content, i+2);
|
||||
i = -1;
|
||||
|
||||
Reference in New Issue
Block a user