Add assimp-based mesh import
This commit is contained in:
@@ -28,5 +28,15 @@ target_include_directories(mesh_tests PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/tests/fixtures
|
||||
)
|
||||
|
||||
target_compile_definitions(mesh_tests PRIVATE
|
||||
XCENGINE_TEST_FIXTURES_DIR="${CMAKE_SOURCE_DIR}/tests/fixtures"
|
||||
)
|
||||
|
||||
add_custom_command(TARGET mesh_tests POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${CMAKE_SOURCE_DIR}/engine/third_party/assimp/bin/assimp-vc143-mt.dll
|
||||
$<TARGET_FILE_DIR:mesh_tests>/assimp-vc143-mt.dll
|
||||
)
|
||||
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(mesh_tests)
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <XCEngine/Core/Asset/ResourceManager.h>
|
||||
|
||||
using namespace XCEngine::Resources;
|
||||
using namespace XCEngine::Math;
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -30,4 +31,44 @@ TEST(Mesh, GetSections) {
|
||||
EXPECT_EQ(mesh.GetSections().Size(), 0u);
|
||||
}
|
||||
|
||||
TEST(Mesh, SetVertexAndIndexData) {
|
||||
Mesh mesh;
|
||||
|
||||
StaticMeshVertex vertices[3];
|
||||
vertices[0].position = Vector3(0.0f, 0.0f, 0.0f);
|
||||
vertices[1].position = Vector3(1.0f, 0.0f, 0.0f);
|
||||
vertices[2].position = Vector3(0.0f, 1.0f, 0.0f);
|
||||
|
||||
const uint16_t indices[3] = {0, 1, 2};
|
||||
|
||||
mesh.SetVertexData(vertices, sizeof(vertices), 3, sizeof(StaticMeshVertex),
|
||||
VertexAttribute::Position | VertexAttribute::Normal | VertexAttribute::UV0);
|
||||
mesh.SetIndexData(indices, sizeof(indices), 3, false);
|
||||
|
||||
EXPECT_EQ(mesh.GetVertexCount(), 3u);
|
||||
EXPECT_EQ(mesh.GetIndexCount(), 3u);
|
||||
EXPECT_EQ(mesh.GetVertexStride(), sizeof(StaticMeshVertex));
|
||||
EXPECT_TRUE(HasVertexAttribute(mesh.GetVertexAttributes(), VertexAttribute::Position));
|
||||
EXPECT_TRUE(HasVertexAttribute(mesh.GetVertexAttributes(), VertexAttribute::Normal));
|
||||
EXPECT_TRUE(HasVertexAttribute(mesh.GetVertexAttributes(), VertexAttribute::UV0));
|
||||
EXPECT_GT(mesh.GetMemorySize(), 0u);
|
||||
}
|
||||
|
||||
TEST(Mesh, AddSection) {
|
||||
Mesh mesh;
|
||||
|
||||
MeshSection section{};
|
||||
section.baseVertex = 1;
|
||||
section.vertexCount = 3;
|
||||
section.startIndex = 6;
|
||||
section.indexCount = 9;
|
||||
section.materialID = 2;
|
||||
|
||||
mesh.AddSection(section);
|
||||
|
||||
ASSERT_EQ(mesh.GetSections().Size(), 1u);
|
||||
EXPECT_EQ(mesh.GetSections()[0].baseVertex, 1u);
|
||||
EXPECT_EQ(mesh.GetSections()[0].materialID, 2u);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -101,4 +101,30 @@ TEST(MeshImportSettings, Clone) {
|
||||
EXPECT_TRUE(clonedSettings->GetMergeMeshes());
|
||||
}
|
||||
|
||||
TEST(MeshImportSettings, SaveAndLoadJSON) {
|
||||
MeshImportSettings settings;
|
||||
settings.SetImportFlags(MeshImportFlags::FlipUVs | MeshImportFlags::GenerateTangents);
|
||||
settings.SetScale(2.5f);
|
||||
settings.SetOffset(Vector3(1.0f, 2.0f, 3.0f));
|
||||
settings.SetAxisConversion(false);
|
||||
settings.SetMergeMeshes(true);
|
||||
settings.SetOptimizeThreshold(0.6f);
|
||||
settings.SetImportScale(0.75f);
|
||||
settings.SetThreshold(0.05f);
|
||||
|
||||
const auto json = settings.SaveToJSON();
|
||||
|
||||
MeshImportSettings loaded;
|
||||
EXPECT_TRUE(loaded.LoadFromJSON(json));
|
||||
EXPECT_TRUE(loaded.HasImportFlag(MeshImportFlags::FlipUVs));
|
||||
EXPECT_TRUE(loaded.HasImportFlag(MeshImportFlags::GenerateTangents));
|
||||
EXPECT_FLOAT_EQ(loaded.GetScale(), 2.5f);
|
||||
EXPECT_EQ(loaded.GetOffset(), Vector3(1.0f, 2.0f, 3.0f));
|
||||
EXPECT_FALSE(loaded.GetAxisConversion());
|
||||
EXPECT_TRUE(loaded.GetMergeMeshes());
|
||||
EXPECT_FLOAT_EQ(loaded.GetOptimizeThreshold(), 0.6f);
|
||||
EXPECT_FLOAT_EQ(loaded.GetImportScale(), 0.75f);
|
||||
EXPECT_FLOAT_EQ(loaded.GetThreshold(), 0.05f);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <XCEngine/Resources/Mesh/MeshLoader.h>
|
||||
#include <XCEngine/Resources/Mesh/MeshImportSettings.h>
|
||||
#include <XCEngine/Core/Asset/ResourceTypes.h>
|
||||
#include <XCEngine/Core/Containers/Array.h>
|
||||
#include <filesystem>
|
||||
|
||||
using namespace XCEngine::Resources;
|
||||
using namespace XCEngine::Containers;
|
||||
|
||||
namespace {
|
||||
|
||||
std::string GetMeshFixturePath(const char* fileName) {
|
||||
return (std::filesystem::path(XCENGINE_TEST_FIXTURES_DIR) / "Resources" / "Mesh" / fileName).string();
|
||||
}
|
||||
|
||||
TEST(MeshLoader, GetResourceType) {
|
||||
MeshLoader loader;
|
||||
EXPECT_EQ(loader.GetResourceType(), ResourceType::Mesh);
|
||||
@@ -24,6 +30,7 @@ TEST(MeshLoader, CanLoad) {
|
||||
EXPECT_TRUE(loader.CanLoad("test.obj"));
|
||||
EXPECT_TRUE(loader.CanLoad("test.fbx"));
|
||||
EXPECT_TRUE(loader.CanLoad("test.gltf"));
|
||||
EXPECT_TRUE(loader.CanLoad("test.OBJ"));
|
||||
EXPECT_FALSE(loader.CanLoad("test.txt"));
|
||||
EXPECT_FALSE(loader.CanLoad("test.png"));
|
||||
}
|
||||
@@ -34,4 +41,61 @@ TEST(MeshLoader, LoadInvalidPath) {
|
||||
EXPECT_FALSE(result);
|
||||
}
|
||||
|
||||
TEST(MeshLoader, LoadValidObjMesh) {
|
||||
MeshLoader loader;
|
||||
const std::string path = GetMeshFixturePath("triangle.obj");
|
||||
|
||||
LoadResult result = loader.Load(path.c_str());
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_NE(result.resource, nullptr);
|
||||
|
||||
auto* mesh = static_cast<Mesh*>(result.resource);
|
||||
EXPECT_EQ(mesh->GetVertexCount(), 3u);
|
||||
EXPECT_EQ(mesh->GetIndexCount(), 3u);
|
||||
EXPECT_EQ(mesh->GetVertexStride(), sizeof(StaticMeshVertex));
|
||||
EXPECT_FALSE(mesh->IsUse32BitIndex());
|
||||
ASSERT_EQ(mesh->GetSections().Size(), 1u);
|
||||
EXPECT_EQ(mesh->GetSections()[0].vertexCount, 3u);
|
||||
EXPECT_EQ(mesh->GetSections()[0].indexCount, 3u);
|
||||
EXPECT_TRUE(HasVertexAttribute(mesh->GetVertexAttributes(), VertexAttribute::Position));
|
||||
EXPECT_TRUE(HasVertexAttribute(mesh->GetVertexAttributes(), VertexAttribute::Normal));
|
||||
EXPECT_TRUE(HasVertexAttribute(mesh->GetVertexAttributes(), VertexAttribute::UV0));
|
||||
|
||||
const auto* vertices = static_cast<const StaticMeshVertex*>(mesh->GetVertexData());
|
||||
ASSERT_NE(vertices, nullptr);
|
||||
EXPECT_FLOAT_EQ(vertices[0].position.x, 0.0f);
|
||||
EXPECT_FLOAT_EQ(vertices[0].position.y, 0.0f);
|
||||
EXPECT_FLOAT_EQ(vertices[0].position.z, -1.0f);
|
||||
EXPECT_FLOAT_EQ(vertices[0].normal.z, -1.0f);
|
||||
EXPECT_FLOAT_EQ(vertices[1].uv0.x, 1.0f);
|
||||
EXPECT_FLOAT_EQ(vertices[2].uv0.y, 1.0f);
|
||||
|
||||
delete mesh;
|
||||
}
|
||||
|
||||
TEST(MeshLoader, GeneratesNormalsAndTangentsWhenRequested) {
|
||||
MeshLoader loader;
|
||||
MeshImportSettings settings;
|
||||
settings.AddImportFlag(MeshImportFlags::GenerateNormals);
|
||||
settings.AddImportFlag(MeshImportFlags::GenerateTangents);
|
||||
|
||||
const std::string path = GetMeshFixturePath("triangle_no_normals.obj");
|
||||
LoadResult result = loader.Load(path.c_str(), &settings);
|
||||
ASSERT_TRUE(result);
|
||||
ASSERT_NE(result.resource, nullptr);
|
||||
|
||||
auto* mesh = static_cast<Mesh*>(result.resource);
|
||||
EXPECT_TRUE(HasVertexAttribute(mesh->GetVertexAttributes(), VertexAttribute::Normal));
|
||||
EXPECT_TRUE(HasVertexAttribute(mesh->GetVertexAttributes(), VertexAttribute::Tangent));
|
||||
EXPECT_TRUE(HasVertexAttribute(mesh->GetVertexAttributes(), VertexAttribute::Bitangent));
|
||||
|
||||
const auto* vertices = static_cast<const StaticMeshVertex*>(mesh->GetVertexData());
|
||||
ASSERT_NE(vertices, nullptr);
|
||||
EXPECT_GT(vertices[0].normal.Magnitude(), 0.0f);
|
||||
EXPECT_GT(vertices[0].tangent.Magnitude(), 0.0f);
|
||||
EXPECT_GT(vertices[0].bitangent.Magnitude(), 0.0f);
|
||||
|
||||
delete mesh;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user