diff --git a/src/DemoApp/main.cpp b/src/DemoApp/main.cpp index f299b1318d7915809d9f48a7c2c4eb1dce8fb5b6..a2b6dd5efcdde2d5ec45b8089053bf6642604936 100644 --- a/src/DemoApp/main.cpp +++ b/src/DemoApp/main.cpp @@ -166,16 +166,23 @@ const std::string customGeomAttrib{"in vec4 geomCustomAttrib[];\n" * 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, vec3 normal_world) {\n" + "in vec4 fragCustomAttrib;" + "\nvec4 computeCustomColor(Material mat, vec3 lightDir, vec3 viewDir, vec3 normal_world) { \n" "vec3 diffColor; \n" "vec3 specColor; \n" "getSeparateBSDFComponent( mat, getPerVertexTexCoord(), lightDir, viewDir,\n" "vec3(0, 0, 1), diffColor, specColor );\n" - "vec3 col = normal_world*0.5+0.5;\n" - "col *= fragCustomAttrib.rgb;\n" - "return vec4( (specColor+col)*max(lightDir.z, 0), 1); \n" - "}\n"}; + "vec3 envd;\n" + "vec3 envs;\n" + "int e = getEnvMapColors(mat, normal_world, envd, envs);" + "vec3 finalColor = normal_world*0.5+0.5;\n" + "finalColor *= fragCustomAttrib.rgb;\n" + "if (e==1) { finalColor = finalColor*envd + specColor*envs; }\n" + "else { finalColor = (finalColor + specColor) * max(lightDir.z, 0) \n" + " * lightContributionFrom(light, getWorldSpacePosition().xyz); }\n" + "return vec4( finalColor, 1); \n" + "}\n" + }; /** * Main code to demonstrate the use of a self configured node based renderer diff --git a/src/libRender/RadiumNBR/Gui/VisualizationGui.cpp b/src/libRender/RadiumNBR/Gui/VisualizationGui.cpp index c8b786923df249bcdb4f51339e7ab74737381a7a..72d9640613349511935493d9a9420b78e45060f5 100644 --- a/src/libRender/RadiumNBR/Gui/VisualizationGui.cpp +++ b/src/libRender/RadiumNBR/Gui/VisualizationGui.cpp @@ -50,6 +50,34 @@ buildControllerGui( NodeBasedRenderer* renderer, const std::function<void()>& ap false ); controlPanel->endLayout( true ); + controlPanel->beginLayout( QBoxLayout::LeftToRight ); + auto envmpClbck = [&controller, appUpdateCallback]( const std::string& files ) { + controller.setEnvMap( files ); + appUpdateCallback(); + }; + controlPanel->addFileInput( + "Environment map", envmpClbck, "../", "Images (*.png *.jpg *.pfm *.exr *hdr)" ); + + controlPanel->beginLayout( QBoxLayout::TopToBottom ); + controlPanel->addOption( + " Show envMap ", + [&controller, appUpdateCallback]( bool b ) { + controller.showEnvMap( b ); + appUpdateCallback(); + }, + true ); + + controlPanel->addSliderInput( + " Environment strength ", + [&controller, appUpdateCallback]( int v ) { + controller.setEnvStrength( v ); + appUpdateCallback(); + }, + 100 ); + controlPanel->endLayout(); + controlPanel->endLayout( true ); + + // TODO : add a double slider to get the good value. ask @dlyr for its doubleSliderClass ... controlPanel->beginLayout( QBoxLayout::LeftToRight ); auto splatSizeCtrl = [&controller]( double v ) { controller.setSplatSize( v ); }; diff --git a/src/libRender/RadiumNBR/Passes/CustomAttribToColorPass.cpp b/src/libRender/RadiumNBR/Passes/CustomAttribToColorPass.cpp index 2ebbe4e4f1f81083f291c7830c998908e8f150ae..fd42a9732899b7187ebaac95122d15c5c7ea2377 100644 --- a/src/libRender/RadiumNBR/Passes/CustomAttribToColorPass.cpp +++ b/src/libRender/RadiumNBR/Passes/CustomAttribToColorPass.cpp @@ -19,6 +19,35 @@ using namespace Ra::Core::Utils; // log namespace RadiumNBR { using namespace gl; +// Envmap shader source +static const std::string noopEnvMapFunction{ + "\nint getEnvMapColors(Material mat, vec3 normalWorld, out vec3 diffuse, out vec3 specular) {\n" + " diffuse = vec3(1); specular = vec3(1); return 0;\n" + "}\n\n" +}; + +static const std::string envMapFunction{ + "\nuniform samplerCube envTexture;\n" + "uniform int numLod;\n" + "uniform mat4 redShCoeffs;\n" + "uniform mat4 greenShCoeffs;\n" + "uniform mat4 blueShCoeffs;\n" + "uniform float envStrength;\n" + "const float OneOverPi = 0.3183098862;\n" + "int getEnvMapColors(Material mat, vec3 normalWorld, out vec3 diffuse, out vec3 specular) {\n" + " vec3 view = normalize(in_viewVector);\n" + " vec3 rfl = reflect(-view, normalWorld.xyz);\n" + " vec4 up = vec4(normalWorld, 1);\n" + " diffuse.r = dot(up, redShCoeffs * up);\n" + " diffuse.g = dot(up, greenShCoeffs * up);\n" + " diffuse.b = dot(up, blueShCoeffs * up);\n" + " diffuse *= envStrength/OneOverPi;\n" + " float cosTi = clamp(dot(rfl, normalWorld), 0.001, 1.);\n" + " float r = getGGXRoughness(material, getPerVertexTexCoord()) * numLod;\n" + " specular = textureLod(envTexture, rfl, r).rgb * cosTi * envStrength;\n" + " return 1;\n" + "}\n\n"}; + /* Test Point cloud parameter provider */ /* * WARNING : this class is here only for testing and experimentation purpose. @@ -114,16 +143,23 @@ void CustomAttribToColorPass::execute( glClearBufferfv( GL_DEPTH, 0, &clearDepth ); + + if ( m_envmap ) { + m_passParams.addParameter( "envStrength", m_envmap->getEnvStrength() ); + } + + // TODO : if an envmap is set, render with the envmap only ? 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 ); - + if (m_envmap) { + passParams.concatParameters( m_passParams ); + } for ( const auto& ro : *m_objectsToRender ) { ro->render( passParams, viewParams, passIndex() ); @@ -150,7 +186,7 @@ bool CustomAttribToColorPass::buildRenderTechnique( {"CustomAtt2ClrPass::CustomColorProgram" + ro->getName()} ) ) { rt.setConfiguration( *cfg, passIndex() ); - // TODO : warning, the param provider might be erroneous + // TODO : is this really usefull ? rt.setParametersProvider( mat, passIndex() ); } else @@ -238,8 +274,14 @@ bool CustomAttribToColorPass::buildRenderTechnique( ro->getName()}; theConfig.addShaderSource( Ra::Engine::Data::ShaderType::ShaderType_VERTEX, vertexShaderSource + m_customVertexAttrib ); - theConfig.addShaderSource( Ra::Engine::Data::ShaderType::ShaderType_FRAGMENT, - fragmentShadersource + m_customFragmentColor ); + if ( m_envmap ) { + theConfig.addShaderSource( Ra::Engine::Data::ShaderType::ShaderType_FRAGMENT, + fragmentShadersource + envMapFunction + m_customFragmentColor ); + } else { + theConfig.addShaderSource( Ra::Engine::Data::ShaderType::ShaderType_FRAGMENT, + fragmentShadersource + noopEnvMapFunction + m_customFragmentColor ); + } + theConfig.addInclude( "\"" + mat->getMaterialName() + ".glsl\"", Ra::Engine::Data::ShaderType::ShaderType_FRAGMENT ); @@ -285,39 +327,39 @@ bool CustomAttribToColorPass::buildRenderTechnique( "layout( location = 6 ) out vec3 out_lightVector;\n" "void propagateAttributes();\n" "void main() {\n" - "vec3 eye = -transform.view[3].xyz * mat3( transform.view );\n" - "// if no normal is provided, splats are aligned with the screen plane\n" - "vec3 normal = in_normal[0];\n" - "if ( length( normal ) < 0.1 ) { normal = normalize( eye - in_position[0] ); }\n" - "// orthonormal basis {u, v, normal}\n" - "vec3 u = vec3( 1, 0, 0 );\n" - "if ( abs( normal.x ) > 1e-3 ) { u = normalize( vec3( -normal.z / normal.x, 0, 1 ) ); }\n" - "vec3 v = normalize( cross( normal, u ) );\n" - "vec3 point[4];\n" - "point[0] = in_position[0] - pointCloudSplatRadius * ( u + v );\n" - "point[1] = point[0] + pointCloudSplatRadius * u * 2;\n" - "point[2] = point[0] + pointCloudSplatRadius * v * 2;\n" - "point[3] = point[0] + pointCloudSplatRadius * ( u + v ) * 2;\n" - "vec2 uv[4];\n" - "uv[0] = vec2( -1, -1 );\n" - "uv[1] = vec2( -1, +1 );\n" - "uv[2] = vec2( +1, -1 );\n" - "uv[3] = vec2( +1, +1 );\n" - "for ( int idx = 0; idx < 4; ++idx ) {\n" - " gl_Position = transform.proj * transform.view * vec4( point[idx], 1 );\n" - " out_position = point[idx];\n" - " out_texcoord = vec3( uv[idx], 0. );\n" - " out_normal = normal;\n" - " out_tangent = in_tangent[0];\n" - " out_viewVector = in_viewVector[0];\n" - " out_lightVector = in_lightVector[0];\n" - " out_vertexcolor = in_vertexColor[0];\n" - " propagateAttributes();" - " EmitVertex();\n" - "}\n" - "EndPrimitive();\n" + "vec3 eye = -transform.view[3].xyz * mat3( transform.view );\n" + "// if no normal is provided, splats are aligned with the screen plane\n" + "vec3 normal = in_normal[0];\n" + "if ( length( normal ) < 0.1 ) { normal = normalize( eye - in_position[0] ); }\n" + "// orthonormal basis {u, v, normal}\n" + "vec3 u = vec3( 1, 0, 0 );\n" + "if ( abs( normal.x ) > 1e-3 ) { u = normalize( vec3( -normal.z / normal.x, 0, 1 ) ); " "}\n" - }; + "vec3 v = normalize( cross( normal, u ) );\n" + "vec3 point[4];\n" + "point[0] = in_position[0] - pointCloudSplatRadius * ( u + v );\n" + "point[1] = point[0] + pointCloudSplatRadius * u * 2;\n" + "point[2] = point[0] + pointCloudSplatRadius * v * 2;\n" + "point[3] = point[0] + pointCloudSplatRadius * ( u + v ) * 2;\n" + "vec2 uv[4];\n" + "uv[0] = vec2( -1, -1 );\n" + "uv[1] = vec2( -1, +1 );\n" + "uv[2] = vec2( +1, -1 );\n" + "uv[3] = vec2( +1, +1 );\n" + "for ( int idx = 0; idx < 4; ++idx ) {\n" + " gl_Position = transform.proj * transform.view * vec4( point[idx], 1 );\n" + " out_position = point[idx];\n" + " out_texcoord = vec3( uv[idx], 0. );\n" + " out_normal = normal;\n" + " out_tangent = in_tangent[0];\n" + " out_viewVector = in_viewVector[0];\n" + " out_lightVector = in_lightVector[0];\n" + " out_vertexcolor = in_vertexColor[0];\n" + " propagateAttributes();" + " EmitVertex();\n" + "}\n" + "EndPrimitive();\n" + "}\n"}; auto pointCloudConst = dynamic_cast<const Ra::Engine::Scene::PointCloudComponent*>( ro->getComponent() ); @@ -328,7 +370,7 @@ bool CustomAttribToColorPass::buildRenderTechnique( geometryShadersource + m_customGeometryAttrib ); // construct the parameter provider for the technique paramProvider = std::make_shared<PointCloudParameterProvider>( mat, pointCloud ); - pointCloud->setSplatSize(0.025); + pointCloud->setSplatSize( 0.025 ); } // Add to the ShaderConfigManager Ra::Engine::Data::ShaderConfigurationFactory::addConfiguration( theConfig ); @@ -343,8 +385,8 @@ bool CustomAttribToColorPass::buildRenderTechnique( void CustomAttribToColorPass::setAttribToColorFunc( const std::string& vertex_source, const std::string& geometry_source, const std::string& fragment_source ) { - m_customVertexAttrib = vertex_source; - m_customFragmentColor = fragment_source; + m_customVertexAttrib = vertex_source; + m_customFragmentColor = fragment_source; m_customGeometryAttrib = geometry_source; rebuildShaders(); } @@ -363,14 +405,32 @@ void CustomAttribToColorPass::rebuildShaders() { m_needConfigRebuild = false; } -void CustomAttribToColorPass::setSplatSize(float s) { +void CustomAttribToColorPass::setSplatSize( float s ) { m_splatsSize = s; - for ( auto ro : *m_objectsToRender ) { + for ( auto ro : *m_objectsToRender ) + { auto pointCloud = dynamic_cast<Ra::Engine::Scene::PointCloudComponent*>( ro->getComponent() ); - if ( pointCloud ) { - pointCloud->setSplatSize( m_splatsSize ); - } + if ( pointCloud ) { pointCloud->setSplatSize( m_splatsSize ); } + } +} + +void CustomAttribToColorPass::setEnvMap( std::shared_ptr<EnvMap> envmp ) { + m_envmap = envmp; + if ( m_envmap ) + { + // Set the envmap parameter once. + // Warning : there is no way to remove parameters. Might segfault if this is not consistent + // with rendering usage + m_passParams.addParameter( "redShCoeffs", m_envmap->getShMatrix( 0 ) ); + m_passParams.addParameter( "greenShCoeffs", m_envmap->getShMatrix( 1 ) ); + m_passParams.addParameter( "blueShCoeffs", m_envmap->getShMatrix( 2 ) ); + m_passParams.addParameter( "envTexture", m_envmap->getEnvTexture() ); + int numLod = std::log2( + std::min( m_envmap->getEnvTexture()->width(), m_envmap->getEnvTexture()->height() ) ); + m_passParams.addParameter( "numLod", numLod ); } + rebuildShaders(); } + } // namespace RadiumNBR diff --git a/src/libRender/RadiumNBR/Passes/CustomAttribToColorPass.hpp b/src/libRender/RadiumNBR/Passes/CustomAttribToColorPass.hpp index 343e952045b5d0cf1e97522943a37ff9617dc809..7e1309a21eda19116aedb41ad0f6268485fcd0b3 100644 --- a/src/libRender/RadiumNBR/Passes/CustomAttribToColorPass.hpp +++ b/src/libRender/RadiumNBR/Passes/CustomAttribToColorPass.hpp @@ -1,5 +1,6 @@ #pragma once #include <RadiumNBR/RenderPass.hpp> +#include <RadiumNBR/EnvMap.hpp> #include <Core/Utils/Color.hpp> @@ -53,9 +54,24 @@ class CustomAttribToColorPass : public RenderPass /// Set the splat size for pointclouds inline float getSplatSize() { return m_splatsSize; } - // return the splatSize used for point clouds + /// return the splatSize used for point clouds void setSplatSize(float s); + /// set the env map to use + void setEnvMap( std::shared_ptr<EnvMap> envmp ); + + /// set the strength (aka "power") of the env map + void setEnvStrength( int s ) { + if ( m_envmap ) + { + m_envStrength = float( s ) / 100.f; + m_envmap->setEnvStrength( m_envStrength ); + } + } + + /// get the strength (aka "power") of the env map + int getEnvStrength() const { return int( m_envStrength * 100 ); } + private: /// The framebuffer used to render this pass std::unique_ptr<globjects::Framebuffer> m_fbo{nullptr}; @@ -74,12 +90,21 @@ class CustomAttribToColorPass : public RenderPass std::string m_customGeometryAttrib{"void propagateAttributes(){}\n"}; /// the custom FragmentColor shader function - /// If not changed, compute the same expression (without ao) than the light stage + /// If not changed, compute the same expression (without ao) than the envlight stage std::string m_customFragmentColor{ - "vec4 computeCustomColor(Material mat, vec3 light_dir, vec3 view_dir) {\n" - "vec3 bsdf= evaluateBSDF(material, getPerVertexTexCoord(), light_dir, view_dir);\n" - "vec3 contribution = lightContributionFrom(light, getWorldSpacePosition().xyz);\n" - "return vec4(bsdf * 3.141592 * contribution, 1.0);\n" + "\nvec4 computeCustomColor(Material mat, vec3 lightDir, vec3 viewDir, vec3 normal_world) { \n" + "vec3 diffColor; \n" + "vec3 specColor; \n" + "getSeparateBSDFComponent( mat, getPerVertexTexCoord(), lightDir, viewDir,\n" + "vec3(0, 0, 1), diffColor, specColor );\n" + "vec3 envd;\n" + "vec3 envs;\n" + "int e = getEnvMapColors(mat, normal_world, envd, envs);" + "vec3 finalColor;\n" + "if (e==1) { finalColor = diffColor*envd + specColor*envs; }\n" + "else { finalColor = (diffColor + specColor) * max(lightDir.z, 0) \n" + " * lightContributionFrom(light, getWorldSpacePosition().xyz); }\n" + "return vec4( finalColor, 1); \n" "}\n"}; /// State indicator @@ -90,5 +115,11 @@ class CustomAttribToColorPass : public RenderPass /// The splats size float m_splatsSize{0.025}; + + /// The Environment to used for envmap lighting + std::shared_ptr<EnvMap> m_envmap{nullptr}; + + /// The strength of the envmap + float m_envStrength; }; } // namespace RadiumNBR diff --git a/src/libRender/RadiumNBR/Renderer/FullFeatureRenderer.hpp b/src/libRender/RadiumNBR/Renderer/FullFeatureRenderer.hpp index e49e07392ef33b10d9c859a727856b99ad4c1e23..256181a80df83cfd6d20360b9accccd4714a07a9 100644 --- a/src/libRender/RadiumNBR/Renderer/FullFeatureRenderer.hpp +++ b/src/libRender/RadiumNBR/Renderer/FullFeatureRenderer.hpp @@ -37,13 +37,15 @@ class NodeBasedRenderer_LIBRARY_API FullFeatureRenderer final : public NodeBased void setEnvMap( const std::string& files ); void showEnvMap( bool state ); + void setEnvStrength( int s ); + // TODO : define a way to configure 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: diff --git a/src/libRender/RadiumNBR/Renderer/Visualization.cpp b/src/libRender/RadiumNBR/Renderer/Visualization.cpp index df101c6151b141bd2f3febae02df79ba77803391..d1cfb7696af05fec40ea10289eff731f2da2566f 100644 --- a/src/libRender/RadiumNBR/Renderer/Visualization.cpp +++ b/src/libRender/RadiumNBR/Renderer/Visualization.cpp @@ -118,4 +118,38 @@ void VisualizationController::setSplatSize( float s ) { m_customPass->setSplatSize( s ); }; + +void VisualizationController::setEnvMap( const std::string& files ) { + if ( files.empty() ) + { + m_clearPass->setEnvMap( nullptr ); + m_customPass->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_customPass->setEnvMap( e ); + m_hasEnvMap = true; + } +} + +void VisualizationController::showEnvMap( bool state ) { + m_clearPass->showEnvMap( state ); +} + +void VisualizationController::setEnvStrength( int s ) { + m_customPass->setEnvStrength( s ); +} } // namespace RadiumNBR diff --git a/src/libRender/RadiumNBR/Renderer/Visualization.hpp b/src/libRender/RadiumNBR/Renderer/Visualization.hpp index bf1973c0ed8604110d95fb4b565813069414aee5..5c482029de947f8e7bebf61a41f129b74ccf9b24 100644 --- a/src/libRender/RadiumNBR/Renderer/Visualization.hpp +++ b/src/libRender/RadiumNBR/Renderer/Visualization.hpp @@ -38,25 +38,41 @@ class NodeBasedRenderer_LIBRARY_API VisualizationController float getSplatSize(); void setSplatSize( float s ); + void setEnvMap( const std::string& files ); + void showEnvMap( bool state ); + void setEnvStrength( int s ); + private: /// The custom pass if needed for modification std::shared_ptr<RadiumNBR::CustomAttribToColorPass> m_customPass; /// The clear pass for the background std::shared_ptr<RadiumNBR::ClearPass> m_clearPass; - /// + /// TODO : this default are the same as in the CustomAttribToColorPass. Use them instead of redefining here std::string m_vertexFunction{"void outputCustomAttribs() {\n}\n"}; std::string m_geometryFunction{"void propagateAttributes(){}\n"}; std::string m_fragmentFunction{ - "vec4 computeCustomColor(Material mat, vec3 light_dir, vec3 view_dir) {\n" - "vec3 bsdf= evaluateBSDF(material, getPerVertexTexCoord(), light_dir, view_dir);\n" - "vec3 contribution = lightContributionFrom(light, getWorldSpacePosition().xyz);\n" - "return vec4(bsdf * 3.141592 * contribution, 1.0);\n" + "\nvec4 computeCustomColor(Material mat, vec3 lightDir, vec3 viewDir, vec3 normal_world) { \n" + "vec3 diffColor; \n" + "vec3 specColor; \n" + "getSeparateBSDFComponent( mat, getPerVertexTexCoord(), lightDir, viewDir,\n" + "vec3(0, 0, 1), diffColor, specColor );\n" + "vec3 envd;\n" + "vec3 envs;\n" + "int e = getEnvMapColors(mat, normal_world, envd, envs);" + "vec3 finalColor;\n" + "if (e==1) { finalColor = diffColor*envd + specColor*envs; }\n" + "else { finalColor = (diffColor + specColor) * max(lightDir.z, 0) \n" + " * lightContributionFrom(light, getWorldSpacePosition().xyz); }\n" + "return vec4( finalColor, 1); \n" "}\n"}; RadiumNBR::NodeBasedRenderer* m_renderer; bool m_postProcess{true}; + + /// Is an envmap attached to the renderer + bool m_hasEnvMap{false}; }; } // namespace RadiumNBR