Skip to content
Snippets Groups Projects
Commit fbc1df78 authored by Mathias Paulin's avatar Mathias Paulin :speech_balloon:
Browse files

Add a lighting pass with customization of final color computation.

parent 218eea89
No related branches found
No related tags found
No related merge requests found
...@@ -2,50 +2,73 @@ ...@@ -2,50 +2,73 @@
#include <Gui/BaseApplication.hpp> #include <Gui/BaseApplication.hpp>
#include <Gui/RadiumWindow/SimpleWindowFactory.hpp> #include <Gui/RadiumWindow/SimpleWindowFactory.hpp>
// To manage the scene
#include <Core/Geometry/MeshPrimitives.hpp>
#include <Engine/Scene/EntityManager.hpp>
#include <Engine/Scene/GeometryComponent.hpp>
#include <Engine/Scene/GeometrySystem.hpp>
// Include the customizable renderer system (only the used part here) // Include the customizable renderer system (only the used part here)
#include <RadiumNBR/NodeBasedRenderer.hpp> #include <RadiumNBR/NodeBasedRenderer.hpp>
#include <RadiumNBR/Passes/ClearPass.hpp> #include <RadiumNBR/Passes/ClearPass.hpp>
#include <RadiumNBR/Passes/CustomAttribToColorPass.hpp>
#include <RadiumNBR/Passes/GeomPrepass.hpp> #include <RadiumNBR/Passes/GeomPrepass.hpp>
#include <RadiumNBR/Passes/WireframePass.hpp>
// To add attribs to loaded objects
#include <Engine/Data/Mesh.hpp>
#include <Engine/Rendering/RenderObject.hpp>
#include <Engine/Rendering/RenderObjectManager.hpp>
#include <Engine/Scene/EntityManager.hpp>
#include <Engine/Scene/SystemDisplay.hpp>
#include <Core/Utils/Log.hpp>
using namespace Ra::Core::Utils; // log
/** /**
* This class parameterize the renderer just after the OpenGL system was initialized. * This class parameterize the renderer just after the OpenGL system was initialized.
* In the functor, The OpenGL context of the drawing window is activated. * when a method of this controler is called, the OpenGL context of the drawing window is activated.
*/ */
class RendererController : public RadiumNBR::RenderControlFunctor { class RendererController : public RadiumNBR::RenderControlFunctor
{
public: public:
/*
void configure(RadiumNBR::NodeBasedRenderer *renderer, int w, int h) override { * Called once : configure the renderer by adding passes and allocating controler resources
LOG( Ra::Core::Utils::logINFO ) << "Customizing the renderer " << renderer->getRendererName(); */
void configure( RadiumNBR::NodeBasedRenderer* renderer, int w, int h ) override {
LOG( Ra::Core::Utils::logINFO )
<< "Customizing the renderer " << renderer->getRendererName();
//! [Caching some helpers and data from the Engine and the renderer] //! [Caching some helpers and data from the Engine and the renderer]
auto resourcesCheck = Ra::Core::Resources::getResourcesPath( auto resourcesCheck = Ra::Core::Resources::getResourcesPath(
reinterpret_cast<void*>( &RadiumNBR::NodeBasedRendererMagic ), { "Resources/RadiumNBR" } ); reinterpret_cast<void*>( &RadiumNBR::NodeBasedRendererMagic ),
{"Resources/RadiumNBR"} );
if ( !resourcesCheck ) if ( !resourcesCheck )
{ {
LOG( Ra::Core::Utils::logERROR ) << "Unable to find resources for NodeBasedRenderer!"; LOG( Ra::Core::Utils::logERROR ) << "Unable to find resources for NodeBasedRenderer!";
return; return;
} else {
LOG( Ra::Core::Utils::logINFO ) << "NodeBasedRenderer Resources are at " << *resourcesCheck;
} }
auto resourcesPath{ *resourcesCheck }; else
{
LOG( Ra::Core::Utils::logINFO )
<< "NodeBasedRenderer Resources are at " << *resourcesCheck;
}
auto resourcesPath{*resourcesCheck};
auto shaderManager = Ra::Engine::RadiumEngine::getInstance()->getShaderProgramManager(); auto shaderManager = Ra::Engine::RadiumEngine::getInstance()->getShaderProgramManager();
auto colortexture = renderer->sharedTextures().find( "Linear RGB (RadiumNBR)"); auto colortexture = renderer->sharedTextures().find( "Linear RGB (RadiumNBR)" );
auto depthtexture = renderer->sharedTextures().find( "Depth (RadiumNBR)" ); auto depthtexture = renderer->sharedTextures().find( "Depth (RadiumNBR)" );
//! [Caching some helpers and data from the Engine and the renderer] //! [Caching some helpers and data from the Engine and the renderer]
//! [Adding a clear-screen pass] //! [Adding a clear-screen pass]
{ {
// pass that draw no object and is positionned at rank 0 // pass that draw no object and is positioned at rank 0
auto pass = std::make_shared<RadiumNBR::ClearPass>( nullptr, 0 ); auto pass = std::make_shared<RadiumNBR::ClearPass>( nullptr, 0 );
// set the output of the pass : clear the renderer Linear RGB output texture // set the output of the pass : clear the renderer Linear RGB output texture
pass->setOutput( *colortexture ); pass->setOutput( *colortexture );
// set the clear color (pass internal state) // set the clear color (pass internal state)
pass->setBackground( renderer->getBackgroundColor()); pass->setBackground( renderer->getBackgroundColor() );
pass->initializePass( w, h, shaderManager ); pass->initializePass( w, h, shaderManager );
// add the pass to the renderer and activate it // add the pass to the renderer and activate it
renderer->addPass(pass, pass->index()); renderer->addPass( pass, pass->index() );
pass->activate(); pass->activate();
} }
//! [Adding a clear-screen pass] //! [Adding a clear-screen pass]
...@@ -60,28 +83,65 @@ class RendererController : public RadiumNBR::RenderControlFunctor { ...@@ -60,28 +83,65 @@ class RendererController : public RadiumNBR::RenderControlFunctor {
pass->setResourcesDir( resourcesPath ); pass->setResourcesDir( resourcesPath );
pass->initializePass( w, h, shaderManager ); pass->initializePass( w, h, shaderManager );
// add the pass to the renderer and activate it // add the pass to the renderer and activate it
renderer->addPass(pass, pass->index()); renderer->addPass( pass, pass->index() );
pass->activate(); pass->activate();
} }
//! [Adding a Z-only pass] //! [Adding a Z-only pass]
//! [Adding a wireframe pass] //! [Adding a CustomAttribToColorPass pass]
{ {
// this pass draw all the objects in wareframe, using the shared z-buffer for hidden line removal and drawing // this pass draw all the objects using the custom color function,
// in the shared color buffer. // Rendering is done against the shared z-buffer for hidden line removal and
auto pass = std::make_shared<RadiumNBR::WireframePass>( renderer->allRenderObjects(), 2 ); // into the shared color buffer.
m_customPass = std::make_shared<RadiumNBR::CustomAttribToColorPass>(
renderer->allRenderObjects(), 2 );
// set the input/output textures // set the input/output textures
pass->setInputs( *depthtexture ); m_customPass->setInputs( *depthtexture );
pass->setOutput( *colortexture ); m_customPass->setOutput( *colortexture );
m_customPass->setLightManager( renderer->getLightManager() );
m_customPass->setAttribToColorFunc( m_vertexFunction, m_fragmentFunction );
// configure access to shader/resources files and initialize the pass // configure access to shader/resources files and initialize the pass
pass->setResourcesDir( resourcesPath ); m_customPass->setResourcesDir( resourcesPath );
pass->initializePass( w, h, shaderManager ); m_customPass->initializePass( w, h, shaderManager );
// add the pass to the renderer and activate it // add the pass to the renderer and activate it
renderer->addPass(pass, pass->index()); renderer->addPass( m_customPass, m_customPass->index() );
pass->activate(); m_customPass->activate();
} }
//! [Adding a wireframe pass] //! [Adding a CustomAttribToColorPass pass]
}
void update( const Ra::Engine::Data::ViewingParameters& ) override{
/* This function is called once before each frame.
* You can use it to modify the scene, or modify the computation function of the renderer
* For this, just call
* m_customPass->setAttribToColorFunc( customVertexAttrib, customFragmentColor );
* with the wanted shader glsl source code.
*/
};
void resize( int w, int h ) override{
/* if you have resizeable resources in your controller, this method is called each time the
* viewer window is resized so that you can dimension your resources accordingly
*/
};
/// Set the custom glsl function for attrib management (vertex) and colorcomputation (fragment)
void setAttribToColorFunc( const std::string& vertex_source,
const std::string& fragment_source ) {
m_vertexFunction = vertex_source;
m_fragmentFunction = fragment_source;
if ( m_customPass )
{ m_customPass->setAttribToColorFunc( m_vertexFunction, m_fragmentFunction ); }
} }
private:
/// The custom pass if needed for modification
std::shared_ptr<RadiumNBR::CustomAttribToColorPass> m_customPass;
///
std::string m_vertexFunction{"void outputCustomAttribs() {}"};
std::string m_fragmentFunction{"vec4 computeCustomColor(Material mat, vec3 lightDir, vec3 "
"viewDir) {return vec4(1, 0, 0, 1);}"};
}; };
/** /**
...@@ -90,19 +150,142 @@ class RendererController : public RadiumNBR::RenderControlFunctor { ...@@ -90,19 +150,142 @@ class RendererController : public RadiumNBR::RenderControlFunctor {
class DemoWindowFactory : public Ra::Gui::BaseApplication::WindowFactory class DemoWindowFactory : public Ra::Gui::BaseApplication::WindowFactory
{ {
public: public:
DemoWindowFactory() = delete; DemoWindowFactory() = delete;
~DemoWindowFactory() = default; ~DemoWindowFactory() = default;
explicit DemoWindowFactory( std::shared_ptr<RadiumNBR::NodeBasedRenderer> r) : renderer(r) {} explicit DemoWindowFactory( std::shared_ptr<RadiumNBR::NodeBasedRenderer> r ) : renderer( r ) {}
inline Ra::Gui::MainWindowInterface* createMainWindow() const override { inline Ra::Gui::MainWindowInterface* createMainWindow() const override {
auto window = new Ra::Gui::SimpleWindow(); auto window = new Ra::Gui::SimpleWindow();
window->addRenderer(renderer->getRendererName(), renderer); window->addRenderer( renderer->getRendererName(), renderer );
return window; return window;
} }
private: private:
std::shared_ptr<RadiumNBR::NodeBasedRenderer> renderer; std::shared_ptr<RadiumNBR::NodeBasedRenderer> renderer;
}; };
/** Process the scene to add the custom attribs to all objects
*/
void AddCustomAttributeToMeshes() {
auto entityManager = Ra::Engine::RadiumEngine::getInstance()->getEntityManager();
auto entities = entityManager->getEntities();
auto roManager = Ra::Engine::RadiumEngine::getInstance()->getRenderObjectManager();
for ( const auto e : entities )
{
if ( e == Ra::Engine::Scene::SystemEntity::getInstance() ) { continue; }
for ( const auto& c : e->getComponents() )
{
for ( const auto& roIdx : c->m_renderObjects )
{
const auto& ro = roManager->getRenderObject( roIdx );
if ( ro->getType() == Ra::Engine::Rendering::RenderObjectType::Geometry )
{
auto theMesh = ro->getMesh();
/* Could be helpfull if one can do
auto displayable = dynamic_cast<Ra::Engine::Data::CoreGeometryDisplayable< ???
>*>( theMesh.get() );
*/
auto displayMesh = dynamic_cast<Ra::Engine::Data::Mesh*>( theMesh.get() );
if ( displayMesh )
{
LOG( logINFO ) << "\t\tMesh " << displayMesh->getName()
<< " (TriangleMesh) is processed.";
displayMesh->addAttrib<Ra::Core::Vector4>(
"myCustomAttrib",
Ra::Core::Vector4Array{displayMesh->getNumVertices(),
Ra::Core::Utils::Color::Yellow()} );
displayMesh->setDirty( "myCustomAttrib" );
}
else
{
auto polyMesh = dynamic_cast<Ra::Engine::Data::PolyMesh*>( theMesh.get() );
if ( polyMesh )
{
LOG( logINFO ) << "\t\tMesh " << polyMesh->getName()
<< " (PolyMesh) is processed.";
polyMesh->addAttrib<Ra::Core::Vector4>(
"myCustomAttrib",
Ra::Core::Vector4Array{polyMesh->getNumVertices(),
Ra::Core::Utils::Color::Magenta()} );
polyMesh->setDirty( "myCustomAttrib" );
}
else
{
auto pointCloud =
dynamic_cast<Ra::Engine::Data::PointCloud*>( theMesh.get() );
if ( pointCloud )
{
LOG( logINFO ) << "\t\tPointCloud " << pointCloud->getName()
<< " is processed.";
pointCloud->addAttrib<Ra::Core::Vector4>(
"myCustomAttrib",
Ra::Core::Vector4Array{pointCloud->getNumVertices(),
Ra::Core::Utils::Color::Blue()} );
pointCloud->setDirty( "myCustomAttrib" );
}
else
{
LOG( logINFO ) << "\t\tMesh " << theMesh->getName()
<< " is nor a trianglemesh, nor a polymesh, nor a "
"point cloud ... skipping";
}
}
}
}
}
}
}
}
/**
* The custom color computation shaders
*/
/* Vertex shader : here, the objective is to transform any set ov vertex
* attribute to any set of fragment shaders input.
* In this example, we just copy the custom attrib to the output.
* All standards attribs can be accessed using their Radium name.
* If needed, all these vectors are expresed in the world frame :
* out_viewVector, out_lightVector, out_position, out_normal (if available)
* if available from the underlying geometry, the following parameters can be used :
* out_texcoord, out_vertexcolor.
*
* Note that this string could also be loaded from a file and/or manually edited if you
* add an edition widget as in Radium app demo
*/
const std::string customVertexAttrib{"in vec4 myCustomAttrib;\n"
"out vec4 fragCustomAttrib;\n"
"\nvoid outputCustomAttribs() { \n"
"fragCustomAttrib=myCustomAttrib;\n"
"}\n"};
/* Fragment shader : here, the objective is to compute the final color of the fragment.
* This function get the Material associated with the objet. This material could be
* used through the Radium GLSL BSDF interface (see Radium doc)
* All standard interpolated attributes from vertices can be fetched using the Radium
* GLSL VertexAttribInterface (see Radium doc)
* The Light could be used through the Radium GLSL light interface.
*
* In the following exemple, the lighting is computed using the custom attrib as
* diffuse reflectance.
*
* Note that this string could also be loaded from a file and/or manually edited if you
* add an edition widget as in Radium app demo
*/
const std::string customFragmentColor{
"in vec4 fragCustomAttrib;\n"
"\nvec4 computeCustomColor(Material mat, vec3 lightDir, vec3 viewDir) {\n"
"vec3 diffColor; \n"
"vec3 specColor; \n"
"getSeparateBSDFComponent( mat, getPerVertexTexCoord(), lightDir, viewDir,\n"
"vec3(0, 0, 1), diffColor, specColor );\n"
"return vec4( (specColor+fragCustomAttrib.rgb)*max(lightDir.z, 0), 1); \n"
"}\n"};
/**
* main function.
*/
int main( int argc, char* argv[] ) { int main( int argc, char* argv[] ) {
if ( argc < 2 ) if ( argc < 2 )
{ {
...@@ -112,6 +295,7 @@ int main( int argc, char* argv[] ) { ...@@ -112,6 +295,7 @@ int main( int argc, char* argv[] ) {
//! [Instatiating the renderer giving a customization functor] //! [Instatiating the renderer giving a customization functor]
RendererController renderControl; RendererController renderControl;
auto renderer = std::make_shared<RadiumNBR::NodeBasedRenderer>( renderControl ); auto renderer = std::make_shared<RadiumNBR::NodeBasedRenderer>( renderControl );
renderControl.setAttribToColorFunc( customVertexAttrib, customFragmentColor );
//! [Instatiating the renderer giving a customization functor] //! [Instatiating the renderer giving a customization functor]
//! [Instatiating the application] //! [Instatiating the application]
...@@ -123,5 +307,63 @@ int main( int argc, char* argv[] ) { ...@@ -123,5 +307,63 @@ int main( int argc, char* argv[] ) {
app.initialize( DemoWindowFactory( renderer ) ); app.initialize( DemoWindowFactory( renderer ) );
//! [Initializing the application] //! [Initializing the application]
//! [Processing the scene to define custom attributes]
AddCustomAttributeToMeshes();
//! [Processing the scene to define custom attributes]
return app.exec();
}
#if 0
int main( int argc, char* argv[] ) {
//! [Instatiating the renderer giving a customization functor]
RendererController renderControl;
auto renderer = std::make_shared<RadiumNBR::NodeBasedRenderer>( renderControl );
//! [Instatiating the renderer giving a customization functor]
//! [Instatiating the application]
Ra::Gui::BaseApplication app( argc, argv );
//! [Instatiating the application]
//! [Initializing the application]
// The customization functor is called here
app.initialize( DemoWindowFactory( renderer ) );
//! [Initializing the application]
//! [show the base grid on the renderer]
renderer->showDebug( false );
//! [show the base grid on the renderer]
//! [Creating the cube]
auto cube = Ra::Core::Geometry::makeSharpBox( {0.1f, 0.1f, 0.1f} );
//! [Creating the cube]
//! [Colorize the Cube]
cube.addAttrib(
"myCustomAttrib",
Ra::Core::Vector4Array{cube.vertices().size(), Ra::Core::Utils::Color::Yellow()} );
//! [Colorize the Cube]
//! [Create the engine entity for the cube]
auto e = app.m_engine->getEntityManager()->createEntity( "Green cube" );
//! [Create the engine entity for the cube]
//! [Create a geometry component with the cube]
auto c =
new Ra::Engine::Scene::TriangleMeshComponent( "Cube Mesh", e, std::move( cube ), nullptr );
//! [Create a geometry component with the cube]
//! [Register the entity/component association to the geometry system ]
auto geometrySystem = app.m_engine->getSystem( "GeometrySystem" );
geometrySystem->addComponent( e, c );
//! [Register the entity/component association to the geometry system ]
//! [Tell the window that something is to be displayed]
app.m_mainWindow->prepareDisplay();
//! [Tell the window that something is to be displayed]
return app.exec(); return app.exec();
} }
#endif
...@@ -34,6 +34,7 @@ set(sources ...@@ -34,6 +34,7 @@ set(sources
RadiumNBR/FullFeatureRenderer.cpp RadiumNBR/FullFeatureRenderer.cpp
RadiumNBR/SphereSampler.cpp RadiumNBR/SphereSampler.cpp
RadiumNBR/Passes/ClearPass.cpp RadiumNBR/Passes/ClearPass.cpp
RadiumNBR/Passes/CustomAttribToColorPass.cpp
RadiumNBR/Passes/DebugPass.cpp RadiumNBR/Passes/DebugPass.cpp
RadiumNBR/Passes/GeomPrepass.cpp RadiumNBR/Passes/GeomPrepass.cpp
RadiumNBR/Passes/AccessibilityBufferPass.cpp RadiumNBR/Passes/AccessibilityBufferPass.cpp
...@@ -53,6 +54,7 @@ set(public_headers ...@@ -53,6 +54,7 @@ set(public_headers
RadiumNBR/RenderPass.hpp RadiumNBR/RenderPass.hpp
RadiumNBR/SphereSampler.hpp RadiumNBR/SphereSampler.hpp
RadiumNBR/Passes/ClearPass.hpp RadiumNBR/Passes/ClearPass.hpp
RadiumNBR/Passes/CustomAttribToColorPass.hpp
RadiumNBR/Passes/DebugPass.hpp RadiumNBR/Passes/DebugPass.hpp
RadiumNBR/Passes/GeomPrepass.hpp RadiumNBR/Passes/GeomPrepass.hpp
RadiumNBR/Passes/AccessibilityBufferPass.hpp RadiumNBR/Passes/AccessibilityBufferPass.hpp
......
...@@ -88,6 +88,9 @@ class NodeBasedRenderer_LIBRARY_API NodeBasedRenderer : public Ra::Engine::Rende ...@@ -88,6 +88,9 @@ class NodeBasedRenderer_LIBRARY_API NodeBasedRenderer : public Ra::Engine::Rende
/// Hide or show the Debug objects /// Hide or show the Debug objects
void showDebug( bool b ); void showDebug( bool b );
/// Access the default light manager
Ra::Engine::Scene::LightManager* getLightManager() { return m_lightmanagers[0]; }
protected: protected:
void initializeInternal() override; void initializeInternal() override;
void resizeInternal() override; void resizeInternal() override;
......
#include <RadiumNBR/Passes/CustomAttribToColorPass.hpp>
#ifdef PASSES_LOG
# include <Core/Utils/Log.hpp>
using namespace Ra::Core::Utils; // log
#endif
#include <Engine/Data/Material.hpp>
#include <Engine/Data/ShaderConfigFactory.hpp>
#include <Engine/Data/ShaderProgramManager.hpp>
#include <Engine/Data/Texture.hpp>
#include <Engine/Rendering/RenderObject.hpp>
#include <Engine/Scene/LightManager.hpp>
#include <globjects/Framebuffer.h>
namespace RadiumNBR {
using namespace gl;
static const GLenum buffers[] = {GL_COLOR_ATTACHMENT0};
CustomAttribToColorPass::CustomAttribToColorPass(
const std::vector<RenderObjectPtr>* objectsToRender,
const Ra::Core::Utils::Index& idx ) :
RenderPass( "Custom AttribToColor pass", idx, objectsToRender ) {}
CustomAttribToColorPass::~CustomAttribToColorPass() = default;
bool CustomAttribToColorPass::initializePass( size_t /* width */,
size_t /* height */,
Ra::Engine::Data::ShaderProgramManager* shaderMngr ) {
m_shaderMngr = shaderMngr;
m_fbo = std::make_unique<globjects::Framebuffer>();
return true;
}
void CustomAttribToColorPass::setInputs( const SharedTextures& depthBuffer ) {
addImportedTextures( {"CustomAtt2Clr::Depth", depthBuffer.second} );
}
void CustomAttribToColorPass::setOutput( const SharedTextures& colorBuffer ) {
m_outputTexture = colorBuffer;
}
bool CustomAttribToColorPass::update() {
return true;
}
void CustomAttribToColorPass::resize( size_t width, size_t height ) {
// Only resize the owned textures. Imported one are resized by their owner
for ( auto& t : m_localTextures )
{
t.second->resize( width, height );
}
for ( auto& t : m_sharedTextures )
{
t.second->resize( width, height );
}
m_fbo->bind();
m_fbo->attachTexture( GL_DEPTH_ATTACHMENT,
m_importedTextures["CustomAtt2Clr::Depth"]->texture() );
m_fbo->attachTexture( GL_COLOR_ATTACHMENT0, m_outputTexture.second->texture() );
#ifdef PASSES_LOG
if ( m_fbo->checkStatus() != GL_FRAMEBUFFER_COMPLETE )
{ LOG( logERROR ) << "FBO Error (EmissivityPass::resize): " << m_fbo->checkStatus(); }
#endif
// finished with fbo, undbind to bind default
globjects::Framebuffer::unbind();
}
void CustomAttribToColorPass::execute(
const Ra::Engine::Data::ViewingParameters& viewParams ) const {
m_fbo->bind();
// only draw into 1 buffers (Color)
GL_ASSERT( glDrawBuffers( 1, buffers ) );
GL_ASSERT( glDepthMask( GL_FALSE ) );
GL_ASSERT( glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ) );
GL_ASSERT( glEnable( GL_DEPTH_TEST ) );
GL_ASSERT( glDepthFunc( GL_LEQUAL ) );
GL_ASSERT( glEnable( GL_BLEND ) );
glBlendFunc( GL_ONE, GL_ONE );
// To prevent z-fighting, remove polygon offset
glDisable( GL_POLYGON_OFFSET_FILL );
if ( m_lightmanager->count() > 0 )
{
// for ( const auto& l : m_lights )
for ( size_t i = 0; i < m_lightmanager->count(); ++i )
{
Ra::Engine::Data::RenderParameters passParams;
passParams.concatParameters( m_passParams );
const auto l = m_lightmanager->getLight( i );
l->getRenderParameters( passParams );
for ( const auto& ro : *m_objectsToRender )
{
ro->render( passParams, viewParams, passIndex() );
}
}
}
// need to maintain global state invariant
glEnable( GL_POLYGON_OFFSET_FILL );
GL_ASSERT( glDisable( GL_BLEND ) );
}
bool CustomAttribToColorPass::buildRenderTechnique(
const Ra::Engine::Rendering::RenderObject* ro,
Ra::Engine::Rendering::RenderTechnique& rt ) const {
if ( m_needConfigRebuild )
{
m_needConfigRebuild = false;
Ra::Engine::Data::ShaderConfigurationFactory::removeConfiguration(
{"CustomAtt2ClrPass::CustomColorProgram"} );
}
std::string resourcesRootDir = getResourcesDir();
auto mat = const_cast<Ra::Engine::Rendering::RenderObject*>( ro )->getMaterial();
// Volumes are not allowed here
if ( mat->getMaterialAspect() == Ra::Engine::Data::Material::MaterialAspect::MAT_DENSITY )
{ return false; }
if ( auto cfg = Ra::Engine::Data::ShaderConfigurationFactory::getConfiguration(
{"CustomAtt2ClrPass::CustomColorProgram"} ) )
{ rt.setConfiguration( *cfg, passIndex() ); }
else
{
// This part is the default configuration for this pass
// In this shader, the definition of the function void outputCustomAttrib(), along the
// declaration of input attribs and output result must be appended to the source.
// e.g.
// in vec3 attribName;
// out vec3 frag_attribName;
// void outputCustomAttrib() {
// frag_attribName = attribName;
// }
const std::string vertexShaderSource{
"#include \"TransformStructs.glsl\"\n"
"#include \"DefaultLight.glsl\"\n"
"layout (location = 0) in vec3 in_position;\n"
"layout (location = 1) in vec3 in_normal;\n"
"layout (location = 2) in vec3 in_texcoord;\n"
"layout (location = 3) in vec3 in_vertexcolor;\n"
"#ifndef DONT_USE_INPUT_TANGENT\n"
"layout( location = 4 ) in vec3 in_tangent;\n"
"#endif\n"
"layout (location = 0) out vec3 out_position;\n"
"layout (location = 1) out vec3 out_normal;\n"
"layout (location = 2) out vec3 out_texcoord;\n"
"layout (location = 3) out vec3 out_vertexcolor;\n"
"#ifndef DONT_USE_INPUT_TANGENT\n"
"layout( location = 4 ) out vec3 out_tangent;\n"
"#endif\n"
"layout (location = 5) out vec3 out_viewVector;\n"
"layout (location = 6) out vec3 out_lightVector;\n"
"uniform Transform transform;\n"
"void outputCustomAttribs();"
"void main() {\n"
"mat4 mvp = transform.proj * transform.view * transform.model;\n"
"gl_Position = mvp * vec4(in_position, 1.0);\n"
"vec4 pos = transform.model * vec4(in_position, 1.0);\n"
"pos /= pos.w;\n"
"vec3 normal = mat3(transform.worldNormal) * in_normal;\n"
"vec3 tangent = mat3(transform.model) * in_tangent;\n"
"vec3 eye = -transform.view[3].xyz * mat3(transform.view);\n"
"out_position = vec3(pos);\n"
"out_normal = normal;\n"
"out_texcoord = in_texcoord;\n"
"out_vertexcolor = in_vertexcolor;\n"
"#ifndef DONT_USE_INPUT_TANGENT\n"
"out_tangent = tangent;\n"
"#endif\n"
"out_viewVector = vec3(eye - out_position);\n"
"out_lightVector = getLightDirection(light, out_position);\n"
"outputCustomAttribs();"
"}\n"};
// the function computeCustomColor, alongside the declaration of frag_attrib is appended to
// the source
const std::string fragmentShadersource{
"#include \"DefaultLight.glsl\"\n"
"#include \"VertexAttribInterface.frag.glsl\"\n"
"layout (location = 5) in vec3 in_viewVector;\n"
"layout (location = 6) in vec3 in_lightVector;\n"
"layout (location = 0) out vec4 out_color;\n"
"vec4 computeCustomColor(Material mat, vec3 light_dir, vec3 view_dir);\n"
"void main()\n"
"{\n"
"// All vectors are in world space\n"
"// A material is always evaluated in the fragment local Frame \n"
"// compute matrix from World to local Frame \n"
"vec3 normalWorld = getWorldSpaceNormal();// normalized interpolated normal \n"
"vec3 tangentWorld = getWorldSpaceTangent();// normalized tangent \n"
"vec3 binormalWorld = getWorldSpaceBiTangent();// normalized bitangent \n"
"// discard non opaque fragment \n"
"vec4 bc = getDiffuseColor(material, getPerVertexTexCoord()); \n"
"if (toDiscard(material, bc)) \n"
"discard; \n"
"// Apply normal mapping \n"
"normalWorld = getNormal(material, getPerVertexTexCoord(), \n"
"normalWorld, tangentWorld, binormalWorld);// normalized bump-mapped normal \n"
"binormalWorld = normalize(cross(normalWorld, tangentWorld));// normalized "
"tangent \n"
"tangentWorld = normalize(cross(binormalWorld, normalWorld));// normalized "
"bitangent \n"
"mat3 world2local; \n"
"world2local[0] = vec3(tangentWorld.x, binormalWorld.x, normalWorld.x); \n"
"world2local[1] = vec3(tangentWorld.y, binormalWorld.y, normalWorld.y); \n"
"world2local[2] = vec3(tangentWorld.z, binormalWorld.z, normalWorld.z); \n"
"// transform all vectors in local frame so that N = (0, 0, 1); \n"
"vec3 lightDir = normalize(world2local * in_lightVector);// incident direction \n"
"vec3 viewDir = normalize(world2local * in_viewVector);// outgoing direction\n"
"out_color = computeCustomColor(material, lightDir, viewDir);\n"
"}\n"};
Ra::Engine::Data::ShaderConfiguration theConfig{"CustomAtt2ClrPass::CustomColorProgram"};
theConfig.addShaderSource( Ra::Engine::Data::ShaderType::ShaderType_VERTEX,
vertexShaderSource + m_customVertexAttrib );
theConfig.addShaderSource( Ra::Engine::Data::ShaderType::ShaderType_FRAGMENT,
fragmentShadersource + m_customFragmentColor );
theConfig.addInclude( "\"" + mat->getMaterialName() + ".glsl\"",
Ra::Engine::Data::ShaderType::ShaderType_FRAGMENT );
// Add to the ShaderConfigManager
Ra::Engine::Data::ShaderConfigurationFactory::addConfiguration( theConfig );
// Add to the RenderTechnique
rt.setConfiguration( theConfig, passIndex() );
}
rt.setParametersProvider( mat, passIndex() );
return true;
}
void CustomAttribToColorPass::setAttribToColorFunc( const std::string& vertex_source,
const std::string& fragment_source ) {
m_customVertexAttrib = vertex_source;
m_customFragmentColor = fragment_source;
m_needConfigRebuild = true;
}
void CustomAttribToColorPass::setLightManager( const Ra::Engine::Scene::LightManager* lm ) {
m_lightmanager = lm;
}
} // namespace RadiumNBR
#pragma once
#include <RadiumNBR/RenderPass.hpp>
#include <Core/Utils/Color.hpp>
namespace Ra::Engine::Scene {
class LightManager;
}
namespace Ra::Engine::Data {
class ShaderProgram;
} // namespace Ra::Engine::Data
namespace globjects {
class Framebuffer;
}
namespace RadiumNBR {
/// Render pass that draws objects using a custom color computation function (in glsl)
class CustomAttribToColorPass : public RenderPass
{
public:
CustomAttribToColorPass( const std::vector<RenderObjectPtr>* objectsToRender,
const Ra::Core::Utils::Index& idx );
~CustomAttribToColorPass() override;
bool buildRenderTechnique( const Ra::Engine::Rendering::RenderObject* ro,
Ra::Engine::Rendering::RenderTechnique& rt ) const override;
bool initializePass( size_t width,
size_t height,
Ra::Engine::Data::ShaderProgramManager* shaderMngr ) override;
bool update() override;
void resize( size_t width, size_t height ) override;
void execute( const Ra::Engine::Data::ViewingParameters& viewParams ) const override;
/// Add the output colorBuffer
void setOutput( const SharedTextures& colorBuffer );
/// These inputs must be computed before executing this pass : depth buffer
void setInputs( const SharedTextures& depthBuffer );
void setLightManager( const Ra::Engine::Scene::LightManager* lm );
/// Set the custom glsl function for attrib management (vertex) and colorcomputation (fragment)
void setAttribToColorFunc(const std::string &vertex_source, const std::string & fragment_source);
private:
/// The framebuffer used to render this pass
std::unique_ptr<globjects::Framebuffer> m_fbo{nullptr};
/// The Shader manager to use when building shaders
Ra::Engine::Data::ShaderProgramManager* m_shaderMngr{nullptr};
/// The color texture for output.Stored here for easy access.
SharedTextures m_outputTexture;
/// The custom Attrib Vertex shader function
std::string m_customVertexAttrib{};
/// the custom FragmentColor shader function
std::string m_customFragmentColor{};
/// State indicator
mutable bool m_needConfigRebuild{true};
/// The light manager to use
const Ra::Engine::Scene::LightManager* m_lightmanager;
};
} // namespace RadiumNBR
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment