Add NanoVDB volume test scaffolding
This commit is contained in:
209
engine/include/XCEngine/Rendering/Passes/BuiltinVolumetricPass.h
Normal file
209
engine/include/XCEngine/Rendering/Passes/BuiltinVolumetricPass.h
Normal file
@@ -0,0 +1,209 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <XCEngine/Core/Asset/ResourceHandle.h>
|
||||||
|
#include <XCEngine/Core/Math/Matrix4.h>
|
||||||
|
#include <XCEngine/Rendering/Builtin/BuiltinPassTypes.h>
|
||||||
|
#include <XCEngine/Rendering/Caches/RenderResourceCache.h>
|
||||||
|
#include <XCEngine/Rendering/Materials/RenderMaterialResolve.h>
|
||||||
|
#include <XCEngine/Rendering/Materials/RenderMaterialStateUtils.h>
|
||||||
|
#include <XCEngine/Rendering/RenderPass.h>
|
||||||
|
#include <XCEngine/RHI/RHIDescriptorPool.h>
|
||||||
|
#include <XCEngine/RHI/RHIDescriptorSet.h>
|
||||||
|
#include <XCEngine/RHI/RHIPipelineLayout.h>
|
||||||
|
#include <XCEngine/RHI/RHIPipelineState.h>
|
||||||
|
#include <XCEngine/Resources/Mesh/Mesh.h>
|
||||||
|
#include <XCEngine/Resources/Shader/Shader.h>
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace XCEngine {
|
||||||
|
namespace Components {
|
||||||
|
class GameObject;
|
||||||
|
} // namespace Components
|
||||||
|
|
||||||
|
namespace Resources {
|
||||||
|
class Material;
|
||||||
|
class VolumeField;
|
||||||
|
} // namespace Resources
|
||||||
|
|
||||||
|
namespace Rendering {
|
||||||
|
struct VisibleVolumeItem;
|
||||||
|
|
||||||
|
namespace Passes {
|
||||||
|
|
||||||
|
class BuiltinVolumetricPass final : public RenderPass {
|
||||||
|
public:
|
||||||
|
~BuiltinVolumetricPass() override;
|
||||||
|
|
||||||
|
static RHI::InputLayoutDesc BuildInputLayout();
|
||||||
|
|
||||||
|
const char* GetName() const override;
|
||||||
|
bool Initialize(const RenderContext& context) override;
|
||||||
|
bool Execute(const RenderPassContext& context) override;
|
||||||
|
void Shutdown() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct PerObjectConstants {
|
||||||
|
Math::Matrix4x4 projection = Math::Matrix4x4::Identity();
|
||||||
|
Math::Matrix4x4 view = Math::Matrix4x4::Identity();
|
||||||
|
Math::Matrix4x4 model = Math::Matrix4x4::Identity();
|
||||||
|
Math::Matrix4x4 inverseModel = Math::Matrix4x4::Identity();
|
||||||
|
Math::Vector4 cameraWorldPosition = Math::Vector4::Zero();
|
||||||
|
Math::Vector4 localBoundsMin = Math::Vector4::Zero();
|
||||||
|
Math::Vector4 localBoundsMax = Math::Vector4::Zero();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct OwnedDescriptorSet {
|
||||||
|
RHI::RHIDescriptorPool* pool = nullptr;
|
||||||
|
RHI::RHIDescriptorSet* set = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassLayoutKey {
|
||||||
|
const Resources::Shader* shader = nullptr;
|
||||||
|
Containers::String passName;
|
||||||
|
|
||||||
|
bool operator==(const PassLayoutKey& other) const {
|
||||||
|
return shader == other.shader && passName == other.passName;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassLayoutKeyHash {
|
||||||
|
size_t operator()(const PassLayoutKey& key) const noexcept {
|
||||||
|
size_t hash = reinterpret_cast<size_t>(key.shader);
|
||||||
|
hash ^= std::hash<Containers::String>{}(key.passName) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PassResourceLayout {
|
||||||
|
RHI::RHIPipelineLayout* pipelineLayout = nullptr;
|
||||||
|
Core::uint32 firstDescriptorSet = 0;
|
||||||
|
Core::uint32 descriptorSetCount = 0;
|
||||||
|
std::vector<BuiltinPassSetLayoutMetadata> setLayouts;
|
||||||
|
PassResourceBindingLocation perObject = {};
|
||||||
|
PassResourceBindingLocation material = {};
|
||||||
|
PassResourceBindingLocation volumeField = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DynamicDescriptorSetKey {
|
||||||
|
PassLayoutKey passLayout = {};
|
||||||
|
Core::uint32 setIndex = 0;
|
||||||
|
Core::uint64 objectId = 0;
|
||||||
|
const Resources::Material* material = nullptr;
|
||||||
|
const Resources::VolumeField* volumeField = nullptr;
|
||||||
|
|
||||||
|
bool operator==(const DynamicDescriptorSetKey& other) const {
|
||||||
|
return passLayout == other.passLayout &&
|
||||||
|
setIndex == other.setIndex &&
|
||||||
|
objectId == other.objectId &&
|
||||||
|
material == other.material &&
|
||||||
|
volumeField == other.volumeField;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DynamicDescriptorSetKeyHash {
|
||||||
|
size_t operator()(const DynamicDescriptorSetKey& key) const noexcept {
|
||||||
|
size_t hash = PassLayoutKeyHash()(key.passLayout);
|
||||||
|
hash ^= std::hash<Core::uint32>{}(key.setIndex) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||||
|
hash ^= std::hash<Core::uint64>{}(key.objectId) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||||
|
hash ^= reinterpret_cast<size_t>(key.material) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||||
|
hash ^= reinterpret_cast<size_t>(key.volumeField) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CachedDescriptorSet {
|
||||||
|
OwnedDescriptorSet descriptorSet = {};
|
||||||
|
Core::uint64 materialVersion = 0;
|
||||||
|
RHI::RHIResourceView* volumeFieldView = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ResolvedShaderPass {
|
||||||
|
const Resources::Shader* shader = nullptr;
|
||||||
|
const Resources::ShaderPass* pass = nullptr;
|
||||||
|
Containers::String passName;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PipelineStateKey {
|
||||||
|
Resources::MaterialRenderState renderState;
|
||||||
|
const Resources::Shader* shader = nullptr;
|
||||||
|
Containers::String passName;
|
||||||
|
Containers::String keywordSignature;
|
||||||
|
uint32_t renderTargetCount = 0;
|
||||||
|
uint32_t renderTargetFormat = 0;
|
||||||
|
uint32_t depthStencilFormat = 0;
|
||||||
|
|
||||||
|
bool operator==(const PipelineStateKey& other) const {
|
||||||
|
return renderState == other.renderState &&
|
||||||
|
shader == other.shader &&
|
||||||
|
passName == other.passName &&
|
||||||
|
keywordSignature == other.keywordSignature &&
|
||||||
|
renderTargetCount == other.renderTargetCount &&
|
||||||
|
renderTargetFormat == other.renderTargetFormat &&
|
||||||
|
depthStencilFormat == other.depthStencilFormat;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PipelineStateKeyHash {
|
||||||
|
size_t operator()(const PipelineStateKey& key) const noexcept {
|
||||||
|
size_t hash = MaterialRenderStateHash()(key.renderState);
|
||||||
|
hash ^= reinterpret_cast<size_t>(key.shader) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||||
|
hash ^= std::hash<Containers::String>{}(key.passName) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||||
|
hash ^= std::hash<Containers::String>{}(key.keywordSignature) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||||
|
hash ^= std::hash<uint32_t>{}(key.renderTargetCount) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||||
|
hash ^= std::hash<uint32_t>{}(key.renderTargetFormat) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||||
|
hash ^= std::hash<uint32_t>{}(key.depthStencilFormat) + 0x9e3779b9u + (hash << 6) + (hash >> 2);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool EnsureInitialized(const RenderContext& context);
|
||||||
|
bool CreateResources(const RenderContext& context);
|
||||||
|
void DestroyResources();
|
||||||
|
|
||||||
|
ResolvedShaderPass ResolveVolumeShaderPass(
|
||||||
|
const RenderSceneData& sceneData,
|
||||||
|
const Resources::Material* material) const;
|
||||||
|
PassResourceLayout* GetOrCreatePassResourceLayout(
|
||||||
|
const RenderContext& context,
|
||||||
|
const ResolvedShaderPass& resolvedShaderPass);
|
||||||
|
RHI::RHIPipelineState* GetOrCreatePipelineState(
|
||||||
|
const RenderContext& context,
|
||||||
|
const RenderSurface& surface,
|
||||||
|
const RenderSceneData& sceneData,
|
||||||
|
const Resources::Material* material);
|
||||||
|
bool CreateOwnedDescriptorSet(
|
||||||
|
const BuiltinPassSetLayoutMetadata& setLayout,
|
||||||
|
OwnedDescriptorSet& descriptorSet);
|
||||||
|
CachedDescriptorSet* GetOrCreateDynamicDescriptorSet(
|
||||||
|
const PassLayoutKey& passLayoutKey,
|
||||||
|
const PassResourceLayout& passLayout,
|
||||||
|
const BuiltinPassSetLayoutMetadata& setLayout,
|
||||||
|
Core::uint32 setIndex,
|
||||||
|
Core::uint64 objectId,
|
||||||
|
const Resources::Material* material,
|
||||||
|
const Resources::VolumeField* volumeField,
|
||||||
|
const MaterialConstantPayloadView& materialConstants,
|
||||||
|
RHI::RHIResourceView* volumeFieldView);
|
||||||
|
void DestroyOwnedDescriptorSet(OwnedDescriptorSet& descriptorSet);
|
||||||
|
void DestroyPassResourceLayout(PassResourceLayout& passLayout);
|
||||||
|
bool DrawVisibleVolume(
|
||||||
|
const RenderContext& context,
|
||||||
|
const RenderSurface& surface,
|
||||||
|
const RenderSceneData& sceneData,
|
||||||
|
const VisibleVolumeItem& visibleVolume);
|
||||||
|
|
||||||
|
RHI::RHIDevice* m_device = nullptr;
|
||||||
|
RHI::RHIType m_backendType = RHI::RHIType::D3D12;
|
||||||
|
Resources::ResourceHandle<Resources::Mesh> m_builtinCubeMesh;
|
||||||
|
RenderResourceCache m_resourceCache;
|
||||||
|
|
||||||
|
std::unordered_map<PassLayoutKey, PassResourceLayout, PassLayoutKeyHash> m_passResourceLayouts;
|
||||||
|
std::unordered_map<PipelineStateKey, RHI::RHIPipelineState*, PipelineStateKeyHash> m_pipelineStates;
|
||||||
|
std::unordered_map<DynamicDescriptorSetKey, CachedDescriptorSet, DynamicDescriptorSetKeyHash> m_dynamicDescriptorSets;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Passes
|
||||||
|
} // namespace Rendering
|
||||||
|
} // namespace XCEngine
|
||||||
3454
engine/third_party/nanovdb/shaders/PNanoVDB.hlsl
vendored
Normal file
3454
engine/third_party/nanovdb/shaders/PNanoVDB.hlsl
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -23,8 +23,25 @@ FetchContent_Declare(
|
|||||||
)
|
)
|
||||||
|
|
||||||
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||||
|
set(INSTALL_GTEST OFF CACHE BOOL "" FORCE)
|
||||||
FetchContent_MakeAvailable(googletest)
|
FetchContent_MakeAvailable(googletest)
|
||||||
|
|
||||||
|
if(TARGET gtest AND NOT TARGET GTest::gtest)
|
||||||
|
add_library(GTest::gtest ALIAS gtest)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(TARGET gtest_main AND NOT TARGET GTest::gtest_main)
|
||||||
|
add_library(GTest::gtest_main ALIAS gtest_main)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(TARGET gmock AND NOT TARGET GTest::gmock)
|
||||||
|
add_library(GTest::gmock ALIAS gmock)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(TARGET gmock_main AND NOT TARGET GTest::gmock_main)
|
||||||
|
add_library(GTest::gmock_main ALIAS gmock_main)
|
||||||
|
endif()
|
||||||
|
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
|||||||
@@ -21,3 +21,4 @@ add_subdirectory(post_process_scene)
|
|||||||
add_subdirectory(camera_post_process_scene camera_post_process_scene_builtin)
|
add_subdirectory(camera_post_process_scene camera_post_process_scene_builtin)
|
||||||
add_subdirectory(final_color_scene)
|
add_subdirectory(final_color_scene)
|
||||||
add_subdirectory(alpha_cutout_scene)
|
add_subdirectory(alpha_cutout_scene)
|
||||||
|
add_subdirectory(volume_scene)
|
||||||
|
|||||||
68
tests/Rendering/integration/volume_scene/CMakeLists.txt
Normal file
68
tests/Rendering/integration/volume_scene/CMakeLists.txt
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.15)
|
||||||
|
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
project(rendering_integration_volume_scene)
|
||||||
|
|
||||||
|
set(ENGINE_ROOT_DIR ${CMAKE_SOURCE_DIR}/engine)
|
||||||
|
set(PACKAGE_DIR ${CMAKE_SOURCE_DIR}/mvs/OpenGL/package)
|
||||||
|
|
||||||
|
get_filename_component(PROJECT_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../.. ABSOLUTE)
|
||||||
|
|
||||||
|
find_package(Vulkan QUIET)
|
||||||
|
|
||||||
|
add_executable(rendering_integration_volume_scene
|
||||||
|
main.cpp
|
||||||
|
${CMAKE_SOURCE_DIR}/tests/RHI/integration/fixtures/RHIIntegrationFixture.cpp
|
||||||
|
${PACKAGE_DIR}/src/glad.c
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(rendering_integration_volume_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_volume_scene PRIVATE
|
||||||
|
d3d12
|
||||||
|
dxgi
|
||||||
|
d3dcompiler
|
||||||
|
winmm
|
||||||
|
opengl32
|
||||||
|
XCEngine
|
||||||
|
GTest::gtest
|
||||||
|
)
|
||||||
|
|
||||||
|
if(TARGET Vulkan::Vulkan)
|
||||||
|
target_link_libraries(rendering_integration_volume_scene PRIVATE Vulkan::Vulkan)
|
||||||
|
target_compile_definitions(rendering_integration_volume_scene PRIVATE XCENGINE_SUPPORT_VULKAN)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_compile_definitions(rendering_integration_volume_scene PRIVATE
|
||||||
|
UNICODE
|
||||||
|
_UNICODE
|
||||||
|
XCENGINE_SUPPORT_OPENGL
|
||||||
|
XCENGINE_SUPPORT_D3D12
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_command(TARGET rendering_integration_volume_scene POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory
|
||||||
|
$<TARGET_FILE_DIR:rendering_integration_volume_scene>/Res/Volumes
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
${CMAKE_SOURCE_DIR}/tests/RHI/integration/compare_ppm.py
|
||||||
|
$<TARGET_FILE_DIR:rendering_integration_volume_scene>/
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/GT.ppm
|
||||||
|
$<TARGET_FILE_DIR:rendering_integration_volume_scene>/GT.ppm
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
${CMAKE_SOURCE_DIR}/mvs/VolumeRenderer/Res/NanoVDB/cloud.nvdb
|
||||||
|
$<TARGET_FILE_DIR:rendering_integration_volume_scene>/Res/Volumes/cloud.nvdb
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
${ENGINE_ROOT_DIR}/third_party/renderdoc/renderdoc.dll
|
||||||
|
$<TARGET_FILE_DIR:rendering_integration_volume_scene>/
|
||||||
|
)
|
||||||
|
|
||||||
|
include(GoogleTest)
|
||||||
|
gtest_discover_tests(rendering_integration_volume_scene)
|
||||||
@@ -13,6 +13,7 @@ if(MSVC)
|
|||||||
set_target_properties(volume_tests PROPERTIES
|
set_target_properties(volume_tests PROPERTIES
|
||||||
LINK_FLAGS "/NODEFAULTLIB:libcpmt.lib /NODEFAULTLIB:libcmt.lib"
|
LINK_FLAGS "/NODEFAULTLIB:libcpmt.lib /NODEFAULTLIB:libcmt.lib"
|
||||||
)
|
)
|
||||||
|
target_compile_options(volume_tests PRIVATE /bigobj /utf-8)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(volume_tests
|
target_link_libraries(volume_tests
|
||||||
@@ -24,11 +25,19 @@ target_link_libraries(volume_tests
|
|||||||
|
|
||||||
target_include_directories(volume_tests PRIVATE
|
target_include_directories(volume_tests PRIVATE
|
||||||
${CMAKE_SOURCE_DIR}/engine/include
|
${CMAKE_SOURCE_DIR}/engine/include
|
||||||
${CMAKE_SOURCE_DIR}/tests/Fixtures
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(XCENGINE_HAS_NANOVDB)
|
||||||
|
target_include_directories(volume_tests PRIVATE
|
||||||
|
${XCENGINE_NANOVDB_INCLUDE_DIR}
|
||||||
|
)
|
||||||
|
target_compile_definitions(volume_tests PRIVATE
|
||||||
|
XCENGINE_HAS_NANOVDB=1
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_compile_definitions(volume_tests PRIVATE
|
target_compile_definitions(volume_tests PRIVATE
|
||||||
XCENGINE_TEST_FIXTURES_DIR="${CMAKE_SOURCE_DIR}/tests/Fixtures"
|
XCENGINE_TEST_CLOUD_NVDB_PATH="${CMAKE_SOURCE_DIR}/mvs/VolumeRenderer/Res/NanoVDB/cloud.nvdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
include(GoogleTest)
|
include(GoogleTest)
|
||||||
|
|||||||
Reference in New Issue
Block a user