Add renderer phase A textured scene path
This commit is contained in:
@@ -8,6 +8,7 @@ set(COMPONENTS_TEST_SOURCES
|
||||
test_transform_component.cpp
|
||||
test_game_object.cpp
|
||||
test_camera_light_component.cpp
|
||||
test_mesh_render_components.cpp
|
||||
)
|
||||
|
||||
add_executable(components_tests ${COMPONENTS_TEST_SOURCES})
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <XCEngine/Components/ComponentFactoryRegistry.h>
|
||||
#include <XCEngine/Components/GameObject.h>
|
||||
#include <XCEngine/Components/LightComponent.h>
|
||||
#include <XCEngine/Components/MeshFilterComponent.h>
|
||||
#include <XCEngine/Components/MeshRendererComponent.h>
|
||||
|
||||
using namespace XCEngine::Components;
|
||||
|
||||
@@ -18,6 +20,8 @@ TEST(ComponentFactoryRegistry_Test, BuiltInTypesAreRegistered) {
|
||||
EXPECT_TRUE(registry.IsRegistered("Light"));
|
||||
EXPECT_TRUE(registry.IsRegistered("AudioSource"));
|
||||
EXPECT_TRUE(registry.IsRegistered("AudioListener"));
|
||||
EXPECT_TRUE(registry.IsRegistered("MeshFilter"));
|
||||
EXPECT_TRUE(registry.IsRegistered("MeshRenderer"));
|
||||
EXPECT_FALSE(registry.IsRegistered("Transform"));
|
||||
EXPECT_FALSE(registry.IsRegistered("MissingComponent"));
|
||||
}
|
||||
@@ -30,6 +34,8 @@ TEST(ComponentFactoryRegistry_Test, CreateBuiltInComponentsByTypeName) {
|
||||
EXPECT_NE(dynamic_cast<LightComponent*>(registry.CreateComponent(&gameObject, "Light")), nullptr);
|
||||
EXPECT_NE(dynamic_cast<AudioSourceComponent*>(registry.CreateComponent(&gameObject, "AudioSource")), nullptr);
|
||||
EXPECT_NE(dynamic_cast<AudioListenerComponent*>(registry.CreateComponent(&gameObject, "AudioListener")), nullptr);
|
||||
EXPECT_NE(dynamic_cast<MeshFilterComponent*>(registry.CreateComponent(&gameObject, "MeshFilter")), nullptr);
|
||||
EXPECT_NE(dynamic_cast<MeshRendererComponent*>(registry.CreateComponent(&gameObject, "MeshRenderer")), nullptr);
|
||||
EXPECT_EQ(registry.CreateComponent(&gameObject, "MissingComponent"), nullptr);
|
||||
}
|
||||
|
||||
|
||||
125
tests/Components/test_mesh_render_components.cpp
Normal file
125
tests/Components/test_mesh_render_components.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <XCEngine/Components/GameObject.h>
|
||||
#include <XCEngine/Components/MeshFilterComponent.h>
|
||||
#include <XCEngine/Components/MeshRendererComponent.h>
|
||||
#include <XCEngine/Core/Asset/IResource.h>
|
||||
#include <XCEngine/Resources/Material/Material.h>
|
||||
#include <XCEngine/Resources/Mesh/Mesh.h>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
using namespace XCEngine::Components;
|
||||
using namespace XCEngine::Resources;
|
||||
|
||||
namespace {
|
||||
|
||||
Mesh* CreateTestMesh(const char* name, const char* path) {
|
||||
auto* mesh = new Mesh();
|
||||
IResource::ConstructParams params = {};
|
||||
params.name = name;
|
||||
params.path = path;
|
||||
params.guid = ResourceGUID::Generate(path);
|
||||
mesh->Initialize(params);
|
||||
return mesh;
|
||||
}
|
||||
|
||||
Material* CreateTestMaterial(const char* name, const char* path) {
|
||||
auto* material = new Material();
|
||||
IResource::ConstructParams params = {};
|
||||
params.name = name;
|
||||
params.path = path;
|
||||
params.guid = ResourceGUID::Generate(path);
|
||||
material->Initialize(params);
|
||||
return material;
|
||||
}
|
||||
|
||||
TEST(MeshFilterComponent_Test, SetMeshCachesResourceAndPath) {
|
||||
GameObject gameObject("MeshHolder");
|
||||
auto* component = gameObject.AddComponent<MeshFilterComponent>();
|
||||
Mesh* mesh = CreateTestMesh("Quad", "Meshes/quad.mesh");
|
||||
|
||||
component->SetMesh(mesh);
|
||||
|
||||
EXPECT_EQ(component->GetMesh(), mesh);
|
||||
EXPECT_EQ(component->GetMeshPath(), "Meshes/quad.mesh");
|
||||
|
||||
component->ClearMesh();
|
||||
delete mesh;
|
||||
}
|
||||
|
||||
TEST(MeshFilterComponent_Test, SerializeAndDeserializePreservesPath) {
|
||||
MeshFilterComponent source;
|
||||
Mesh* mesh = CreateTestMesh("Quad", "Meshes/serialized.mesh");
|
||||
source.SetMesh(mesh);
|
||||
|
||||
std::stringstream stream;
|
||||
source.Serialize(stream);
|
||||
|
||||
MeshFilterComponent target;
|
||||
target.Deserialize(stream);
|
||||
|
||||
EXPECT_EQ(target.GetMeshPath(), "Meshes/serialized.mesh");
|
||||
EXPECT_EQ(target.GetMesh(), nullptr);
|
||||
|
||||
source.ClearMesh();
|
||||
delete mesh;
|
||||
}
|
||||
|
||||
TEST(MeshRendererComponent_Test, SetMaterialsKeepsSlotsAndFlags) {
|
||||
GameObject gameObject("RendererHolder");
|
||||
auto* component = gameObject.AddComponent<MeshRendererComponent>();
|
||||
Material* material0 = CreateTestMaterial("M0", "Materials/m0.mat");
|
||||
Material* material1 = CreateTestMaterial("M1", "Materials/m1.mat");
|
||||
|
||||
component->SetMaterial(0, material0);
|
||||
component->SetMaterial(1, material1);
|
||||
component->SetCastShadows(false);
|
||||
component->SetReceiveShadows(false);
|
||||
component->SetRenderLayer(7);
|
||||
|
||||
ASSERT_EQ(component->GetMaterialCount(), 2u);
|
||||
EXPECT_EQ(component->GetMaterial(0), material0);
|
||||
EXPECT_EQ(component->GetMaterial(1), material1);
|
||||
EXPECT_EQ(component->GetMaterialPaths()[0], "Materials/m0.mat");
|
||||
EXPECT_EQ(component->GetMaterialPaths()[1], "Materials/m1.mat");
|
||||
EXPECT_FALSE(component->GetCastShadows());
|
||||
EXPECT_FALSE(component->GetReceiveShadows());
|
||||
EXPECT_EQ(component->GetRenderLayer(), 7u);
|
||||
|
||||
component->ClearMaterials();
|
||||
delete material0;
|
||||
delete material1;
|
||||
}
|
||||
|
||||
TEST(MeshRendererComponent_Test, SerializeAndDeserializePreservesMaterialPathsAndSettings) {
|
||||
MeshRendererComponent source;
|
||||
Material* material0 = CreateTestMaterial("M0", "Materials/serialized0.mat");
|
||||
Material* material1 = CreateTestMaterial("M1", "Materials/serialized1.mat");
|
||||
source.SetMaterial(0, material0);
|
||||
source.SetMaterial(1, material1);
|
||||
source.SetCastShadows(false);
|
||||
source.SetReceiveShadows(true);
|
||||
source.SetRenderLayer(3);
|
||||
|
||||
std::stringstream stream;
|
||||
source.Serialize(stream);
|
||||
|
||||
MeshRendererComponent target;
|
||||
target.Deserialize(stream);
|
||||
|
||||
ASSERT_EQ(target.GetMaterialCount(), 2u);
|
||||
EXPECT_EQ(target.GetMaterial(0), nullptr);
|
||||
EXPECT_EQ(target.GetMaterial(1), nullptr);
|
||||
EXPECT_EQ(target.GetMaterialPaths()[0], "Materials/serialized0.mat");
|
||||
EXPECT_EQ(target.GetMaterialPaths()[1], "Materials/serialized1.mat");
|
||||
EXPECT_FALSE(target.GetCastShadows());
|
||||
EXPECT_TRUE(target.GetReceiveShadows());
|
||||
EXPECT_EQ(target.GetRenderLayer(), 3u);
|
||||
|
||||
source.ClearMaterials();
|
||||
delete material0;
|
||||
delete material1;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
6
tests/Rendering/CMakeLists.txt
Normal file
6
tests/Rendering/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
project(XCEngine_RenderingTests)
|
||||
|
||||
add_subdirectory(unit)
|
||||
add_subdirectory(integration)
|
||||
5
tests/Rendering/integration/CMakeLists.txt
Normal file
5
tests/Rendering/integration/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
project(XCEngine_RenderingIntegrationTests)
|
||||
|
||||
add_subdirectory(textured_quad_scene)
|
||||
@@ -0,0 +1,56 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
project(rendering_integration_textured_quad_scene)
|
||||
|
||||
set(ENGINE_ROOT_DIR ${CMAKE_SOURCE_DIR}/engine)
|
||||
set(PACKAGE_DIR ${CMAKE_SOURCE_DIR}/tests/opengl/package)
|
||||
|
||||
get_filename_component(PROJECT_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../.. ABSOLUTE)
|
||||
|
||||
add_executable(rendering_integration_textured_quad_scene
|
||||
main.cpp
|
||||
${CMAKE_SOURCE_DIR}/tests/RHI/integration/fixtures/RHIIntegrationFixture.cpp
|
||||
${PACKAGE_DIR}/src/glad.c
|
||||
)
|
||||
|
||||
target_include_directories(rendering_integration_textured_quad_scene PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_SOURCE_DIR}/tests/RHI/integration/fixtures
|
||||
${ENGINE_ROOT_DIR}/include
|
||||
${PACKAGE_DIR}/include
|
||||
${PROJECT_ROOT_DIR}/engine/src
|
||||
)
|
||||
|
||||
target_link_libraries(rendering_integration_textured_quad_scene PRIVATE
|
||||
d3d12
|
||||
dxgi
|
||||
d3dcompiler
|
||||
winmm
|
||||
opengl32
|
||||
XCEngine
|
||||
GTest::gtest
|
||||
)
|
||||
|
||||
target_compile_definitions(rendering_integration_textured_quad_scene PRIVATE
|
||||
UNICODE
|
||||
_UNICODE
|
||||
XCENGINE_SUPPORT_OPENGL
|
||||
XCENGINE_SUPPORT_D3D12
|
||||
)
|
||||
|
||||
add_custom_command(TARGET rendering_integration_textured_quad_scene POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${CMAKE_SOURCE_DIR}/tests/RHI/integration/compare_ppm.py
|
||||
$<TARGET_FILE_DIR:rendering_integration_textured_quad_scene>/
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/GT.ppm
|
||||
$<TARGET_FILE_DIR:rendering_integration_textured_quad_scene>/GT.ppm
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${ENGINE_ROOT_DIR}/third_party/renderdoc/renderdoc.dll
|
||||
$<TARGET_FILE_DIR:rendering_integration_textured_quad_scene>/
|
||||
)
|
||||
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(rendering_integration_textured_quad_scene)
|
||||
4
tests/Rendering/integration/textured_quad_scene/GT.ppm
Normal file
4
tests/Rendering/integration/textured_quad_scene/GT.ppm
Normal file
File diff suppressed because one or more lines are too long
272
tests/Rendering/integration/textured_quad_scene/main.cpp
Normal file
272
tests/Rendering/integration/textured_quad_scene/main.cpp
Normal file
@@ -0,0 +1,272 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <XCEngine/Components/CameraComponent.h>
|
||||
#include <XCEngine/Components/GameObject.h>
|
||||
#include <XCEngine/Components/MeshFilterComponent.h>
|
||||
#include <XCEngine/Components/MeshRendererComponent.h>
|
||||
#include <XCEngine/Core/Asset/IResource.h>
|
||||
#include <XCEngine/Core/Math/Color.h>
|
||||
#include <XCEngine/Core/Math/Vector2.h>
|
||||
#include <XCEngine/Core/Math/Vector3.h>
|
||||
#include <XCEngine/Debug/ConsoleLogSink.h>
|
||||
#include <XCEngine/Debug/Logger.h>
|
||||
#include <XCEngine/Rendering/RenderContext.h>
|
||||
#include <XCEngine/Rendering/RenderSurface.h>
|
||||
#include <XCEngine/Rendering/SceneRenderer.h>
|
||||
#include <XCEngine/Resources/Material/Material.h>
|
||||
#include <XCEngine/Resources/Mesh/Mesh.h>
|
||||
#include <XCEngine/Resources/Texture/Texture.h>
|
||||
#include <XCEngine/Scene/Scene.h>
|
||||
|
||||
#include "../../../RHI/integration/fixtures/RHIIntegrationFixture.h"
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
using namespace XCEngine::Components;
|
||||
using namespace XCEngine::Debug;
|
||||
using namespace XCEngine::Math;
|
||||
using namespace XCEngine::Rendering;
|
||||
using namespace XCEngine::Resources;
|
||||
using namespace XCEngine::RHI;
|
||||
using namespace XCEngine::RHI::Integration;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char* kD3D12Screenshot = "textured_quad_scene_d3d12.ppm";
|
||||
constexpr const char* kOpenGLScreenshot = "textured_quad_scene_opengl.ppm";
|
||||
|
||||
Mesh* CreateQuadMesh() {
|
||||
auto* mesh = new Mesh();
|
||||
IResource::ConstructParams params = {};
|
||||
params.name = "TexturedQuad";
|
||||
params.path = "Tests/Rendering/TexturedQuad.mesh";
|
||||
params.guid = ResourceGUID::Generate(params.path);
|
||||
mesh->Initialize(params);
|
||||
|
||||
StaticMeshVertex vertices[4] = {};
|
||||
vertices[0].position = Vector3(-1.0f, -1.0f, 0.0f);
|
||||
vertices[0].uv0 = Vector2(0.0f, 1.0f);
|
||||
vertices[1].position = Vector3(-1.0f, 1.0f, 0.0f);
|
||||
vertices[1].uv0 = Vector2(0.0f, 0.0f);
|
||||
vertices[2].position = Vector3(1.0f, -1.0f, 0.0f);
|
||||
vertices[2].uv0 = Vector2(1.0f, 1.0f);
|
||||
vertices[3].position = Vector3(1.0f, 1.0f, 0.0f);
|
||||
vertices[3].uv0 = Vector2(1.0f, 0.0f);
|
||||
|
||||
const uint32_t indices[6] = { 0, 1, 2, 2, 1, 3 };
|
||||
mesh->SetVertexData(
|
||||
vertices,
|
||||
sizeof(vertices),
|
||||
4,
|
||||
sizeof(StaticMeshVertex),
|
||||
VertexAttribute::Position | VertexAttribute::UV0);
|
||||
mesh->SetIndexData(indices, sizeof(indices), 6, true);
|
||||
|
||||
MeshSection section = {};
|
||||
section.baseVertex = 0;
|
||||
section.vertexCount = 4;
|
||||
section.startIndex = 0;
|
||||
section.indexCount = 6;
|
||||
section.materialID = 0;
|
||||
mesh->AddSection(section);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
Texture* CreateCheckerTexture() {
|
||||
auto* texture = new Texture();
|
||||
IResource::ConstructParams params = {};
|
||||
params.name = "Checker";
|
||||
params.path = "Tests/Rendering/Checker.texture";
|
||||
params.guid = ResourceGUID::Generate(params.path);
|
||||
texture->Initialize(params);
|
||||
|
||||
const unsigned char pixels[16] = {
|
||||
255, 32, 32, 255,
|
||||
32, 255, 32, 255,
|
||||
32, 32, 255, 255,
|
||||
255, 255, 32, 255
|
||||
};
|
||||
texture->Create(
|
||||
2,
|
||||
2,
|
||||
1,
|
||||
1,
|
||||
XCEngine::Resources::TextureType::Texture2D,
|
||||
XCEngine::Resources::TextureFormat::RGBA8_UNORM,
|
||||
pixels,
|
||||
sizeof(pixels));
|
||||
return texture;
|
||||
}
|
||||
|
||||
Material* CreateMaterial(Texture* texture) {
|
||||
auto* material = new Material();
|
||||
IResource::ConstructParams params = {};
|
||||
params.name = "QuadMaterial";
|
||||
params.path = "Tests/Rendering/Quad.material";
|
||||
params.guid = ResourceGUID::Generate(params.path);
|
||||
material->Initialize(params);
|
||||
material->SetTexture("_BaseColorTexture", ResourceHandle<Texture>(texture));
|
||||
return material;
|
||||
}
|
||||
|
||||
const char* GetScreenshotFilename(RHIType backendType) {
|
||||
return backendType == RHIType::D3D12 ? kD3D12Screenshot : kOpenGLScreenshot;
|
||||
}
|
||||
|
||||
int GetComparisonThreshold(RHIType backendType) {
|
||||
return backendType == RHIType::OpenGL ? 5 : 0;
|
||||
}
|
||||
|
||||
class TexturedQuadSceneTest : public RHIIntegrationFixture {
|
||||
protected:
|
||||
void SetUp() override;
|
||||
void TearDown() override;
|
||||
void RenderFrame() override;
|
||||
|
||||
private:
|
||||
RHIResourceView* GetCurrentBackBufferView();
|
||||
|
||||
std::unique_ptr<Scene> mScene;
|
||||
std::unique_ptr<SceneRenderer> mSceneRenderer;
|
||||
std::vector<RHIResourceView*> mBackBufferViews;
|
||||
Mesh* mMesh = nullptr;
|
||||
Material* mMaterial = nullptr;
|
||||
Texture* mTexture = nullptr;
|
||||
};
|
||||
|
||||
void TexturedQuadSceneTest::SetUp() {
|
||||
RHIIntegrationFixture::SetUp();
|
||||
|
||||
mSceneRenderer = std::make_unique<SceneRenderer>();
|
||||
mScene = std::make_unique<Scene>("TexturedQuadScene");
|
||||
|
||||
mMesh = CreateQuadMesh();
|
||||
mTexture = CreateCheckerTexture();
|
||||
mMaterial = CreateMaterial(mTexture);
|
||||
|
||||
GameObject* cameraObject = mScene->CreateGameObject("MainCamera");
|
||||
auto* camera = cameraObject->AddComponent<CameraComponent>();
|
||||
camera->SetPrimary(true);
|
||||
camera->SetClearColor(XCEngine::Math::Color(0.08f, 0.08f, 0.10f, 1.0f));
|
||||
|
||||
GameObject* quadObject = mScene->CreateGameObject("Quad");
|
||||
quadObject->GetTransform()->SetLocalPosition(Vector3(0.0f, 0.0f, 3.0f));
|
||||
auto* meshFilter = quadObject->AddComponent<MeshFilterComponent>();
|
||||
auto* meshRenderer = quadObject->AddComponent<MeshRendererComponent>();
|
||||
meshFilter->SetMesh(ResourceHandle<Mesh>(mMesh));
|
||||
meshRenderer->SetMaterial(0, ResourceHandle<Material>(mMaterial));
|
||||
|
||||
mBackBufferViews.resize(2, nullptr);
|
||||
}
|
||||
|
||||
void TexturedQuadSceneTest::TearDown() {
|
||||
mSceneRenderer.reset();
|
||||
|
||||
for (RHIResourceView*& backBufferView : mBackBufferViews) {
|
||||
if (backBufferView != nullptr) {
|
||||
backBufferView->Shutdown();
|
||||
delete backBufferView;
|
||||
backBufferView = nullptr;
|
||||
}
|
||||
}
|
||||
mBackBufferViews.clear();
|
||||
|
||||
mScene.reset();
|
||||
|
||||
delete mMaterial;
|
||||
mMaterial = nullptr;
|
||||
delete mMesh;
|
||||
mMesh = nullptr;
|
||||
delete mTexture;
|
||||
mTexture = nullptr;
|
||||
|
||||
RHIIntegrationFixture::TearDown();
|
||||
}
|
||||
|
||||
RHIResourceView* TexturedQuadSceneTest::GetCurrentBackBufferView() {
|
||||
const int backBufferIndex = GetCurrentBackBufferIndex();
|
||||
if (backBufferIndex < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (static_cast<size_t>(backBufferIndex) >= mBackBufferViews.size()) {
|
||||
mBackBufferViews.resize(static_cast<size_t>(backBufferIndex) + 1, nullptr);
|
||||
}
|
||||
|
||||
if (mBackBufferViews[backBufferIndex] == nullptr) {
|
||||
ResourceViewDesc viewDesc = {};
|
||||
viewDesc.format = static_cast<uint32_t>(Format::R8G8B8A8_UNorm);
|
||||
viewDesc.dimension = ResourceViewDimension::Texture2D;
|
||||
viewDesc.mipLevel = 0;
|
||||
mBackBufferViews[backBufferIndex] = GetDevice()->CreateRenderTargetView(GetCurrentBackBuffer(), viewDesc);
|
||||
}
|
||||
|
||||
return mBackBufferViews[backBufferIndex];
|
||||
}
|
||||
|
||||
void TexturedQuadSceneTest::RenderFrame() {
|
||||
ASSERT_NE(mScene, nullptr);
|
||||
ASSERT_NE(mSceneRenderer, nullptr);
|
||||
|
||||
RHICommandList* commandList = GetCommandList();
|
||||
ASSERT_NE(commandList, nullptr);
|
||||
|
||||
commandList->Reset();
|
||||
|
||||
RenderSurface surface(1280, 720);
|
||||
surface.SetColorAttachment(GetCurrentBackBufferView());
|
||||
|
||||
RenderContext renderContext = {};
|
||||
renderContext.device = GetDevice();
|
||||
renderContext.commandList = commandList;
|
||||
renderContext.commandQueue = GetCommandQueue();
|
||||
renderContext.backendType = GetBackendType();
|
||||
|
||||
ASSERT_TRUE(mSceneRenderer->Render(*mScene, nullptr, renderContext, surface));
|
||||
|
||||
commandList->Close();
|
||||
void* commandLists[] = { commandList };
|
||||
GetCommandQueue()->ExecuteCommandLists(1, commandLists);
|
||||
}
|
||||
|
||||
TEST_P(TexturedQuadSceneTest, RenderTexturedQuadScene) {
|
||||
RHICommandQueue* commandQueue = GetCommandQueue();
|
||||
RHISwapChain* swapChain = GetSwapChain();
|
||||
const int targetFrameCount = 30;
|
||||
const char* screenshotFilename = GetScreenshotFilename(GetBackendType());
|
||||
const int comparisonThreshold = GetComparisonThreshold(GetBackendType());
|
||||
|
||||
for (int frameCount = 0; frameCount <= targetFrameCount; ++frameCount) {
|
||||
if (frameCount > 0) {
|
||||
commandQueue->WaitForPreviousFrame();
|
||||
}
|
||||
|
||||
BeginRender();
|
||||
RenderFrame();
|
||||
|
||||
if (frameCount >= targetFrameCount) {
|
||||
commandQueue->WaitForIdle();
|
||||
ASSERT_TRUE(TakeScreenshot(screenshotFilename));
|
||||
ASSERT_TRUE(CompareWithGoldenTemplate(screenshotFilename, "GT.ppm", static_cast<float>(comparisonThreshold)));
|
||||
break;
|
||||
}
|
||||
|
||||
swapChain->Present(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(D3D12, TexturedQuadSceneTest, ::testing::Values(RHIType::D3D12));
|
||||
INSTANTIATE_TEST_SUITE_P(OpenGL, TexturedQuadSceneTest, ::testing::Values(RHIType::OpenGL));
|
||||
|
||||
GTEST_API_ int main(int argc, char** argv) {
|
||||
Logger::Get().Initialize();
|
||||
Logger::Get().AddSink(std::make_unique<ConsoleLogSink>());
|
||||
Logger::Get().SetMinimumLevel(LogLevel::Debug);
|
||||
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
28
tests/Rendering/unit/CMakeLists.txt
Normal file
28
tests/Rendering/unit/CMakeLists.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
project(XCEngine_RenderingUnitTests)
|
||||
|
||||
set(RENDERING_UNIT_TEST_SOURCES
|
||||
test_render_scene_extractor.cpp
|
||||
)
|
||||
|
||||
add_executable(rendering_unit_tests ${RENDERING_UNIT_TEST_SOURCES})
|
||||
|
||||
if(MSVC)
|
||||
set_target_properties(rendering_unit_tests PROPERTIES
|
||||
LINK_FLAGS "/NODEFAULTLIB:libcpmt.lib /NODEFAULTLIB:libcmt.lib"
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(rendering_unit_tests PRIVATE
|
||||
XCEngine
|
||||
GTest::gtest
|
||||
GTest::gtest_main
|
||||
)
|
||||
|
||||
target_include_directories(rendering_unit_tests PRIVATE
|
||||
${CMAKE_SOURCE_DIR}/engine/include
|
||||
)
|
||||
|
||||
include(GoogleTest)
|
||||
gtest_discover_tests(rendering_unit_tests)
|
||||
101
tests/Rendering/unit/test_render_scene_extractor.cpp
Normal file
101
tests/Rendering/unit/test_render_scene_extractor.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <XCEngine/Components/CameraComponent.h>
|
||||
#include <XCEngine/Components/GameObject.h>
|
||||
#include <XCEngine/Components/MeshFilterComponent.h>
|
||||
#include <XCEngine/Components/MeshRendererComponent.h>
|
||||
#include <XCEngine/Core/Asset/IResource.h>
|
||||
#include <XCEngine/Core/Math/Vector3.h>
|
||||
#include <XCEngine/Rendering/RenderSceneExtractor.h>
|
||||
#include <XCEngine/Scene/Scene.h>
|
||||
#include <XCEngine/Resources/Mesh/Mesh.h>
|
||||
|
||||
using namespace XCEngine::Components;
|
||||
using namespace XCEngine::Math;
|
||||
using namespace XCEngine::Rendering;
|
||||
using namespace XCEngine::Resources;
|
||||
|
||||
namespace {
|
||||
|
||||
Mesh* CreateTestMesh(const char* path) {
|
||||
auto* mesh = new Mesh();
|
||||
IResource::ConstructParams params = {};
|
||||
params.name = "TestMesh";
|
||||
params.path = path;
|
||||
params.guid = ResourceGUID::Generate(path);
|
||||
mesh->Initialize(params);
|
||||
return mesh;
|
||||
}
|
||||
|
||||
TEST(RenderSceneExtractor_Test, SelectsHighestDepthPrimaryCameraAndVisibleObjects) {
|
||||
Scene scene("RenderScene");
|
||||
|
||||
GameObject* cameraObjectA = scene.CreateGameObject("CameraA");
|
||||
auto* cameraA = cameraObjectA->AddComponent<CameraComponent>();
|
||||
cameraA->SetPrimary(true);
|
||||
cameraA->SetDepth(0.0f);
|
||||
|
||||
GameObject* cameraObjectB = scene.CreateGameObject("CameraB");
|
||||
auto* cameraB = cameraObjectB->AddComponent<CameraComponent>();
|
||||
cameraB->SetPrimary(true);
|
||||
cameraB->SetDepth(5.0f);
|
||||
cameraObjectB->GetTransform()->SetLocalPosition(Vector3(2.0f, 3.0f, 4.0f));
|
||||
|
||||
GameObject* visibleObject = scene.CreateGameObject("VisibleQuad");
|
||||
visibleObject->GetTransform()->SetLocalPosition(Vector3(1.0f, 2.0f, 3.0f));
|
||||
auto* meshFilter = visibleObject->AddComponent<MeshFilterComponent>();
|
||||
visibleObject->AddComponent<MeshRendererComponent>();
|
||||
Mesh* visibleMesh = CreateTestMesh("Meshes/visible.mesh");
|
||||
meshFilter->SetMesh(visibleMesh);
|
||||
|
||||
GameObject* hiddenObject = scene.CreateGameObject("HiddenQuad");
|
||||
hiddenObject->SetActive(false);
|
||||
auto* hiddenMeshFilter = hiddenObject->AddComponent<MeshFilterComponent>();
|
||||
hiddenObject->AddComponent<MeshRendererComponent>();
|
||||
Mesh* hiddenMesh = CreateTestMesh("Meshes/hidden.mesh");
|
||||
hiddenMeshFilter->SetMesh(hiddenMesh);
|
||||
|
||||
RenderSceneExtractor extractor;
|
||||
const RenderSceneData sceneData = extractor.Extract(scene, nullptr, 1280, 720);
|
||||
|
||||
ASSERT_TRUE(sceneData.HasCamera());
|
||||
EXPECT_EQ(sceneData.camera, cameraB);
|
||||
EXPECT_EQ(sceneData.cameraData.viewportWidth, 1280u);
|
||||
EXPECT_EQ(sceneData.cameraData.viewportHeight, 720u);
|
||||
EXPECT_EQ(sceneData.cameraData.worldPosition, Vector3(2.0f, 3.0f, 4.0f));
|
||||
|
||||
ASSERT_EQ(sceneData.visibleObjects.size(), 1u);
|
||||
EXPECT_EQ(sceneData.visibleObjects[0].gameObject, visibleObject);
|
||||
EXPECT_EQ(sceneData.visibleObjects[0].mesh, visibleMesh);
|
||||
EXPECT_EQ(sceneData.visibleObjects[0].localToWorld.GetTranslation(), Vector3(1.0f, 2.0f, 3.0f));
|
||||
|
||||
meshFilter->ClearMesh();
|
||||
hiddenMeshFilter->ClearMesh();
|
||||
delete visibleMesh;
|
||||
delete hiddenMesh;
|
||||
}
|
||||
|
||||
TEST(RenderSceneExtractor_Test, OverrideCameraTakesPriority) {
|
||||
Scene scene("OverrideScene");
|
||||
|
||||
GameObject* primaryObject = scene.CreateGameObject("PrimaryCamera");
|
||||
auto* primaryCamera = primaryObject->AddComponent<CameraComponent>();
|
||||
primaryCamera->SetPrimary(true);
|
||||
primaryCamera->SetDepth(10.0f);
|
||||
|
||||
GameObject* overrideObject = scene.CreateGameObject("OverrideCamera");
|
||||
auto* overrideCamera = overrideObject->AddComponent<CameraComponent>();
|
||||
overrideCamera->SetPrimary(false);
|
||||
overrideCamera->SetDepth(-1.0f);
|
||||
|
||||
RenderSceneExtractor extractor;
|
||||
const RenderSceneData sceneData = extractor.Extract(scene, overrideCamera, 640, 480);
|
||||
|
||||
ASSERT_TRUE(sceneData.HasCamera());
|
||||
EXPECT_EQ(sceneData.camera, overrideCamera);
|
||||
EXPECT_NE(sceneData.camera, primaryCamera);
|
||||
EXPECT_EQ(sceneData.cameraData.viewportWidth, 640u);
|
||||
EXPECT_EQ(sceneData.cameraData.viewportHeight, 480u);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user