diff --git a/src/Mara/RadiumPlayer.cpp b/src/Mara/RadiumPlayer.cpp index d31010d63c7e8cd83487160388674ef9975af39d..72064268fdb4ddb07082a0a5c0d4fb69538f4f4d 100644 --- a/src/Mara/RadiumPlayer.cpp +++ b/src/Mara/RadiumPlayer.cpp @@ -14,8 +14,8 @@ using namespace Ra::Core::Utils; // for LOG( logLEVEL ) #include <QCommandLineParser> #include <QFileDialog> -#include <RadiumNBR/Gui/NodeBasedRendererGui.hpp> -#include <RadiumNBR/NodeBasedRenderer.hpp> +#include <RadiumNBR/FullFeatureRenderer.hpp> +#include <RadiumNBR/Gui/FullFeaturedRendererGui.hpp> #ifdef WITH_H3D_SUPPORT # include <RadiumH3D/h3DLoader.hpp> @@ -135,7 +135,7 @@ void RadiumPlayer::addRenderers() { } // add experimental renderer { - auto myRenderer = std::make_shared<RadiumNBR::NodeBasedRenderer>(); + auto myRenderer = std::make_shared<RadiumNBR::FullFeatureRenderer>(); std::string rendererName = myRenderer->getRendererName(); auto controlPanel = RadiumNBR::buildRadiumNBRGui( myRenderer.get(), [this]() { this->askForUpdate(); } ); diff --git a/src/Plugin/NodeRendererPlugin.cpp b/src/Plugin/NodeRendererPlugin.cpp index 57986087ecc64593965ea6df4c6962ac1a1872e6..c9f37601fb2255f88049c73bf60607f078e0b795 100644 --- a/src/Plugin/NodeRendererPlugin.cpp +++ b/src/Plugin/NodeRendererPlugin.cpp @@ -1,6 +1,6 @@ #include <NodeRendererPlugin.hpp> -#include <RadiumNBR/Gui/NodeBasedRendererGui.hpp> +#include <RadiumNBR/Gui/FullFeaturedRendererGui.hpp> namespace RadiumNBRPlugin { @@ -15,7 +15,7 @@ bool NodeRendererPlugin::doAddWidget( QString& name ) { } QWidget* NodeRendererPlugin::getWidget() { - if ( !m_renderer ) { m_renderer = std::make_shared<RadiumNBR::NodeBasedRenderer>(); } + if ( !m_renderer ) { m_renderer = std::make_shared<RadiumNBR::FullFeatureRenderer>(); } auto sendSignal = [this]() { emit askForUpdate(); }; return RadiumNBR::buildRadiumNBRGui( m_renderer.get(), sendSignal ); } @@ -44,7 +44,7 @@ bool NodeRendererPlugin::doAddRenderer() { } void NodeRendererPlugin::addRenderers( std::vector<std::shared_ptr<Ra::Engine::Rendering::Renderer>>* rds ) { - if ( !m_renderer ) { m_renderer = std::make_shared<RadiumNBR::NodeBasedRenderer>(); } + if ( !m_renderer ) { m_renderer = std::make_shared<RadiumNBR::FullFeatureRenderer>(); } rds->push_back( m_renderer ); } diff --git a/src/Plugin/NodeRendererPlugin.hpp b/src/Plugin/NodeRendererPlugin.hpp index a7ff67ed51ba1bffd406aff4066fb96609949313..2fc506ee4e90be8a4eeb99f5e6d956e47346f757 100644 --- a/src/Plugin/NodeRendererPlugin.hpp +++ b/src/Plugin/NodeRendererPlugin.hpp @@ -5,7 +5,7 @@ #include <PluginBase/RadiumPluginInterface.hpp> -#include <RadiumNBR/NodeBasedRenderer.hpp> +#include <RadiumNBR/FullFeatureRenderer.hpp> namespace RadiumNBRPlugin { @@ -45,7 +45,7 @@ class NodeRenderer_PLUGIN_API NodeRendererPlugin : public QObject, void askForUpdate(); private: - std::shared_ptr<RadiumNBR::NodeBasedRenderer> m_renderer; + std::shared_ptr<RadiumNBR::FullFeatureRenderer> m_renderer; }; } // namespace RadiumNBRPlugin diff --git a/src/libRender/CMakeLists.txt b/src/libRender/CMakeLists.txt index 33683c5a347c5261c8a6eef8d8df7abe06aad510..ce0a3beaa3f4c353a164f27acace879ae09f1afd 100644 --- a/src/libRender/CMakeLists.txt +++ b/src/libRender/CMakeLists.txt @@ -31,6 +31,7 @@ set(markdowns set(sources RadiumNBR/NodeBasedRenderer.cpp RadiumNBR/EnvMap.cpp + RadiumNBR/FullFeatureRenderer.cpp RadiumNBR/SphereSampler.cpp RadiumNBR/Passes/ClearPass.cpp RadiumNBR/Passes/GeomPrepass.cpp @@ -46,6 +47,7 @@ set(public_headers RadiumNBR/NodeBasedRendererMacro.hpp RadiumNBR/NodeBasedRenderer.hpp RadiumNBR/EnvMap.hpp + RadiumNBR/FullFeatureRenderer.hpp RadiumNBR/RenderPass.hpp RadiumNBR/SphereSampler.hpp RadiumNBR/Passes/ClearPass.hpp @@ -122,12 +124,12 @@ set(gui_markdowns ) set(gui_sources - RadiumNBR/Gui/NodeBasedRendererGui.cpp + RadiumNBR/Gui/FullFeaturedRendererGui.cpp RadiumNBR/Gui/RendererPanel.cpp ) set(gui_public_headers - RadiumNBR/Gui/NodeBasedRendererGui.hpp + RadiumNBR/Gui/FullFeaturedRendererGui.hpp RadiumNBR/Gui/RendererPanel.hpp ) diff --git a/src/libRender/RadiumNBR/FullFeatureRenderer.cpp b/src/libRender/RadiumNBR/FullFeatureRenderer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f455a4e85352fefb03b1c6a88667ba32b0749fe4 --- /dev/null +++ b/src/libRender/RadiumNBR/FullFeatureRenderer.cpp @@ -0,0 +1,370 @@ +#include <RadiumNBR/FullFeatureRenderer.hpp> + +#include <Core/Containers/MakeShared.hpp> +#include <Core/Resources/Resources.hpp> + +#ifdef PASSES_LOG +# include <Core/Utils/Log.hpp> +using namespace Ra::Core::Utils; // log +#endif + +#include <Engine/Data/Material.hpp> +#include <Engine/Data/ShaderProgramManager.hpp> +#include <Engine/Rendering/RenderObject.hpp> +#include <Engine/Scene/DefaultCameraManager.hpp> +#include <Engine/Scene/DefaultLightManager.hpp> + +#include <RadiumNBR/Passes/AccessibilityBufferPass.hpp> +#include <RadiumNBR/Passes/ClearPass.hpp> +#include <RadiumNBR/Passes/EmissivityPass.hpp> +#include <RadiumNBR/Passes/EnvLightPass.hpp> +#include <RadiumNBR/Passes/GeomPrepass.hpp> +#include <RadiumNBR/Passes/LocalLightPass.hpp> +#include <RadiumNBR/Passes/TransparencyPass.hpp> +#include <RadiumNBR/Passes/VolumePass.hpp> +#include <RadiumNBR/Passes/WireframePass.hpp> + +#include <globjects/Framebuffer.h> + +using namespace Ra::Engine; +using namespace Ra::Engine::Scene; +using namespace Ra::Engine::Data; +using namespace Ra::Engine::Rendering; + +namespace RadiumNBR { +using namespace gl; + +static int FullFeaturedRendererMagic = 0x0F0F0F0F; + +static const GLenum buffers[] = { GL_COLOR_ATTACHMENT0, + GL_COLOR_ATTACHMENT1, + GL_COLOR_ATTACHMENT2, + GL_COLOR_ATTACHMENT3, + GL_COLOR_ATTACHMENT4, + GL_COLOR_ATTACHMENT5, + GL_COLOR_ATTACHMENT6, + GL_COLOR_ATTACHMENT7 }; + +FullFeatureRenderer::FullFeatureRenderer() : NodeBasedRenderer() {} + +FullFeatureRenderer::~FullFeatureRenderer() = default; + + + +void FullFeatureRenderer::initializeInternal() { + NodeBasedRenderer::initializeInternal(); + initPasses(); + for ( const auto& t : sharedTextures() ) + { m_secondaryTextures.insert( { t.first, t.second.get() } ); } +} + +void FullFeatureRenderer::initPasses() { + auto resourcesCheck = Ra::Core::Resources::getResourcesPath( + reinterpret_cast<void*>( &FullFeaturedRendererMagic ), { "Resources/RadiumNBR" } ); + if ( !resourcesCheck ) + { + LOG( Ra::Core::Utils::logERROR ) << "Unable to find resources for NodeBasedRenderer!"; + return; + } + auto resourcesPath{ *resourcesCheck }; + auto depthTexture = sharedTextures().find( "Depth (RadiumNBR)" ); + auto colorTexture = sharedTextures().find( "Linear RGB (RadiumNBR)" ); + + /*** + * 0 - clear the final picture + * Set the background color either to the global background color or to the env-map + */ + { + m_clearPass = std::make_shared<ClearPass>( nullptr, FullFeaturedRendererPasses::CLEAR_PASS ); + m_clearPass->setOutput( *colorTexture ); + m_clearPass->setBackground( getBackgroundColor() ); + m_clearPass->initializePass( m_width, m_height, m_shaderProgramManager ); + } + + /*** + * 1 Extract basic geometric information : position, normal and depth + * Only draw ont AOV Position and Normal + */ + { + // Zprepass takes all objects but transparent objects are expected to render only their + // opaque fragments. + m_zPrePass = std::make_shared<GeomPrePass>( allRenderObjects(), + FullFeaturedRendererPasses::Z_PASS ); + // Add the shared depth texture + m_zPrePass->setOutput( *depthTexture ); + // configure acces to shader files + m_zPrePass->setResourcesDir( resourcesPath ); + m_zPrePass->initializePass( m_width, m_height, m_shaderProgramManager ); + for ( auto&& t : m_zPrePass->getOutputImages() ) + { + sharedTextures().insert( t ); + } + } + + /*** + * Compute accessibiity buffer (ambient occlusion) from output of pass 1 + * Screen space ambiant occlusion + */ + { + auto sphereSampler = + std::make_unique<SphereSampler>( m_aoSamplingMethod, m_aoSamplingPoints ); + m_aoPass = std::make_shared<AccessibilityBufferPass>( + allRenderObjects(), FullFeaturedRendererPasses::ACCESSIBILITY_PASS ); + m_aoPass->setResourcesDir( resourcesPath ); + m_aoPass->setSampler( std::move( sphereSampler ) ); + // Connect to the preceeding pass + auto posTexture = sharedTextures().find( "GeomPrePass::PosInWorld" ); + auto nrmTexture = sharedTextures().find( "GeomPrePass::NormalInWorld" ); + m_aoPass->setInputs( *posTexture, *nrmTexture ); + m_aoPass->initializePass( m_width, m_height, m_shaderProgramManager ); + for ( auto&& t : m_aoPass->getOutputImages() ) + { + sharedTextures().insert( t ); + } + } + auto ambientOcclusionTexture = sharedTextures().find( "SSDO::AOBuffer" ); + /*** + * 3 - Render emissivity + * Render Ambiant or emissivity color. + * Ambiant is 0.01 the base color. TODO -> set 0.01 a parameter of the pass + * Do not blend with output, replace the background color by the emissivity/ambiant color + */ + { + m_emissivityPass = std::make_shared<EmissivityPass>( + allRenderObjects(), FullFeaturedRendererPasses::EMISSIVITY_PASS ); + m_emissivityPass->setResourcesDir( resourcesPath ); + m_emissivityPass->setInputs( *depthTexture, *ambientOcclusionTexture ); + m_emissivityPass->setOutput( *colorTexture ); + m_emissivityPass->setBackground( getBackgroundColor() ); + m_emissivityPass->initializePass( m_width, m_height, m_shaderProgramManager ); + } + /*** + * 4 - Render envlighting + * Only render scene if an envmap is set + * Blend with the previous color buffer + */ + { + m_envlightPass = std::make_shared<EnvLightPass>( + allRenderObjects(), FullFeaturedRendererPasses::ENVMAP_LIGHTING_OPAQUE_PASS ); + m_envlightPass->setResourcesDir( resourcesPath ); + m_envlightPass->setInputs( *depthTexture, *ambientOcclusionTexture ); + m_envlightPass->setOutput( *colorTexture ); + m_envlightPass->initializePass( m_width, m_height, m_shaderProgramManager ); + } + + /*** + * 5 - Compute lighting - Opaque objects + */ + { + m_locallightPass = std::make_shared<LocalLightPass>( + allRenderObjects(), FullFeaturedRendererPasses::LIGHTING_OPAQUE_PASS ); + m_locallightPass->setResourcesDir( resourcesPath ); + m_locallightPass->setInputs( *depthTexture, *ambientOcclusionTexture ); + m_locallightPass->setOutput( *colorTexture ); + m_locallightPass->setLightManager( m_lightmanagers[0] ); + m_locallightPass->initializePass( m_width, m_height, m_shaderProgramManager ); + } + /*** + * 6 - Compute lighting - Transparent objects + */ + { + m_transparencyPass = std::make_shared<TransparencyPass>( + &m_transparentRenderObjects, FullFeaturedRendererPasses::LIGHTING_TRANSPARENT_PASS ); + m_transparencyPass->setResourcesDir( resourcesPath ); + m_transparencyPass->setInputs( *depthTexture, *ambientOcclusionTexture ); + m_transparencyPass->setOutput( *colorTexture ); + m_transparencyPass->setLightManager( m_lightmanagers[0] ); + m_transparencyPass->initializePass( m_width, m_height, m_shaderProgramManager ); + } + + /*** + * 7 - Compute lighting for volume objects + */ + { + m_volumelightPass = std::make_shared<VolumeLightingPass>( + &m_volumetricRenderObjects, FullFeaturedRendererPasses::LIGHTING_VOLUME_PASS ); + m_volumelightPass->setResourcesDir( resourcesPath ); + m_volumelightPass->setInputs( *depthTexture, *colorTexture ); + m_volumelightPass->setOutput( *colorTexture ); + m_volumelightPass->setLightManager( m_lightmanagers[0] ); + m_volumelightPass->initializePass( m_width, m_height, m_shaderProgramManager ); + } + + /*** + * Option - Render in wireframe + * Render all objects as wireframe + * Render in white over an existing depth buffer + */ + { + m_wireframePass = std::make_shared<WireframePass>( + allRenderObjects(), FullFeaturedRendererPasses::WIREFRAME_PASS ); + m_wireframePass->setResourcesDir( resourcesPath ); + m_wireframePass->setInputs( *depthTexture ); + m_wireframePass->setOutput( *colorTexture ); + m_wireframePass->initializePass( m_width, m_height, m_shaderProgramManager ); + } + + + // Build the sequence of active passes + addPass(m_clearPass, m_clearPass->index()); + m_clearPass->activate(); + addPass(m_zPrePass, m_zPrePass->index()); + m_zPrePass->activate(); + addPass( m_aoPass, m_aoPass->index() ); + m_aoPass->activate(); + + addPass( m_emissivityPass, m_emissivityPass->index() ); + m_emissivityPass->activate(); + + addPass( m_envlightPass, m_envlightPass->index() ); + m_envlightPass->activate(); + + addPass( m_locallightPass, m_locallightPass->index(), true ); + m_locallightPass->activate(); + addPass( m_transparencyPass, m_transparencyPass->index() ); + m_transparencyPass->activate(); + addPass( m_volumelightPass, m_volumelightPass->index() ); + m_volumelightPass->activate(); + + addPass( m_wireframePass, m_wireframePass->index() ); + + // Add intermediate textures to the texture explorer + for ( const auto& p : renderPasses() ) + { + for ( auto&& t : p.second->getOutputImages() ) + { + sharedTextures().insert( t ); + } + } +} + + +// Todo : verify if the ro partition is the good one and that the passes use the right part. +void FullFeatureRenderer::updateStepInternal( const ViewingParameters& renderData ) { + // Split objects into opaque and transparent + m_transparentRenderObjects.clear(); + m_volumetricRenderObjects.clear(); + allRenderObjects()->clear(); + for ( auto it = m_fancyRenderObjects.begin(); it != m_fancyRenderObjects.end(); ) + { + allRenderObjects()->push_back( *it ); + if ( ( *it )->isTransparent() ) + { + m_transparentRenderObjects.push_back( *it ); + it = m_fancyRenderObjects.erase( it ); + } + else + { + auto material = ( *it )->getMaterial(); + if ( material && + material->getMaterialAspect() == Material::MaterialAspect::MAT_DENSITY ) + { + m_volumetricRenderObjects.push_back( *it ); + it = m_fancyRenderObjects.erase( it ); + } + else + { ++it; } + } + } + + // Update passes + // Note that this could be expensive. Find a way to add attributes to renderObjects so + // that one ca factorizes some evaluations. + for ( auto& rp : renderPasses() ) + { + if ( rp.second->isActive() ) { rp.second->update(); } + } +} + +void FullFeatureRenderer::renderInternal( const ViewingParameters& renderData ) { + m_clearPass->setBackground( getBackgroundColor() ); + if ( m_hasEnvMap ) + { + // for ( auto &lm : m_lightmanagers ) { lm->removeSystemLights(); } + } + NodeBasedRenderer::renderInternal( renderData ); +} + + + +void FullFeatureRenderer::setEnvMap( const std::string& files ) { + if ( files.empty() ) + { + m_clearPass->setEnvMap( nullptr ); + m_envlightPass->setEnvMap( nullptr ); + m_envlightPass->deactivate(); + m_volumelightPass->setEnvMap( nullptr ); + m_hasEnvMap = false; + } + else + { + // Todo, add type VERTICALCROSS, HORIZONTALCROSS and differentiate between all types + // using file extension and file size + auto t = ( files.find( ';' ) != files.npos ) ? EnvMap::EnvMapType::ENVMAP_CUBE + : EnvMap::EnvMapType::ENVMAP_PFM; + if ( t == EnvMap::EnvMapType::ENVMAP_PFM ) + { + auto ext = files.substr( files.size() - 3 ); + if ( ext != "pfm" ) { t = EnvMap::EnvMapType::ENVMAP_LATLON; } + } + // for now, only skyboxes are managed + auto e = std::make_shared<EnvMap>( files, t, true ); + m_clearPass->setEnvMap( e ); + m_envlightPass->setEnvMap( e ); + // activate the envmap pass only if wireframe is inactive ? + if ( !m_wireframePass->isActive() ) { m_envlightPass->activate(); } + m_volumelightPass->setEnvMap( e ); + m_hasEnvMap = true; + } +} + +void FullFeatureRenderer::showEnvMap( bool state ) { + m_clearPass->showEnvMap( state ); +} + +void FullFeatureRenderer::setEnvStrength( int s ) { + m_envlightPass->setEnvStrength( s ); +} + +Scalar FullFeatureRenderer::getAoRadius() const { + if ( m_aoPass ) { return m_aoPass->aoRadius(); } + return 5.0; +} +void FullFeatureRenderer::setAoRadius( Scalar r ) { + if ( m_aoPass ) { m_aoPass->setAoRadius( r ); } +} + +int FullFeatureRenderer::getAoSamplingDensity() const { + return m_aoSamplingPoints; +} +void FullFeatureRenderer::setAoSamplingDensity( int d ) { + m_aoSamplingPoints = d; + auto sphereSampler = std::make_unique<SphereSampler>( m_aoSamplingMethod, m_aoSamplingPoints ); + if ( m_aoPass ) { m_aoPass->setSampler( std::move( sphereSampler ) ); } +} + +void FullFeatureRenderer::wireframeMode( bool status ) { + enableWireframe( status ); + if ( m_wireframe ) { + m_wireframePass->activate(); + + m_aoPass->deactivate(); + m_emissivityPass->deactivate(); + m_envlightPass->deactivate(); + m_locallightPass->deactivate(); + m_transparencyPass->deactivate(); + m_volumelightPass->deactivate(); + + } else { + m_wireframePass->deactivate(); + + m_aoPass->activate(); + m_emissivityPass->activate(); + m_envlightPass->activate(); + m_locallightPass->activate(); + m_transparencyPass->activate(); + m_volumelightPass->activate(); + + } +} +} // namespace RadiumNBR diff --git a/src/libRender/RadiumNBR/FullFeatureRenderer.hpp b/src/libRender/RadiumNBR/FullFeatureRenderer.hpp new file mode 100644 index 0000000000000000000000000000000000000000..44dba4f8cc0b3ab391cec03bba25086217c589d5 --- /dev/null +++ b/src/libRender/RadiumNBR/FullFeatureRenderer.hpp @@ -0,0 +1,120 @@ +#pragma once +#include <RadiumNBR/NodeBasedRendererMacro.hpp> +#include <RadiumNBR/RenderPass.hpp> +#include <RadiumNBR/SphereSampler.hpp> + +#include <RadiumNBR/NodeBasedRenderer.hpp> + +namespace globjects { +class Framebuffer; +} + +namespace Ra::Engine::Data { +class Texture; +} // namespace Ra::Engine::Data + +namespace RadiumNBR { +class ClearPass; +class GeomPrePass; +class AccessibilityBufferPass; +class EmissivityPass; +class EnvLightPass; +class LocalLightPass; +class VolumeLightingPass; +class TransparencyPass; +class WireframePass; + +/** Advanced renderer for the Radium Engine + * This class implements a forward rendering algorithm with Z-prepass, multipass light accumulation + * for opaque and transparent objects. + * Once renderer, the final is composited with Ui, debug and + * X-ray objects renderings on demand. + * + * @see rendering.md for description of the renderer + */ +class NodeBasedRenderer_LIBRARY_API FullFeatureRenderer final : public NodeBasedRenderer +{ + + public: + FullFeatureRenderer(); + ~FullFeatureRenderer() override; + + [[nodiscard]] std::string getRendererName() const override { return "Full Featured Renderer"; } + + void setEnvMap( const std::string& files ); + void showEnvMap( bool state ); + // TODO : define a way to configfure each passes without adding here specifi methods + // TODO the following might be removed in the future + Scalar getAoRadius() const; + void setAoRadius( Scalar r ); + int getAoSamplingDensity() const; + void setAoSamplingDensity( int d ); + void setEnvStrength( int s ); + void wireframeMode( bool status ); + + protected: + void initializeInternal() override; + void updateStepInternal( const Ra::Engine::Data::ViewingParameters& renderData ) override; + void renderInternal( const Ra::Engine::Data::ViewingParameters& renderData ) override; + + private: + void initPasses(); + + enum FullFeaturedRendererPasses : int { + CLEAR_PASS = 0, + Z_PASS, + ACCESSIBILITY_PASS, + EMISSIVITY_PASS, + ENVMAP_LIGHTING_OPAQUE_PASS, + LIGHTING_OPAQUE_PASS, + LIGHTING_TRANSPARENT_PASS, + LIGHTING_VOLUME_PASS, + WIREFRAME_PASS, + NUM_PASSES, + DEFAULT_PASS = LIGHTING_OPAQUE_PASS + }; + protected: + + /// Subset of the objects that are transparent and need special rendering + std::vector<RenderObjectPtr> m_transparentRenderObjects; + + /// Subset of the objects that are volumetric + std::vector<RenderObjectPtr> m_volumetricRenderObjects; + + /// The ambiant occlusion pass + std::shared_ptr<AccessibilityBufferPass> m_aoPass; + // The sampling method of the sphere sampler + SphereSampler::SamplingMethod m_aoSamplingMethod{ SphereSampler::SamplingMethod::HAMMERSLEY }; + // The number of points for the sampler + int m_aoSamplingPoints{ 64 }; + + /// clear the final ouput image + std::shared_ptr<ClearPass> m_clearPass; + + /// The zprepass + std::shared_ptr<GeomPrePass> m_zPrePass; + + /// The emissivity pass + std::shared_ptr<EmissivityPass> m_emissivityPass; + + /// The envlight pass + std::shared_ptr<EnvLightPass> m_envlightPass; + + /// The local lighting pass + std::shared_ptr<LocalLightPass> m_locallightPass; + + /// The volume lighting pass + std::shared_ptr<VolumeLightingPass> m_volumelightPass; + + /// The transparency (Order independant transparency) pass + std::shared_ptr<TransparencyPass> m_transparencyPass; + + /// The transparency (Order independant transparency) pass + std::shared_ptr<WireframePass> m_wireframePass; + + /// Is an envmap attached to the renderer + bool m_hasEnvMap{ false }; + +}; + +} // namespace RadiumNBR diff --git a/src/libRender/RadiumNBR/Gui/NodeBasedRendererGui.cpp b/src/libRender/RadiumNBR/Gui/FullFeaturedRendererGui.cpp similarity index 92% rename from src/libRender/RadiumNBR/Gui/NodeBasedRendererGui.cpp rename to src/libRender/RadiumNBR/Gui/FullFeaturedRendererGui.cpp index 7645bd1dd2a668147d89b9722d9852ae4ea09b34..625125ae8a3717bbcb564ad90fc5c8a7326b23ff 100644 --- a/src/libRender/RadiumNBR/Gui/NodeBasedRendererGui.cpp +++ b/src/libRender/RadiumNBR/Gui/FullFeaturedRendererGui.cpp @@ -1,10 +1,10 @@ -#include <RadiumNBR/Gui/NodeBasedRendererGui.hpp> -#include <RadiumNBR/NodeBasedRenderer.hpp> +#include <RadiumNBR/FullFeatureRenderer.hpp> +#include <RadiumNBR/Gui/FullFeaturedRendererGui.hpp> namespace RadiumNBR { using namespace Gui; -RadiumNBR::Gui::RendererPanel* buildRadiumNBRGui( NodeBasedRenderer* renderer, +RadiumNBR::Gui::RendererPanel* buildRadiumNBRGui( FullFeatureRenderer* renderer, const std::function<void()>& appUpdateCallback ) { auto controlPanel = new RendererPanel( renderer->getRendererName() ); diff --git a/src/libRender/RadiumNBR/Gui/NodeBasedRendererGui.hpp b/src/libRender/RadiumNBR/Gui/FullFeaturedRendererGui.hpp similarity index 62% rename from src/libRender/RadiumNBR/Gui/NodeBasedRendererGui.hpp rename to src/libRender/RadiumNBR/Gui/FullFeaturedRendererGui.hpp index 0a0de26a23b296e390ec1246e9c484a6405946bf..ccfd7c52e65d235cb75428aeebf984b9a44c7cf7 100644 --- a/src/libRender/RadiumNBR/Gui/NodeBasedRendererGui.hpp +++ b/src/libRender/RadiumNBR/Gui/FullFeaturedRendererGui.hpp @@ -3,9 +3,9 @@ #include <RadiumNBR/NodeBasedRendererMacro.hpp> namespace RadiumNBR { -class NodeBasedRenderer; +class FullFeatureRenderer; NodeBasedRenderer_LIBRARY_API RadiumNBR::Gui::RendererPanel* -buildRadiumNBRGui( NodeBasedRenderer* renderer, const std::function<void()>& appUpdateCallback ); +buildRadiumNBRGui( FullFeatureRenderer* renderer, const std::function<void()>& appUpdateCallback ); } // namespace RadiumNBR diff --git a/src/libRender/RadiumNBR/NodeBasedRenderer.cpp b/src/libRender/RadiumNBR/NodeBasedRenderer.cpp index fd28a8a5f798966be57376ff1eeec24609144a31..a6e4f718a92ce74181c0e86f708601eee28007cd 100644 --- a/src/libRender/RadiumNBR/NodeBasedRenderer.cpp +++ b/src/libRender/RadiumNBR/NodeBasedRenderer.cpp @@ -1,50 +1,30 @@ #include <RadiumNBR/NodeBasedRenderer.hpp> #include <Core/Containers/MakeShared.hpp> -#include <Core/Resources/Resources.hpp> #ifdef PASSES_LOG # include <Core/Utils/Log.hpp> using namespace Ra::Core::Utils; // log #endif -#include <Engine/Data/Material.hpp> #include <Engine/Data/ShaderProgramManager.hpp> #include <Engine/Data/Texture.hpp> #include <Engine/Rendering/RenderObject.hpp> #include <Engine/Scene/DefaultCameraManager.hpp> #include <Engine/Scene/DefaultLightManager.hpp> -#include <RadiumNBR/Passes/AccessibilityBufferPass.hpp> -#include <RadiumNBR/Passes/ClearPass.hpp> -#include <RadiumNBR/Passes/EmissivityPass.hpp> -#include <RadiumNBR/Passes/EnvLightPass.hpp> -#include <RadiumNBR/Passes/GeomPrepass.hpp> -#include <RadiumNBR/Passes/LocalLightPass.hpp> -#include <RadiumNBR/Passes/TransparencyPass.hpp> -#include <RadiumNBR/Passes/VolumePass.hpp> -#include <RadiumNBR/Passes/WireframePass.hpp> - #include <globjects/Framebuffer.h> using namespace Ra::Engine; using namespace Ra::Engine::Scene; using namespace Ra::Engine::Data; using namespace Ra::Engine::Rendering; - namespace RadiumNBR { using namespace gl; -static int NodeBasedRendererMagic = 0x0F0F0F0F; +static int NodeBasedRendererMagic = 0xFF0F00F0; -static const GLenum buffers[] = { GL_COLOR_ATTACHMENT0, - GL_COLOR_ATTACHMENT1, - GL_COLOR_ATTACHMENT2, - GL_COLOR_ATTACHMENT3, - GL_COLOR_ATTACHMENT4, - GL_COLOR_ATTACHMENT5, - GL_COLOR_ATTACHMENT6, - GL_COLOR_ATTACHMENT7 }; +static const GLenum buffers[] = { GL_COLOR_ATTACHMENT0 }; NodeBasedRenderer::NodeBasedRenderer() : Renderer() {} @@ -52,234 +32,30 @@ NodeBasedRenderer::~NodeBasedRenderer() = default; bool NodeBasedRenderer::buildRenderTechnique( RenderObject* ro ) const { auto rt = Ra::Core::make_shared<RenderTechnique>(); - for ( auto& rp : m_renderPasses ) + for ( auto& rp : renderPasses() ) { - rp->buildRenderTechnique( ro, *rt ); + rp.second->buildRenderTechnique( ro, *rt ); } rt->updateGL(); ro->setRenderTechnique( rt ); return true; } -void NodeBasedRenderer::initializeInternal() { - - // TODO : this must be done only once, see register system ... - if ( Ra::Engine::RadiumEngine::getInstance()->getSystem( "DefaultCameraManager" ) == nullptr ) - { - auto cameraManager = new DefaultCameraManager(); - Ra::Engine::RadiumEngine::getInstance()->registerSystem( "DefaultCameraManager", - cameraManager ); - } - auto lmngr = dynamic_cast<DefaultLightManager*>( - Ra::Engine::RadiumEngine::getInstance()->getSystem( "DefaultLightManager" ) ); - if ( lmngr == nullptr ) - { - lmngr = new DefaultLightManager(); - Ra::Engine::RadiumEngine::getInstance()->registerSystem( "DefaultLightManager", lmngr ); - } - m_lightmanagers.push_back( lmngr ); - - // Initialize renderer resources - initShaders(); - initBuffers(); - initPasses(); - for ( const auto& t : m_sharedTextures ) - { m_secondaryTextures.insert( { t.first, t.second.get() } ); } -} - -void NodeBasedRenderer::initPasses() { - auto resourcesCheck = Ra::Core::Resources::getResourcesPath( - reinterpret_cast<void*>( &NodeBasedRendererMagic ), { "Resources/RadiumNBR" } ); - if ( !resourcesCheck ) - { - LOG( Ra::Core::Utils::logERROR ) << "Unable to find resources for NodeBasedRenderer!"; - return; - } - auto resourcesPath{ *resourcesCheck }; - auto depthTexture = m_sharedTextures.find( "Depth ( AdvRndr )" ); - auto colorTexture = m_sharedTextures.find( "Linear RGB ( AdvRndr )" ); - - /*** - * 0 - clear the final picture - * Set the background color either to the global background color or to the env-map - */ - { - m_clearPass = std::make_shared<ClearPass>( nullptr, NodeBasedRendererPasses::CLEAR_PASS ); - m_clearPass->setOutput( *colorTexture ); - m_clearPass->setBackground( getBackgroundColor() ); - m_clearPass->initializePass( m_width, m_height, m_shaderProgramManager ); - } - - /*** - * 1 Extract basic geometric information : position, normal and depth - * Only draw ont AOV Position and Normal - */ - { - // Zprepass takes all objects but transparent objects are expected to render only their - // opaque fragments. - m_zPrePass = std::make_shared<GeomPrePass>( &m_allRenderObjects, - NodeBasedRendererPasses::GEOM_PASS ); - // Add the shared depth texture - m_zPrePass->setOutput( *depthTexture ); - // configure acces to shader files - m_zPrePass->setResourcesDir( resourcesPath ); - m_zPrePass->initializePass( m_width, m_height, m_shaderProgramManager ); - for ( auto&& t : m_zPrePass->getOutputImages() ) - { - m_sharedTextures.insert( t ); - } - } - - /*** - * Compute accessibiity buffer (ambient occlusion) from output of pass 1 - * Screen space ambiant occlusion - */ - { - auto sphereSampler = - std::make_unique<SphereSampler>( m_aoSamplingMethod, m_aoSamplingPoints ); - m_aoPass = std::make_shared<AccessibilityBufferPass>( - &m_allRenderObjects, NodeBasedRendererPasses::ACCESSIBILITY_PASS ); - m_aoPass->setResourcesDir( resourcesPath ); - m_aoPass->setSampler( std::move( sphereSampler ) ); - // Connect to the preceeding pass - auto posTexture = m_sharedTextures.find( "GeomPrePass::PosInWorld" ); - auto nrmTexture = m_sharedTextures.find( "GeomPrePass::NormalInWorld" ); - m_aoPass->setInputs( *posTexture, *nrmTexture ); - m_aoPass->initializePass( m_width, m_height, m_shaderProgramManager ); - for ( auto&& t : m_aoPass->getOutputImages() ) - { - m_sharedTextures.insert( t ); - } - } - auto ambientOcclusionTexture = m_sharedTextures.find( "SSDO::AOBuffer" ); - /*** - * 3 - Render emissivity - * Render Ambiant or emissivity color. - * Ambiant is 0.01 the base color. TODO -> set 0.01 a parameter of the pass - * Do not blend with output, replace the background color by the emissivity/ambiant color - */ - { - m_emissivityPass = std::make_shared<EmissivityPass>( - &m_allRenderObjects, NodeBasedRendererPasses::EMISSIVITY_PASS ); - m_emissivityPass->setResourcesDir( resourcesPath ); - m_emissivityPass->setInputs( *depthTexture, *ambientOcclusionTexture ); - m_emissivityPass->setOutput( *colorTexture ); - m_emissivityPass->setBackground( getBackgroundColor() ); - m_emissivityPass->initializePass( m_width, m_height, m_shaderProgramManager ); - } - /*** - * 4 - Render envlighting - * Only render scene if an envmap is set - * Blend with the previous color buffer - */ - { - m_envlightPass = std::make_shared<EnvLightPass>( - &m_allRenderObjects, NodeBasedRendererPasses::ENVMAP_LIGHTING_OPAQUE_PASS ); - m_envlightPass->setResourcesDir( resourcesPath ); - m_envlightPass->setInputs( *depthTexture, *ambientOcclusionTexture ); - m_envlightPass->setOutput( *colorTexture ); - m_envlightPass->initializePass( m_width, m_height, m_shaderProgramManager ); - } - - /*** - * 5 - Compute lighting - Opaque objects - */ - { - m_locallightPass = std::make_shared<LocalLightPass>( - &m_allRenderObjects, NodeBasedRendererPasses::LIGHTING_OPAQUE_PASS ); - m_locallightPass->setResourcesDir( resourcesPath ); - m_locallightPass->setInputs( *depthTexture, *ambientOcclusionTexture ); - m_locallightPass->setOutput( *colorTexture ); - m_locallightPass->setLightManager( m_lightmanagers[0] ); - m_locallightPass->initializePass( m_width, m_height, m_shaderProgramManager ); - } - /*** - * 6 - Compute lighting - Transparent objects - */ - { - m_transparencyPass = std::make_shared<TransparencyPass>( - &m_transparentRenderObjects, NodeBasedRendererPasses::LIGHTING_TRANSPARENT_PASS ); - m_transparencyPass->setResourcesDir( resourcesPath ); - m_transparencyPass->setInputs( *depthTexture, *ambientOcclusionTexture ); - m_transparencyPass->setOutput( *colorTexture ); - m_transparencyPass->setLightManager( m_lightmanagers[0] ); - m_transparencyPass->initializePass( m_width, m_height, m_shaderProgramManager ); - } - - /*** - * 7 - Compute lighting for volume objects - */ - { - m_volumelightPass = std::make_shared<VolumeLightingPass>( - &m_volumetricRenderObjects, NodeBasedRendererPasses::LIGHTING_VOLUME_PASS ); - m_volumelightPass->setResourcesDir( resourcesPath ); - m_volumelightPass->setInputs( *depthTexture, *colorTexture ); - m_volumelightPass->setOutput( *colorTexture ); - m_volumelightPass->setLightManager( m_lightmanagers[0] ); - m_volumelightPass->initializePass( m_width, m_height, m_shaderProgramManager ); - } - - /*** - * Option - Render in wireframe - * Render all objects as wireframe - * Render in white over an existing depth buffer - */ - { - m_wireframePass = std::make_shared<WireframePass>( - &m_allRenderObjects, NodeBasedRendererPasses::WIREFRAME_PASS ); - m_wireframePass->setResourcesDir( resourcesPath ); - m_wireframePass->setInputs( *depthTexture ); - m_wireframePass->setOutput( *colorTexture ); - m_wireframePass->initializePass( m_width, m_height, m_shaderProgramManager ); - } - - - // Build the sequence of active passes - m_renderPasses.emplace_back( m_clearPass ); - m_clearPass->activate(); - m_renderPasses.emplace_back( m_zPrePass ); - m_zPrePass->activate(); - m_renderPasses.emplace_back( m_aoPass ); - m_aoPass->activate(); - - m_renderPasses.emplace_back( m_emissivityPass ); - m_emissivityPass->activate(); - - m_renderPasses.emplace_back( m_envlightPass ); - m_envlightPass->activate(); - - m_renderPasses.emplace_back( m_locallightPass ); - m_locallightPass->activate(); - m_renderPasses.emplace_back( m_transparencyPass ); - m_transparencyPass->activate(); - m_renderPasses.emplace_back( m_volumelightPass ); - m_volumelightPass->activate(); - - m_renderPasses.emplace_back( m_wireframePass ); - - // Add intermediate textures to the texture explorer - for ( const auto& p : m_renderPasses ) - { - for ( auto&& t : p->getOutputImages() ) - { - m_sharedTextures.insert( t ); - } - } -} - void NodeBasedRenderer::initShaders() { // uses several resources from the Radium engine auto resourcesRootDir{ RadiumEngine::getInstance()->getResourcesDir() + "Shaders/" }; + m_shaderProgramManager->addShaderProgram( { { "Hdr2Ldr" }, resourcesRootDir + "2DShaders/Basic2D.vert.glsl", resourcesRootDir + "2DShaders/Hdr2Ldr.frag.glsl" } ); + } void NodeBasedRenderer::initBuffers() { m_postprocessFbo = std::make_unique<globjects::Framebuffer>(); - // Advanced renderer : only initializes textures that are shared between all the passe or + // NodeBased renderer : only initializes textures that are shared between all the passes or // that are used internally on the renderer. // Each pass will manage its own textures and export them if they can be shared. @@ -294,7 +70,7 @@ void NodeBasedRenderer::initBuffers() { texparams.internalFormat = GL_DEPTH_COMPONENT24; texparams.format = GL_DEPTH_COMPONENT; texparams.type = GL_UNSIGNED_INT; - texparams.name = "Depth ( AdvRndr )"; + texparams.name = "Depth (RadiumNBR)"; m_sharedTextures.insert( { texparams.name, std::make_shared<Texture>( texparams ) } ); // Linear (and HDR) RGBA Color texture @@ -303,18 +79,43 @@ void NodeBasedRenderer::initBuffers() { texparams.type = GL_FLOAT; texparams.minFilter = GL_LINEAR; texparams.magFilter = GL_LINEAR; - texparams.name = "Linear RGB ( AdvRndr )"; + texparams.name = "Linear RGB (RadiumNBR)"; m_sharedTextures.insert( { texparams.name, std::make_shared<Texture>( texparams ) } ); } +void NodeBasedRenderer::initializeInternal() { + + // TODO : this must be done only once, see register system ... + if ( Ra::Engine::RadiumEngine::getInstance()->getSystem( "DefaultCameraManager" ) == nullptr ) + { + auto cameraManager = new DefaultCameraManager(); + Ra::Engine::RadiumEngine::getInstance()->registerSystem( "DefaultCameraManager", + cameraManager ); + } + auto lmngr = dynamic_cast<DefaultLightManager*>( + Ra::Engine::RadiumEngine::getInstance()->getSystem( "DefaultLightManager" ) ); + if ( lmngr == nullptr ) + { + lmngr = new DefaultLightManager(); + Ra::Engine::RadiumEngine::getInstance()->registerSystem( "DefaultLightManager", lmngr ); + } + m_lightmanagers.push_back( lmngr ); + + // Initialize renderer resources + initShaders(); + initBuffers(); + for ( const auto& t : m_sharedTextures ) + { m_secondaryTextures.insert( { t.first, t.second.get() } ); } +} + void NodeBasedRenderer::resizeInternal() { - m_sharedTextures["Depth ( AdvRndr )"]->resize( m_width, m_height ); - m_sharedTextures["Linear RGB ( AdvRndr )"]->resize( m_width, m_height ); + m_sharedTextures["Depth (RadiumNBR)"]->resize( m_width, m_height ); + m_sharedTextures["Linear RGB (RadiumNBR)"]->resize( m_width, m_height ); for ( auto& rp : m_renderPasses ) { - rp->resize( m_width, m_height ); + rp.second->resize( m_width, m_height ); } m_postprocessFbo->bind(); @@ -330,54 +131,12 @@ void NodeBasedRenderer::resizeInternal() { globjects::Framebuffer::unbind(); } -// Todo : verify if the ro partition is the good one and that the passes use the right part. -void NodeBasedRenderer::updateStepInternal( const ViewingParameters& renderData ) { - // Split objects into opaque and transparent - m_transparentRenderObjects.clear(); - m_volumetricRenderObjects.clear(); - m_allRenderObjects.clear(); - for ( auto it = m_fancyRenderObjects.begin(); it != m_fancyRenderObjects.end(); ) - { - m_allRenderObjects.push_back( *it ); - if ( ( *it )->isTransparent() ) - { - m_transparentRenderObjects.push_back( *it ); - it = m_fancyRenderObjects.erase( it ); - } - else - { - auto material = ( *it )->getMaterial(); - if ( material && - material->getMaterialAspect() == Material::MaterialAspect::MAT_DENSITY ) - { - m_volumetricRenderObjects.push_back( *it ); - it = m_fancyRenderObjects.erase( it ); - } - else - { ++it; } - } - } - - // Update passes - // Note that this could be expensive. Find a way to add attributes to renderObjects so - // that one ca factorizes some evaluations. - for ( auto& rp : m_renderPasses ) - { - if ( rp->isActive() ) { rp->update(); } - } -} - void NodeBasedRenderer::renderInternal( const ViewingParameters& renderData ) { - m_clearPass->setBackground( getBackgroundColor() ); - if ( m_hasEnvMap ) - { - // for ( auto &lm : m_lightmanagers ) { lm->removeSystemLights(); } - } // Run each pass, in order. for ( const auto& rp : m_renderPasses ) { - if (rp->isActive()) { - rp->execute( renderData ); + if (rp.second->isActive()) { + rp.second->execute( renderData ); } } } @@ -495,7 +254,7 @@ void NodeBasedRenderer::postProcessInternal( const ViewingParameters& /* renderD auto shader = m_shaderProgramManager->getShaderProgram( "Hdr2Ldr" ); shader->bind(); - shader->setUniform( "screenTexture", m_sharedTextures["Linear RGB ( AdvRndr )"].get(), 0 ); + shader->setUniform( "screenTexture", m_sharedTextures["Linear RGB (RadiumNBR)"].get(), 0 ); m_quadMesh->render( shader ); GL_ASSERT( glDepthMask( GL_TRUE ) ); @@ -504,84 +263,30 @@ void NodeBasedRenderer::postProcessInternal( const ViewingParameters& /* renderD m_postprocessFbo->unbind(); } -void NodeBasedRenderer::setEnvMap( const std::string& files ) { - if ( files.empty() ) +// Todo : verify if the ro partition is the good one and that the passes use the right part. +void NodeBasedRenderer::updateStepInternal( const ViewingParameters& renderData ) { + m_allRenderObjects.clear(); + for ( auto it = m_fancyRenderObjects.begin(); it != m_fancyRenderObjects.end(); ) { - m_clearPass->setEnvMap( nullptr ); - m_envlightPass->setEnvMap( nullptr ); - m_envlightPass->deactivate(); - m_volumelightPass->setEnvMap( nullptr ); - m_hasEnvMap = false; + m_allRenderObjects.push_back( *it ); } - else + + // Update passes + // Note that this could be expensive. Find a way to add attributes to renderObjects so + // that one ca factorizes some evaluations. + for ( auto& rp : m_renderPasses ) { - // Todo, add type VERTICALCROSS, HORIZONTALCROSS and differentiate between all types - // using file extension and file size - auto t = ( files.find( ';' ) != files.npos ) ? EnvMap::EnvMapType::ENVMAP_CUBE - : EnvMap::EnvMapType::ENVMAP_PFM; - if ( t == EnvMap::EnvMapType::ENVMAP_PFM ) - { - auto ext = files.substr( files.size() - 3 ); - if ( ext != "pfm" ) { t = EnvMap::EnvMapType::ENVMAP_LATLON; } - } - // for now, only skyboxes are managed - auto e = std::make_shared<EnvMap>( files, t, true ); - m_clearPass->setEnvMap( e ); - m_envlightPass->setEnvMap( e ); - // activate the envmap pass only if wireframe is inactive ? - if ( !m_wireframePass->isActive() ) { m_envlightPass->activate(); } - m_volumelightPass->setEnvMap( e ); - m_hasEnvMap = true; + if ( rp.second->isActive() ) { rp.second->update(); } } } -void NodeBasedRenderer::showEnvMap( bool state ) { - m_clearPass->showEnvMap( state ); -} - -void NodeBasedRenderer::setEnvStrength( int s ) { - m_envlightPass->setEnvStrength( s ); -} - -Scalar NodeBasedRenderer::getAoRadius() const { - if ( m_aoPass ) { return m_aoPass->aoRadius(); } - return 5.0; -} -void NodeBasedRenderer::setAoRadius( Scalar r ) { - if ( m_aoPass ) { m_aoPass->setAoRadius( r ); } -} -int NodeBasedRenderer::getAoSamplingDensity() const { - return m_aoSamplingPoints; -} -void NodeBasedRenderer::setAoSamplingDensity( int d ) { - m_aoSamplingPoints = d; - auto sphereSampler = std::make_unique<SphereSampler>( m_aoSamplingMethod, m_aoSamplingPoints ); - if ( m_aoPass ) { m_aoPass->setSampler( std::move( sphereSampler ) ); } +bool NodeBasedRenderer::addPass( std::shared_ptr<RadiumNBR::RenderPass> pass, int rank, bool defaultPass ) { + const auto [itPass, success] = m_renderPasses.insert( {rank, pass} ); + if ( defaultPass && success ) { + m_defaultPass = rank; + } + return success; } -void NodeBasedRenderer::wireframeMode( bool status ) { - enableWireframe( status ); - if ( m_wireframe ) { - m_wireframePass->activate(); - - m_aoPass->deactivate(); - m_emissivityPass->deactivate(); - m_envlightPass->deactivate(); - m_locallightPass->deactivate(); - m_transparencyPass->deactivate(); - m_volumelightPass->deactivate(); - - } else { - m_wireframePass->deactivate(); - - m_aoPass->activate(); - m_emissivityPass->activate(); - m_envlightPass->activate(); - m_locallightPass->activate(); - m_transparencyPass->activate(); - m_volumelightPass->activate(); - - } } -} // namespace RadiumNBR diff --git a/src/libRender/RadiumNBR/NodeBasedRenderer.hpp b/src/libRender/RadiumNBR/NodeBasedRenderer.hpp index 49c4c3a9f8223b8ce642c7571ae375c4a4657ca4..53d1ad7a17050ac9147d2bf41f20b5e57d49b474 100644 --- a/src/libRender/RadiumNBR/NodeBasedRenderer.hpp +++ b/src/libRender/RadiumNBR/NodeBasedRenderer.hpp @@ -1,7 +1,6 @@ #pragma once #include <RadiumNBR/NodeBasedRendererMacro.hpp> #include <RadiumNBR/RenderPass.hpp> -#include <RadiumNBR/SphereSampler.hpp> #include <Engine/Rendering/Renderer.hpp> @@ -9,26 +8,19 @@ namespace globjects { class Framebuffer; } -namespace Ra::Engine::Data { -class Texture; -} // namespace Ra::Engine::Data - namespace RadiumNBR { -class ClearPass; -class GeomPrePass; -class AccessibilityBufferPass; -class EmissivityPass; -class EnvLightPass; -class LocalLightPass; -class VolumeLightingPass; -class TransparencyPass; -class WireframePass; - -/** Advanced renderer for the Radium Engine - * This class implements a forward rendering algorithm with Z-prepass, multipass light accumulation - * for opaque and transparent objects. - * Once renderer, the final is composited with Ui, debug and - * X-ray objects renderings on demand. + +/** Node based for the Radium Engine + * This Renderer is fully configurable, either dynammically or programatically. + * It implements the Ra::Engine::Rendering/Renderer interface and cand be configured by adding + * as many RadiumNBR::RenderPass rendering passes. + * + * It defines two textures that migh be shared between passes : + * - a depth buffer attachable texture + * - a Linear space RGBA color texture + * + * It allows to apply a linearRGB to sRGB color transformation before displaying the image. + * * * @see rendering.md for description of the renderer */ @@ -39,19 +31,23 @@ class NodeBasedRenderer_LIBRARY_API NodeBasedRenderer : public Ra::Engine::Rende NodeBasedRenderer(); ~NodeBasedRenderer() override; - [[nodiscard]] std::string getRendererName() const override { return "Node Based Renderer"; } + [[nodiscard]] std::string getRendererName() const override { return "Configurable Renderer"; } + bool buildRenderTechnique( Ra::Engine::Rendering::RenderObject* ro ) const override; - void setEnvMap( const std::string& files ); - void showEnvMap( bool state ); - // TODO : define a way to configfure each passes without adding here specifi methods - // TODO the following might be removed in the future - Scalar getAoRadius() const; - void setAoRadius( Scalar r ); - int getAoSamplingDensity() const; - void setAoSamplingDensity( int d ); - void setEnvStrength( int s ); - void wireframeMode( bool status ); + /** add a pass to be executed at the given rank, and, optionally, is the default pass for the + * renderer. + * + * Passes are executed by increasing rank. + * [not yet available : If two passes have the same rank, they will be + * executed in arbitrary order]. + * + * The default pass (rank 0) might be used for specific render operations. + * + * If a pass with the same rank already exists in the Renderer, the given pass is not added nor is changed the default) + * @return true if the pass is insserted, false if not + */ + bool addPass( std::shared_ptr<RadiumNBR::RenderPass> pass, int rank, bool defaultPass = false ); protected: void initializeInternal() override; @@ -62,39 +58,34 @@ class NodeBasedRenderer_LIBRARY_API NodeBasedRenderer : public Ra::Engine::Rende void debugInternal( const Ra::Engine::Data::ViewingParameters& renderData ) override; void uiInternal( const Ra::Engine::Data::ViewingParameters& renderData ) override; + virtual void initShaders(); + virtual void initBuffers(); + + inline std::map<std::string, std::shared_ptr<Ra::Engine::Data::Texture>> &sharedTextures() { + return m_sharedTextures; + } + + inline globjects::Framebuffer *postprocessFbo() { + return m_postprocessFbo.get(); + } + + inline std::map< int, std::shared_ptr<RenderPass> >& renderPasses() { + return m_renderPasses; + } + + inline const std::map< int, std::shared_ptr<RenderPass> >& renderPasses() const { + return m_renderPasses; + } + + inline std::vector<RenderObjectPtr> *allRenderObjects() { + return &m_allRenderObjects; + } + + inline int defaultPass() const { + return m_defaultPass; + } + private: - void initPasses(); - void initShaders(); - void initBuffers(); - -#if 0 - struct NodeBasedRendererPasses { - static constexpr Ra::Core::Utils::Index DEFAULT_PASS{0}; - static constexpr Ra::Core::Utils::Index LIGHTING_OPAQUE_PASS{DEFAULT_PASS}; - static constexpr Ra::Core::Utils::Index GEOM_PASS{1}; - static constexpr Ra::Core::Utils::Index ACCESSIBILITY_PASS{2}; - static constexpr Ra::Core::Utils::Index CLEAR_PASS{3}; - static constexpr Ra::Core::Utils::Index ENVMAP_LIGHTING_OPAQUE_PASS{4}; - static constexpr Ra::Core::Utils::Index EMISSIVITY_PASS{5}; - static constexpr Ra::Core::Utils::Index LIGHTING_TRANSPARENT_PASS{6}; - static constexpr Ra::Core::Utils::Index LIGHTING_VOLUME_PASS{7}; - }; -#else - enum NodeBasedRendererPasses : int { - DEFAULT_PASS = 0, - LIGHTING_OPAQUE_PASS = DEFAULT_PASS, - GEOM_PASS, - ACCESSIBILITY_PASS, - CLEAR_PASS, - ENVMAP_LIGHTING_OPAQUE_PASS, - EMISSIVITY_PASS, - LIGHTING_TRANSPARENT_PASS, - LIGHTING_VOLUME_PASS, - WIREFRAME_PASS, - NUM_PASSES - }; -#endif - protected: /// textures own by the Renderer but shared across passes std::map<std::string, std::shared_ptr<Ra::Engine::Data::Texture>> m_sharedTextures; @@ -102,51 +93,13 @@ class NodeBasedRenderer_LIBRARY_API NodeBasedRenderer : public Ra::Engine::Rende std::unique_ptr<globjects::Framebuffer> m_postprocessFbo; /// vector of this renderer render passes, sorted by precedence (first pass is at index 0) - std::vector<std::shared_ptr<RenderPass>> m_renderPasses; - - /// Subset of the objects that are transparent and need special rendering - std::vector<RenderObjectPtr> m_transparentRenderObjects; - - /// Subset of the objects that are volumetric - std::vector<RenderObjectPtr> m_volumetricRenderObjects; + std::map< int, std::shared_ptr<RenderPass> > m_renderPasses; /// Backup of all objects so that global passses can execute std::vector<RenderObjectPtr> m_allRenderObjects; - /// The ambiant occlusion pass - std::shared_ptr<AccessibilityBufferPass> m_aoPass; - // The sampling method of the sphere sampler - SphereSampler::SamplingMethod m_aoSamplingMethod{ SphereSampler::SamplingMethod::HAMMERSLEY }; - // The number of points for the sampler - int m_aoSamplingPoints{ 64 }; - - /// clear the final ouput image - std::shared_ptr<ClearPass> m_clearPass; - - /// The zprepass - std::shared_ptr<GeomPrePass> m_zPrePass; - - /// The emissivity pass - std::shared_ptr<EmissivityPass> m_emissivityPass; - - /// The envlight pass - std::shared_ptr<EnvLightPass> m_envlightPass; - - /// The local lighting pass - std::shared_ptr<LocalLightPass> m_locallightPass; - - /// The volume lighting pass - std::shared_ptr<VolumeLightingPass> m_volumelightPass; - - /// The transparency (Order independant transparency) pass - std::shared_ptr<TransparencyPass> m_transparencyPass; - - /// The transparency (Order independant transparency) pass - std::shared_ptr<WireframePass> m_wireframePass; - - /// Is an envmap attached to the renderer - bool m_hasEnvMap{ false }; - + /// The default pass + int m_defaultPass{-1}; }; -} // namespace RadiumNBR +} diff --git a/src/libRender/RadiumNBR/RenderPass.hpp b/src/libRender/RadiumNBR/RenderPass.hpp index e9b71569cfa933c611eccdfa8f0f6849a5c71fe2..8e07a08cb629bbe1cecf9df455ba045ca3d9c63a 100644 --- a/src/libRender/RadiumNBR/RenderPass.hpp +++ b/src/libRender/RadiumNBR/RenderPass.hpp @@ -124,6 +124,8 @@ class NodeBasedRenderer_LIBRARY_API RenderPass // is the pass active ? [[nodiscard]] inline bool isActive() { return m_active; } + [[nodiscard]] inline int index() const { return int(m_idx); } + /// @todo : Having protected member is a bad idea /// @see https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c133-avoid-protected-data protected: