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

Make wireframe animation compatible.

parent c3022675
Branches
No related tags found
No related merge requests found
...@@ -13,10 +13,8 @@ using namespace Ra::Core::Utils; // log ...@@ -13,10 +13,8 @@ using namespace Ra::Core::Utils; // log
#include <globjects/Framebuffer.h> #include <globjects/Framebuffer.h>
#ifdef ADVANCED_WIREFRAME #include <Engine/Data/Mesh.hpp>
# include <Engine/Data/Mesh.hpp> #include <Engine/Data/ViewingParameters.hpp>
# include <Engine/Data/ViewingParameters.hpp>
#endif
namespace RadiumNBR { namespace RadiumNBR {
using namespace gl; using namespace gl;
...@@ -47,96 +45,102 @@ void WireframePass::setOutput( const SharedTextures& colorBuffer ) { ...@@ -47,96 +45,102 @@ void WireframePass::setOutput( const SharedTextures& colorBuffer ) {
} }
bool WireframePass::update() { bool WireframePass::update() {
#ifdef ADVANCED_WIREFRAME // keep the wireframe cache coherent with the scene
// build the wireframe representation of all drawn objects if ( m_wireframes.size() > m_objectsToRender->size() ) { m_wireframes.clear(); };
m_wireframes.clear(); return true;
for ( const auto& ro : *m_objectsToRender ) }
template <typename IndexContainerType>
void computeIndices( Ra::Core::Geometry::LineMesh::IndexContainerType& indices,
IndexContainerType& other ) {
for ( const auto& index : other )
{ {
std::shared_ptr<Ra::Engine::Data::LineMesh> disp; auto s = index.size();
for ( unsigned int i = 0; i < s; ++i )
using trimesh = Ra::Engine::Data::IndexedGeometry<Ra::Core::Geometry::TriangleMesh>;
using polymesh = Ra::Engine::Data::IndexedGeometry<Ra::Core::Geometry::PolyMesh>;
auto displayable = ro->getMesh();
auto tm = std::dynamic_pointer_cast<trimesh>( displayable );
auto tp = std::dynamic_pointer_cast<polymesh>( displayable );
bool drawable;
Ra::Core::Geometry::LineMesh lines;
Ra::Core::Geometry::LineMesh::IndexContainerType indices;
if ( tm )
{ {
drawable = tm->getRenderMode() == int i1 = index[i];
Ra::Engine::Data::AttribArrayDisplayable::MeshRenderMode::RM_TRIANGLES; int i2 = index[( i + 1 ) % s];
if ( drawable ) if ( i1 > i2 ) std::swap( i1, i2 );
{ indices.emplace_back( i1, i2 );
lines.setVertices( tm->getCoreGeometry().vertices() );
for ( const auto& index : tm->getCoreGeometry().getIndices() )
{
for ( unsigned int i = 0; i < 3; ++i )
{
int i1 = index[i];
int i2 = index[( i + 1 ) % 3];
if ( i1 > i2 ) std::swap( i1, i2 );
indices.emplace_back( i1, i2 );
}
}
}
} }
if ( tp ) }
{
drawable = tp->getRenderMode() ==
Ra::Engine::Data::AttribArrayDisplayable::MeshRenderMode::RM_TRIANGLES;
if ( drawable ) std::sort( indices.begin(),
{ indices.end(),
drawable = tp->getRenderMode() == []( const Ra::Core::Geometry::LineMesh::IndexType& a,
Ra::Engine::Data::AttribArrayDisplayable::MeshRenderMode::RM_TRIANGLES; const Ra::Core::Geometry::LineMesh::IndexType& b ) {
lines.setVertices( tp->getCoreGeometry().vertices() ); return a[0] < b[0] || ( a[0] == b[0] && a[1] < b[1] );
for ( const auto& index : tp->getCoreGeometry().getIndices() ) } );
{ indices.erase( std::unique( indices.begin(), indices.end() ), indices.end() );
auto s = index.size(); }
for ( unsigned int i = 0; i < s; ++i )
{ // store LineMesh and Core, define the observer functor to update data one core update for wireframe
int i1 = index[i]; // linemesh
int i2 = index[( i + 1 ) % s]; template <typename CoreGeometry>
if ( i1 > i2 ) std::swap( i1, i2 ); class VerticesUpdater
indices.emplace_back( i1, i2 ); {
} public:
} VerticesUpdater( std::shared_ptr<Ra::Engine::Data::LineMesh> disp, CoreGeometry& core ) :
} m_disp{disp}, m_core{core} {};
}
if ( drawable ) void operator()() { m_disp->getCoreGeometry().setVertices( m_core.vertices() ); }
{ std::shared_ptr<Ra::Engine::Data::LineMesh> m_disp;
std::sort( indices.begin(), CoreGeometry& m_core;
indices.end(), };
[]( const Ra::Core::Geometry::LineMesh::IndexType& a,
const Ra::Core::Geometry::LineMesh::IndexType& b ) { template <typename CoreGeometry>
return a[0] < b[0] || ( a[0] == b[0] && a[1] < b[1] ); class IndicesUpdater
} ); {
indices.erase( std::unique( indices.begin(), indices.end() ), indices.end() ); public:
IndicesUpdater( std::shared_ptr<Ra::Engine::Data::LineMesh> disp, CoreGeometry& core ) :
lines.setIndices( std::move( indices ) ); m_disp{disp}, m_core{core} {};
disp = std::make_shared<Ra::Engine::Data::LineMesh>( std::string( "wireframe" ), void operator()() {
std::move( lines ) ); auto lineIndices = m_disp->getCoreGeometry().getIndicesWithLock();
disp->updateGL(); computeIndices( lineIndices, m_core.getIndices() );
m_wireframes[ro.get()] = disp; m_disp->getCoreGeometry().indicesUnlock();
}
else
{
disp.reset();
m_wireframes[ro.get()] = {nullptr};
}
} }
#endif std::shared_ptr<Ra::Engine::Data::LineMesh> m_disp;
return true; CoreGeometry& m_core;
};
// create a linemesh to draw wireframe given a core mesh
template <typename CoreGeometry>
void setupLineMesh( std::shared_ptr<Ra::Engine::Data::LineMesh>& disp, CoreGeometry& core ) {
Ra::Core::Geometry::LineMesh lines;
Ra::Core::Geometry::LineMesh::IndexContainerType indices;
lines.setVertices( core.vertices() );
computeIndices( indices, core.getIndices() );
if ( indices.size() > 0 )
{
lines.setIndices( std::move( indices ) );
disp = std::make_shared<Ra::Engine::Data::LineMesh>( std::string( "wireframe" ),
std::move( lines ) );
disp->updateGL();
// add observer
auto handle = core.template getAttribHandle<typename CoreGeometry::Point>(
Ra::Engine::Data::Mesh::getAttribName( Ra::Engine::Data::Mesh::VERTEX_POSITION ) );
core.vertexAttribs().getAttrib( handle ).attach( VerticesUpdater( disp, core ) );
core.attach( IndicesUpdater( disp, core ) );
}
else
{ disp.reset(); }
}
template <typename CoreGeometry>
void processLineMesh( const std::shared_ptr<CoreGeometry>& m,
std::shared_ptr<Ra::Engine::Data::LineMesh>& r ) {
if ( m->getRenderMode() ==
Ra::Engine::Data::AttribArrayDisplayable::MeshRenderMode::RM_TRIANGLES )
{ setupLineMesh( r, m->getCoreGeometry() ); }
} }
void WireframePass::resize( size_t width, size_t height ) { void WireframePass::resize( size_t width, size_t height ) {
#ifdef ADVANCED_WIREFRAME
m_width = width; m_width = width;
m_height = height; m_height = height;
#endif
// Only resize the owned textures. Imported one are resized by their owner // Only resize the owned textures. Imported one are resized by their owner
for ( auto& t : m_localTextures ) for ( auto& t : m_localTextures )
{ {
...@@ -161,66 +165,61 @@ void WireframePass::resize( size_t width, size_t height ) { ...@@ -161,66 +165,61 @@ void WireframePass::resize( size_t width, size_t height ) {
} }
void WireframePass::execute( const Ra::Engine::Data::ViewingParameters& viewParams ) const { void WireframePass::execute( const Ra::Engine::Data::ViewingParameters& viewParams ) const {
m_fbo->bind(); m_fbo->bind();
// only draw into 1 buffers (Color) // only draw into 1 buffers (Color)
GL_ASSERT( glDrawBuffers( 1, buffers ) ); glDrawBuffers( 1, buffers );
GL_ASSERT( glDepthMask( GL_FALSE ) ); glDepthMask( GL_FALSE );
GL_ASSERT( glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ) ); glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
glEnable( GL_DEPTH_TEST );
GL_ASSERT( glEnable( GL_DEPTH_TEST ) ); glDepthFunc( GL_LESS );
GL_ASSERT( glDepthFunc( GL_LESS ) ); glEnable( GL_BLEND );
GL_ASSERT( glEnable( GL_BLEND ) );
#ifdef ADVANCED_WIREFRAME_SHADER
glBlendEquationSeparate( GL_FUNC_ADD, GL_FUNC_ADD ); glBlendEquationSeparate( GL_FUNC_ADD, GL_FUNC_ADD );
glBlendFuncSeparate( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO ); glBlendFuncSeparate( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO );
// To prevent z-fighting, remove polygon offset // To prevent z-fighting, remove polygon offset
glDisable( GL_POLYGON_OFFSET_FILL ); glDisable( GL_POLYGON_OFFSET_FILL );
#else
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
glEnable( GL_LINE_SMOOTH );
glLineWidth( 1.f );
glDisable( GL_POLYGON_OFFSET_LINE );
#endif
for ( const auto& ro : *m_objectsToRender ) for ( const auto& ro : *m_objectsToRender )
{ {
if ( ro->isVisible() ) if ( ro->isVisible() )
{ {
#ifdef ADVANCED_WIREFRAME std::shared_ptr<Ra::Engine::Data::Displayable> wro;
auto it = m_wireframes.find( ro.get() ); auto it = m_wireframes.find( ro.get() );
if ( it != m_wireframes.end() ) if ( it == m_wireframes.end() )
{ {
auto wro = it->second; using trimesh = Ra::Engine::Data::IndexedGeometry<Ra::Core::Geometry::TriangleMesh>;
auto shader = m_shaderMngr->getShaderProgram( "WireframePass::WireframeProgram" ); using polymesh = Ra::Engine::Data::IndexedGeometry<Ra::Core::Geometry::PolyMesh>;
if ( wro && shader ) std::shared_ptr<Ra::Engine::Data::LineMesh> disp;
{ auto displayable = ro->getMesh();
shader->bind(); auto tm = std::dynamic_pointer_cast<trimesh>( displayable );
Ra::Core::Matrix4 modelMatrix = ro->getTransformAsMatrix(); auto tp = std::dynamic_pointer_cast<polymesh>( displayable );
shader->setUniform( "transform.proj", viewParams.projMatrix ); if ( tm ) { processLineMesh( tm, disp ); }
shader->setUniform( "transform.view", viewParams.viewMatrix ); if ( tp ) { processLineMesh( tp, disp ); }
shader->setUniform( "transform.model", modelMatrix ); m_wireframes[ro.get()] = disp;
shader->setUniform( "viewport", Ra::Core::Vector2{m_width, m_height} ); wro = disp;
wro->render( shader );
GL_CHECK_ERROR;
}
} }
else
{ wro = it->second; }
#else auto shader = m_shaderMngr->getShaderProgram( "WireframePass::WireframeProgram" );
ro->render( m_passParams, viewParams, passIndex() ); if ( wro && shader )
#endif {
wro->updateGL();
shader->bind();
Ra::Core::Matrix4 modelMatrix = ro->getTransformAsMatrix();
shader->setUniform( "transform.proj", viewParams.projMatrix );
shader->setUniform( "transform.view", viewParams.viewMatrix );
shader->setUniform( "transform.model", modelMatrix );
shader->setUniform( "viewport", Ra::Core::Vector2{m_width, m_height} );
wro->render( shader );
GL_CHECK_ERROR;
}
} }
} }
#ifdef ADVANCED_WIREFRAME_SHADER
// need to maintain global state invariant // need to maintain global state invariant
glEnable( GL_POLYGON_OFFSET_FILL ); glEnable( GL_POLYGON_OFFSET_FILL );
#else glDisable( GL_BLEND );
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
// do we need to enable this ? it is not part of the invariant ...
// glEnable( GL_POLYGON_OFFSET_LINE );
#endif
GL_ASSERT( glDisable( GL_BLEND ) );
} }
bool WireframePass::buildRenderTechnique( const Ra::Engine::Rendering::RenderObject* ro, bool WireframePass::buildRenderTechnique( const Ra::Engine::Rendering::RenderObject* ro,
...@@ -235,7 +234,7 @@ bool WireframePass::buildRenderTechnique( const Ra::Engine::Rendering::RenderObj ...@@ -235,7 +234,7 @@ bool WireframePass::buildRenderTechnique( const Ra::Engine::Rendering::RenderObj
{ rt.setConfiguration( *cfg, passIndex() ); } { rt.setConfiguration( *cfg, passIndex() ); }
else else
{ {
#ifdef ADVANCED_WIREFRAME_SHADER
Ra::Engine::Data::ShaderConfiguration theConfig{ Ra::Engine::Data::ShaderConfiguration theConfig{
{"WireframePass::WireframeProgram"}, {"WireframePass::WireframeProgram"},
resourcesRootDir + "Shaders/WireframePass/Advanced/wireframe.vert.glsl", resourcesRootDir + "Shaders/WireframePass/Advanced/wireframe.vert.glsl",
...@@ -243,13 +242,6 @@ bool WireframePass::buildRenderTechnique( const Ra::Engine::Rendering::RenderObj ...@@ -243,13 +242,6 @@ bool WireframePass::buildRenderTechnique( const Ra::Engine::Rendering::RenderObj
theConfig.addShader( Ra::Engine::Data::ShaderType_GEOMETRY, theConfig.addShader( Ra::Engine::Data::ShaderType_GEOMETRY,
resourcesRootDir + resourcesRootDir +
"Shaders/WireframePass/Advanced/wireframe.geom.glsl" ); "Shaders/WireframePass/Advanced/wireframe.geom.glsl" );
#else
// Build the shader configuration
Ra::Engine::Data::ShaderConfiguration theConfig{
{"WireframePass::WireframeProgram"},
resourcesRootDir + "Shaders/WireframePass/Basic/wireframepass.vert.glsl",
resourcesRootDir + "Shaders/WireframePass/Basic/wireframepass.frag.glsl"};
#endif
// Add to the ShaderConfigManager // Add to the ShaderConfigManager
Ra::Engine::Data::ShaderConfigurationFactory::addConfiguration( theConfig ); Ra::Engine::Data::ShaderConfigurationFactory::addConfiguration( theConfig );
// Add to the RenderTechnique // Add to the RenderTechnique
......
...@@ -2,13 +2,7 @@ ...@@ -2,13 +2,7 @@
#include <RadiumNBR/RenderPass.hpp> #include <RadiumNBR/RenderPass.hpp>
#include <Core/Utils/Color.hpp> #include <Core/Utils/Color.hpp>
#include <Engine/Data/DisplayableObject.hpp>
// This is the default. The two way of rendering wireframe is kept for illustration only
#define ADVANCED_WIREFRAME
#define ADVANCED_WIREFRAME_SHADER
#ifdef ADVANCED_WIREFRAME
# include <Engine/Data/DisplayableObject.hpp>
#endif
namespace Ra::Engine::Data { namespace Ra::Engine::Data {
class ShaderProgram; class ShaderProgram;
...@@ -52,15 +46,13 @@ class WireframePass : public RenderPass ...@@ -52,15 +46,13 @@ class WireframePass : public RenderPass
/// The color texture for output.Stored here for easy access. /// The color texture for output.Stored here for easy access.
SharedTextures m_outputTexture; SharedTextures m_outputTexture;
#ifdef ADVANCED_WIREFRAME
using WireMap = std::map<Ra::Engine::Rendering::RenderObject*, using WireMap = std::map<Ra::Engine::Rendering::RenderObject*,
std::shared_ptr<Ra::Engine::Data::Displayable>>; std::shared_ptr<Ra::Engine::Data::Displayable>>;
WireMap m_wireframes; mutable WireMap m_wireframes;
bool m_wireframeAa{true}; bool m_wireframeAa{true};
Ra::Core::Utils::Color m_wireframeColor{Ra::Core::Utils::Color::White()}; Ra::Core::Utils::Color m_wireframeColor{Ra::Core::Utils::Color::White()};
uint m_width{0}; uint m_width{0};
uint m_height{0}; uint m_height{0};
#endif
}; };
} // namespace RadiumNBR } // namespace RadiumNBR
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment