refactor: use XCEngine::Math module in sphere test, update matrix to left-handed coordinate system

- Use Matrix4x4 type directly instead of float[16]
- Remove wrapper functions (IdentityMatrix, TranslationMatrix, PerspectiveMatrix, LookAtMatrix, MultiplyMatrix, TransposeMatrix)
- Direct use of Matrix4x4::Identity(), Matrix4x4::Translation(), Matrix4x4::Perspective()
- Transpose matrices before uploading to GPU to match HLSL column-major
- Update Math module Perspective and Orthographic to left-handed coordinate system
- Update math unit tests for new matrix values
This commit is contained in:
2026-03-22 20:08:36 +08:00
parent 70cc86793f
commit 0eadc7cfd1
3 changed files with 25 additions and 86 deletions

View File

@@ -31,11 +31,14 @@
#include "XCEngine/Debug/ConsoleLogSink.h"
#include "XCEngine/Debug/FileLogSink.h"
#include "XCEngine/Containers/String.h"
#include "XCEngine/Math/Matrix4.h"
#include "XCEngine/Math/Vector3.h"
#include "third_party/stb/stb_image.h"
using namespace XCEngine::RHI;
using namespace XCEngine::Debug;
using namespace XCEngine::Containers;
using namespace XCEngine::Math;
#pragma comment(lib,"d3d12.lib")
#pragma comment(lib,"dxgi.lib")
@@ -71,9 +74,9 @@ int gCurrentRTIndex = 0;
UINT gIndexCount = 0;
float gProjectionMatrix[16];
float gViewMatrix[16];
float gModelMatrix[16];
Matrix4x4 gProjectionMatrix;
Matrix4x4 gViewMatrix;
Matrix4x4 gModelMatrix;
HWND gHWND = nullptr;
int gWidth = 1280;
@@ -97,73 +100,6 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void IdentityMatrix(float* m) {
memset(m, 0, 16 * sizeof(float));
m[0] = m[5] = m[10] = m[15] = 1.0f;
}
void TranslationMatrix(float* m, float x, float y, float z) {
memset(m, 0, 16 * sizeof(float));
m[0] = 1.0f; m[12] = x;
m[5] = 1.0f; m[13] = y;
m[10] = 1.0f; m[14] = z;
m[15] = 1.0f;
}
void PerspectiveMatrix(float* m, float fov, float aspect, float nearZ, float farZ) {
memset(m, 0, 16 * sizeof(float));
float tanHalfFov = tanf(fov / 2.0f);
m[0] = 1.0f / (aspect * tanHalfFov);
m[5] = 1.0f / tanHalfFov;
m[10] = farZ / (farZ - nearZ);
m[11] = 1.0f;
m[14] = -(farZ * nearZ) / (farZ - nearZ);
m[15] = 0.0f;
}
void LookAtMatrix(float* m, const float* eye, const float* target, const float* up) {
float zAxis[3] = { eye[0] - target[0], eye[1] - target[1], eye[2] - target[2] };
float zLen = sqrtf(zAxis[0] * zAxis[0] + zAxis[1] * zAxis[1] + zAxis[2] * zAxis[2]);
if (zLen > 0) { zAxis[0] /= zLen; zAxis[1] /= zLen; zAxis[2] /= zLen; }
float xAxis[3] = { up[1] * zAxis[2] - up[2] * zAxis[1],
up[2] * zAxis[0] - up[0] * zAxis[2],
up[0] * zAxis[1] - up[1] * zAxis[0] };
float xLen = sqrtf(xAxis[0] * xAxis[0] + xAxis[1] * xAxis[1] + xAxis[2] * xAxis[2]);
if (xLen > 0) { xAxis[0] /= xLen; xAxis[1] /= xLen; xAxis[2] /= xLen; }
float yAxis[3] = { zAxis[1] * xAxis[2] - zAxis[2] * xAxis[1],
zAxis[2] * xAxis[0] - zAxis[0] * xAxis[2],
zAxis[0] * xAxis[1] - zAxis[1] * xAxis[0] };
m[0] = xAxis[0]; m[1] = yAxis[0]; m[2] = zAxis[0]; m[3] = 0;
m[4] = xAxis[1]; m[5] = yAxis[1]; m[6] = zAxis[1]; m[7] = 0;
m[8] = xAxis[2]; m[9] = yAxis[2]; m[10] = zAxis[2]; m[11] = 0;
m[12] = -xAxis[0] * eye[0] - xAxis[1] * eye[1] - xAxis[2] * eye[2];
m[13] = -yAxis[0] * eye[0] - yAxis[1] * eye[1] - yAxis[2] * eye[2];
m[14] = -zAxis[0] * eye[0] - zAxis[1] * eye[1] - zAxis[2] * eye[2];
m[15] = 1.0f;
}
void MultiplyMatrix(float* dst, const float* a, const float* b) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
dst[i * 4 + j] = 0;
for (int k = 0; k < 4; k++) {
dst[i * 4 + j] += a[i * 4 + k] * b[k * 4 + j];
}
}
}
}
void TransposeMatrix(float* dst, const float* src) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
dst[i * 4 + j] = src[j * 4 + i];
}
}
}
struct Vertex {
float pos[4];
float texcoord[4];
@@ -408,15 +344,18 @@ bool InitD3D12() {
gIndexBuffer.SetBufferType(BufferType::Index);
float aspect = 1280.0f / 720.0f;
PerspectiveMatrix(gProjectionMatrix, 45.0f * 3.141592f / 180.0f, aspect, 0.1f, 1000.0f);
IdentityMatrix(gViewMatrix);
TranslationMatrix(gModelMatrix, 0.0f, 0.0f, 5.0f);
gProjectionMatrix = Matrix4x4::Perspective(45.0f * 3.141592f / 180.0f, aspect, 0.1f, 1000.0f);
gViewMatrix = Matrix4x4::Identity();
gModelMatrix = Matrix4x4::Translation(Vector3(0.0f, 0.0f, 5.0f));
float matrices[64];
memcpy(matrices, gProjectionMatrix, 64);
memcpy(matrices + 16, gViewMatrix, 64);
memcpy(matrices + 32, gModelMatrix, 64);
memcpy(matrices + 48, gModelMatrix, 64);
Matrix4x4 projTransposed = gProjectionMatrix.Transpose();
Matrix4x4 viewTransposed = gViewMatrix.Transpose();
Matrix4x4 modelTransposed = gModelMatrix.Transpose();
memcpy(matrices, &projTransposed.m[0][0], 64);
memcpy(matrices + 16, &viewTransposed.m[0][0], 64);
memcpy(matrices + 32, &modelTransposed.m[0][0], 64);
memcpy(matrices + 48, &modelTransposed.m[0][0], 64);
gMVPBuffer.InitializeWithData(device, gCommandList.GetCommandList(), matrices, sizeof(matrices), D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFER);

View File

@@ -139,9 +139,9 @@ TEST(Math_Matrix4, Perspective) {
EXPECT_FLOAT_EQ(m.m[0][0], 1.0f / (aspect * std::tan(fov * 0.5f)));
EXPECT_FLOAT_EQ(m.m[1][1], 1.0f / std::tan(fov * 0.5f));
EXPECT_FLOAT_EQ(m.m[2][2], -(farPlane + nearPlane) / (farPlane - nearPlane));
EXPECT_FLOAT_EQ(m.m[2][3], -(2.0f * farPlane * nearPlane) / (farPlane - nearPlane));
EXPECT_FLOAT_EQ(m.m[3][2], -1.0f);
EXPECT_FLOAT_EQ(m.m[2][2], farPlane / (farPlane - nearPlane));
EXPECT_FLOAT_EQ(m.m[2][3], -farPlane * nearPlane / (farPlane - nearPlane));
EXPECT_FLOAT_EQ(m.m[3][2], 1.0f);
}
TEST(Math_Matrix4, Orthographic) {
@@ -153,7 +153,7 @@ TEST(Math_Matrix4, Orthographic) {
EXPECT_FLOAT_EQ(m.m[0][0], 0.1f);
EXPECT_FLOAT_EQ(m.m[1][1], 0.1f);
EXPECT_FLOAT_EQ(m.m[2][2], -2.0f / (farPlane - nearPlane));
EXPECT_FLOAT_EQ(m.m[2][2], 1.0f / (farPlane - nearPlane));
}
TEST(Math_Matrix4, Multiply_MatrixWithMatrix) {