Fix sphere winding and viewport middle-pan input

This commit is contained in:
2026-04-06 04:11:00 +08:00
parent 31d14abece
commit 3540dbc94d
4 changed files with 72 additions and 7 deletions

View File

@@ -1,6 +1,8 @@
#include <gtest/gtest.h>
#include <XCEngine/Core/Asset/AssetDatabase.h>
#include <XCEngine/Core/Asset/ResourceManager.h>
#include <XCEngine/Core/Math/Vector3.h>
#include <XCEngine/Resources/BuiltinResources.h>
#include <XCEngine/Resources/Material/MaterialLoader.h>
#include <XCEngine/Resources/Mesh/MeshLoader.h>
#include <XCEngine/Resources/Mesh/MeshImportSettings.h>
@@ -23,6 +25,16 @@ std::string GetMeshFixturePath(const char* fileName) {
return (std::filesystem::path(XCENGINE_TEST_FIXTURES_DIR) / "Resources" / "Mesh" / fileName).string();
}
XCEngine::Core::uint32 ReadMeshIndex(const Mesh& mesh, XCEngine::Core::uint32 index) {
if (mesh.IsUse32BitIndex()) {
const auto* indices = static_cast<const XCEngine::Core::uint32*>(mesh.GetIndexData());
return indices[index];
}
const auto* indices = static_cast<const XCEngine::Core::uint16*>(mesh.GetIndexData());
return static_cast<XCEngine::Core::uint32>(indices[index]);
}
XCEngine::Core::uint32 GetFirstSectionMaterialIndex(const Mesh& mesh) {
if (mesh.GetSections().Empty()) {
return 0;
@@ -142,6 +154,41 @@ TEST(MeshLoader, LoadValidObjMesh) {
delete mesh;
}
TEST(MeshLoader, BuiltinSphereUsesFrontFacingWindingForOutwardNormals) {
LoadResult result = CreateBuiltinMeshResource(GetBuiltinPrimitiveMeshPath(BuiltinPrimitiveType::Sphere));
ASSERT_TRUE(result);
ASSERT_NE(result.resource, nullptr);
auto* mesh = static_cast<Mesh*>(result.resource);
const auto* vertices = static_cast<const StaticMeshVertex*>(mesh->GetVertexData());
ASSERT_NE(vertices, nullptr);
ASSERT_GE(mesh->GetIndexCount(), 3u);
bool foundNonDegenerateTriangle = false;
for (XCEngine::Core::uint32 index = 0; index + 2 < mesh->GetIndexCount(); index += 3) {
const XCEngine::Core::uint32 i0 = ReadMeshIndex(*mesh, index + 0);
const XCEngine::Core::uint32 i1 = ReadMeshIndex(*mesh, index + 1);
const XCEngine::Core::uint32 i2 = ReadMeshIndex(*mesh, index + 2);
const XCEngine::Math::Vector3 edge01 = vertices[i1].position - vertices[i0].position;
const XCEngine::Math::Vector3 edge02 = vertices[i2].position - vertices[i0].position;
const XCEngine::Math::Vector3 geometricNormal =
XCEngine::Math::Vector3::Cross(edge01, edge02);
if (geometricNormal.SqrMagnitude() <= XCEngine::Math::EPSILON) {
continue;
}
const XCEngine::Math::Vector3 averagedVertexNormal =
(vertices[i0].normal + vertices[i1].normal + vertices[i2].normal).Normalized();
EXPECT_LT(XCEngine::Math::Vector3::Dot(geometricNormal, averagedVertexNormal), 0.0f);
foundNonDegenerateTriangle = true;
break;
}
EXPECT_TRUE(foundNonDegenerateTriangle);
delete mesh;
}
TEST(MeshLoader, GeneratesNormalsAndTangentsWhenRequested) {
MeshLoader loader;
MeshImportSettings settings;