diff --git a/CMakeLists.txt b/CMakeLists.txt index ce8262e6c5a5549476cad778045aafdc1e984590..266b12686ba6692a87025029d893fb051a95acc1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ cmake_minimum_required( VERSION 3.1 FATAL_ERROR ) # visimpl project and version -project( visimpl VERSION 1.8.2 ) +project( visimpl VERSION 1.8.3 ) set( visimpl_VERSION_ABI 6 ) SET( VISIMPL_LICENSE "GPL") diff --git a/visimpl/DomainManager.cpp b/visimpl/DomainManager.cpp index 27ae227d9ca998413d6f30d03aa52b7ec368e185..f3be64bddd82bd25f2a6c28fdd732d8cd7b8bdab 100644 --- a/visimpl/DomainManager.cpp +++ b/visimpl/DomainManager.cpp @@ -24,6 +24,8 @@ namespace visimpl , _currentRenderer( nullptr ) , _defaultRenderer( nullptr ) , _solidRenderer( nullptr ) + , _solidMode( false ) + , _accumulativeMode( false ) , _decay( 0.0f ) { } @@ -62,15 +64,48 @@ namespace visimpl visimpl::PARTICLE_SOLID_FRAGMENT_SHADER ); _solidProgram.compileAndLink( ); - _defaultRenderer = std::make_shared< plab::CoverageRenderer >( + _defaultAccProgram.loadFromText( + visimpl::PARTICLE_VERTEX_SHADER , + visimpl::PARTICLE_ACC_DEFAULT_FRAGMENT_SHADER ); + _defaultAccProgram.compileAndLink( ); + + _solidAccProgram.loadFromText( + visimpl::PARTICLE_VERTEX_SHADER , + visimpl::PARTICLE_ACC_SOLID_FRAGMENT_SHADER ); + _solidAccProgram.compileAndLink( ); + + _defaultRenderer = std::make_shared< plab::SimpleRenderer >( _defaultProgram.program( )); - _solidRenderer = std::make_shared< plab::CoverageRenderer >( + _solidRenderer = std::make_shared< plab::SimpleRenderer >( _solidProgram.program( )); - _currentRenderer = _defaultRenderer; + _defaultAccRenderer = std::make_shared< plab::SimpleRenderer >( + _defaultAccProgram.program( )); + _solidAccRenderer = std::make_shared< plab::SimpleRenderer >( + _solidAccProgram.program( )); _selectionCluster->setModel( _selectionModel ); - _selectionCluster->setRenderer( _currentRenderer ); + + refreshRenderer( ); + } + + void DomainManager::refreshRenderer( ) + { + if ( _accumulativeMode ) + { + _currentRenderer = _solidMode ? _solidAccRenderer : _defaultAccRenderer; + } + else + { + _currentRenderer = _solidMode ? _solidRenderer : _defaultRenderer; + } + + if ( _selectionCluster != nullptr ) + _selectionCluster->setRenderer( _currentRenderer ); + for ( const auto& item: _groupClusters ) + item.second->setRenderer( _currentRenderer ); + for ( const auto& item: _attributeClusters ) + item.second->setRenderer( _currentRenderer ); } #ifdef SIMIL_USE_BRION @@ -291,8 +326,7 @@ namespace visimpl _currentRenderer , _selectionModel->isClippingEnabled( )); - group->getModel( )->setAccumulativeMode( - _selectionModel->isAccumulativeMode( )); + group->getModel( )->setAccumulativeMode( _accumulativeMode ); std::vector< uint32_t > ids; std::vector< NeuronParticle > particles; @@ -326,8 +360,7 @@ namespace visimpl _currentRenderer , _selectionModel->isClippingEnabled( )); - group->getModel( )->setAccumulativeMode( - _selectionModel->isAccumulativeMode( )); + group->getModel( )->setAccumulativeMode( _accumulativeMode ); std::vector< NeuronParticle > particles; for ( const auto& gid: _selectionGids ) @@ -345,7 +378,7 @@ namespace visimpl void DomainManager::removeGroup( const std::string& name ) { - if(1 != _groupClusters.erase( name )) + if ( 1 != _groupClusters.erase( name )) { std::cerr << "DomainManager: Error removing group '" << name << "' - " << __FILE__ << ":" << __LINE__ << std::endl; @@ -373,8 +406,7 @@ namespace visimpl _selectionModel->getRightPlane( ) , _currentRenderer , _selectionModel->isClippingEnabled( )); - group->getModel( )->setAccumulativeMode( - _selectionModel->isAccumulativeMode( )); + group->getModel( )->setAccumulativeMode( _accumulativeMode ); const auto currentIndex = i % colors.size( ); const auto color = colors[ currentIndex ].toRgb( ); @@ -402,14 +434,21 @@ namespace visimpl } + bool DomainManager::isAccumulativeModeEnabled( ) + { + return _accumulativeMode; + } + void DomainManager::enableAccumulativeMode( bool enabled ) { + _accumulativeMode = enabled; if ( _selectionModel != nullptr ) { _selectionModel->setAccumulativeMode( enabled ); } for ( const auto& item: _groupClusters ) item.second->getModel( )->setAccumulativeMode( enabled ); + refreshRenderer( ); } void DomainManager::enableClipping( bool enabled ) @@ -456,22 +495,14 @@ namespace visimpl void DomainManager::applyDefaultShader( ) { - _currentRenderer = _defaultRenderer; - _selectionCluster->setRenderer( _currentRenderer ); - for ( const auto& item: _groupClusters ) - item.second->setRenderer( _currentRenderer ); - for ( const auto& item: _attributeClusters ) - item.second->setRenderer( _currentRenderer ); + _solidMode = false; + refreshRenderer( ); } void DomainManager::applySolidShader( ) { - _currentRenderer = _solidRenderer; - _selectionCluster->setRenderer( _currentRenderer ); - for ( const auto& item: _groupClusters ) - item.second->setRenderer( _currentRenderer ); - for ( const auto& item: _attributeClusters ) - item.second->setRenderer( _currentRenderer ); + _solidMode = true; + refreshRenderer( ); } void DomainManager::processInput( @@ -551,7 +582,7 @@ namespace visimpl { particle->timestamp = -std::numeric_limits< float >::infinity( ); } - auto gid = item.second->getGids().at( i ); + auto gid = item.second->getGids( ).at( i ); auto value = input.find( gid ); if ( value != input.cend( )) { @@ -580,7 +611,7 @@ namespace visimpl { particle->timestamp = -std::numeric_limits< float >::infinity( ); } - auto gid = item.second->getGids().at( i ); + auto gid = item.second->getGids( ).at( i ); auto value = input.find( gid ); if ( value != input.cend( )) { diff --git a/visimpl/DomainManager.h b/visimpl/DomainManager.h index 2a8dc65d60d3809949a5c49b0facb282eba2ee01..bd051039b08254dabddb55dfd4fc478a508c0ac4 100644 --- a/visimpl/DomainManager.h +++ b/visimpl/DomainManager.h @@ -47,10 +47,16 @@ namespace visimpl // Renders reto::ShaderProgram _defaultProgram; reto::ShaderProgram _solidProgram; + reto::ShaderProgram _defaultAccProgram; + reto::ShaderProgram _solidAccProgram; - std::shared_ptr< plab::CoverageRenderer > _currentRenderer; - std::shared_ptr< plab::CoverageRenderer > _defaultRenderer; - std::shared_ptr< plab::CoverageRenderer > _solidRenderer; + std::shared_ptr< plab::SimpleRenderer > _currentRenderer; + std::shared_ptr< plab::SimpleRenderer > _defaultRenderer; + std::shared_ptr< plab::SimpleRenderer > _solidRenderer; + std::shared_ptr< plab::SimpleRenderer > _defaultAccRenderer; + std::shared_ptr< plab::SimpleRenderer > _solidAccRenderer; + + bool _solidMode , _accumulativeMode; // Others tBoundingBox _boundingBox; @@ -65,6 +71,8 @@ namespace visimpl const std::shared_ptr< reto::ClippingPlane >& rightPlane , const std::shared_ptr< plab::ICamera >& camera ); + void refreshRenderer( ); + #ifdef SIMIL_USE_BRION void initAttributeData( const TGIDSet& gids , @@ -97,7 +105,7 @@ namespace visimpl void setTime( float time ); - void addTime( float time, float endTime ); + void addTime( float time , float endTime ); const tBoundingBox& getBoundingBox( ) const; @@ -125,6 +133,8 @@ namespace visimpl void applySolidShader( ); + bool isAccumulativeModeEnabled( ); + void enableAccumulativeMode( bool enabled ); void enableClipping( bool enabled ); diff --git a/visimpl/OpenGLWidget.cpp b/visimpl/OpenGLWidget.cpp index 9367a6b173971b960135a82d7714fa60970a8eea..078d3f4dc3b0a045bd18878e847a6f6b9fc75776 100644 --- a/visimpl/OpenGLWidget.cpp +++ b/visimpl/OpenGLWidget.cpp @@ -61,8 +61,6 @@ constexpr float ZOOM_FACTOR = 1.3f; constexpr float TRANSLATION_FACTOR = 0.001f; constexpr float ROTATION_FACTOR = 0.01f; -constexpr int FRAMEBUFFER_SCALE_FACTOR = 2; -constexpr int SAMPLES = 4; constexpr float DEFAULT_DELTA_TIME = 0.5f; const QString INITIAL_CAMERA_POSITION = "0,0,0;1;1,0,0,0,1,0,0,0,1"; @@ -81,44 +79,18 @@ namespace visimpl constexpr float invRGBInt = 1.0f / 255; - const static std::string vertexShaderCode = R"(#version 330 core -layout (location = 0) in vec2 aPos; -layout (location = 1) in vec2 aTexCoords; - -out vec2 TexCoords; - -void main() -{ - gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0); - TexCoords = aTexCoords; -} -)"; - - const static std::string screenFragment = R"(#version 330 core -out vec4 FragColor; - -in vec2 TexCoords; - -uniform sampler2D screenTexture; - -void main() -{ - FragColor = vec4(texture(screenTexture, TexCoords).rgb, 1); -} -)"; - - OpenGLWidget::OpenGLWidget( QWidget* parent_ , Qt::WindowFlags windowsFlags_ , const std::string& #ifdef VISIMPL_USE_ZEROEQ - zeqUri + zeqUri #endif ) : QOpenGLWidget( parent_ , windowsFlags_ ) #ifdef VISIMPL_USE_ZEROEQ , _zeqUri( zeqUri ) #endif + , _gl( ) , _fpsLabel( nullptr ) , _labelCurrentTime( nullptr ) , _showFps( false ) @@ -189,12 +161,10 @@ void main() , _deltaEvents( 0.125f ) , _domainManager( ) , _screenPlaneShader( nullptr ) - , _msaaFrameBuffer( 0 ) - , _msaaTextureColor( 0 ) - , _msaaRBODepth( 0 ) - , _midFrameBuffer( 0 ) - , _midTextureColor( 0 ) - , _midRBODepth( 0 ) + , _quadVAO( 0 ) + , _weightFrameBuffer( 0 ) + , _accumulationTexture( 0 ) + , _revealTexture( 0 ) { _lastCameraPosition = glm::vec3( 0 , 0 , 0 ); @@ -277,7 +247,7 @@ void main() } } #else - _camera = std::make_shared< Camera >( ); + _camera = std::make_shared< Camera >( ); #endif Q_ASSERT( _camera ); @@ -292,7 +262,7 @@ void main() void OpenGLWidget::initializeGL( void ) { - initializeOpenGLFunctions( ); + _gl.initializeOpenGLFunctions( ); auto* logger = new QOpenGLDebugLogger( this ); logger->initialize( ); @@ -316,8 +286,6 @@ void main() glPolygonMode( GL_FRONT_AND_BACK , GL_FILL ); glEnable( GL_CULL_FACE ); - glLineWidth( 1.5 ); - _then = std::chrono::system_clock::now( ); _lastFrame = std::chrono::system_clock::now( ); @@ -331,13 +299,14 @@ void main() const GLubyte* shadingVer = glGetString( GL_SHADING_LANGUAGE_VERSION ); _screenPlaneShader = new reto::ShaderProgram( ); - _screenPlaneShader->loadVertexShaderFromText( vertexShaderCode ); - _screenPlaneShader->loadFragmentShaderFromText( screenFragment ); + _screenPlaneShader->loadVertexShaderFromText( SHADER_SCREEN_VERTEX ); + _screenPlaneShader->loadFragmentShaderFromText( SHADER_SCREEN_FRAGMENT ); _screenPlaneShader->create( ); _screenPlaneShader->link( ); _screenPlaneShader->autocatching( true ); _screenPlaneShader->use( ); - _screenPlaneShader->sendUniformi( "screenTexture" , 0 ); + _screenPlaneShader->sendUniformi( "accumulation" , 0 ); + _screenPlaneShader->sendUniformi( "reveal" , 1 ); std::cout << "OpenGL Hardware: " << vendor << " (" << renderer << ")" @@ -348,84 +317,66 @@ void main() void OpenGLWidget::_initRenderToTexture( void ) { - _screenPlaneShader = new reto::ShaderProgram( ); - _screenPlaneShader->loadVertexShaderFromText( vertexShaderCode ); - _screenPlaneShader->loadFragmentShaderFromText( screenFragment ); - _screenPlaneShader->create( ); - _screenPlaneShader->link( ); - _screenPlaneShader->autocatching( true ); - _screenPlaneShader->use( ); - _screenPlaneShader->sendUniformi( "screenTexture" , 0 ); - - // Generate the MSAA framebuffer - glGenFramebuffers( 1 , &_msaaFrameBuffer ); - glBindFramebuffer( GL_FRAMEBUFFER , _msaaFrameBuffer ); + // Generate the OIR framebuffer - glGenTextures( 1 , &_msaaTextureColor ); - glBindTexture( GL_TEXTURE_2D_MULTISAMPLE , _msaaTextureColor ); - - glTexImage2DMultisample( - GL_TEXTURE_2D_MULTISAMPLE , SAMPLES , GL_RGB , - width( ) * FRAMEBUFFER_SCALE_FACTOR , - height( ) * FRAMEBUFFER_SCALE_FACTOR , - GL_TRUE - ); + _gl.glGenFramebuffers( 1 , &_weightFrameBuffer ); + _gl.glBindFramebuffer( GL_FRAMEBUFFER , _weightFrameBuffer ); - glBindTexture( GL_TEXTURE_2D_MULTISAMPLE , 0 ); - - glFramebufferTexture2D( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , - GL_TEXTURE_2D_MULTISAMPLE , _msaaTextureColor , 0 ); + glGenTextures( 1 , &_accumulationTexture ); + glBindTexture( GL_TEXTURE_2D , _accumulationTexture ); + glTexImage2D( GL_TEXTURE_2D , 0 , GL_RGBA32F , width( ) , height( ) , 0 , + GL_RGBA , GL_FLOAT , nullptr ); + glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ); + glGenTextures( 1 , &_revealTexture ); + glBindTexture( GL_TEXTURE_2D , _revealTexture ); + glTexImage2D( GL_TEXTURE_2D , 0 , GL_R8 , width( ) , height( ) , 0 , + GL_RED , GL_FLOAT , nullptr ); + glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ); - glGenRenderbuffers( 1 , &_msaaRBODepth ); - glBindRenderbuffer( GL_RENDERBUFFER , _msaaRBODepth ); - glRenderbufferStorageMultisample( - GL_RENDERBUFFER , SAMPLES , GL_DEPTH_COMPONENT32 , - width( ) * FRAMEBUFFER_SCALE_FACTOR , - height( ) * FRAMEBUFFER_SCALE_FACTOR ); - glBindRenderbuffer( GL_RENDERBUFFER , 0 ); + _gl.glFramebufferTexture2D( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , + GL_TEXTURE_2D , _accumulationTexture , 0 ); + _gl.glFramebufferTexture2D( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT1 , + GL_TEXTURE_2D , _revealTexture , 0 ); - glFramebufferRenderbuffer( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , - GL_RENDERBUFFER , _msaaRBODepth ); + const GLenum transparentDrawBuffers[] = { GL_COLOR_ATTACHMENT0 , + GL_COLOR_ATTACHMENT1 }; + _gl.glDrawBuffers( 2 , transparentDrawBuffers ); - if ( glCheckFramebufferStatus( GL_FRAMEBUFFER ) != GL_FRAMEBUFFER_COMPLETE ) + if ( _gl.glCheckFramebufferStatus( GL_FRAMEBUFFER ) != + GL_FRAMEBUFFER_COMPLETE ) std::cerr << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl; - // Generate the mid framebuffer. + _gl.glBindFramebuffer( GL_FRAMEBUFFER , defaultFramebufferObject( )); - glGenFramebuffers( 1 , &_midFrameBuffer ); - glBindFramebuffer( GL_FRAMEBUFFER , _midFrameBuffer ); + float quadVertices[] = { + // positions + -1.0f , -1.0f , 0.0f , + 1.0f , -1.0f , 0.0f , + 1.0f , 1.0f , 0.0f , - glGenTextures( 1 , &_midTextureColor ); - glBindTexture( GL_TEXTURE_2D , _midTextureColor ); - glTexImage2D( GL_TEXTURE_2D , 0 , GL_RGB , - width( ) * FRAMEBUFFER_SCALE_FACTOR , - height( ) * FRAMEBUFFER_SCALE_FACTOR , - 0 , - GL_RGB , GL_UNSIGNED_BYTE , nullptr ); - glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ); - glBindTexture( GL_TEXTURE_2D , 0 ); - glFramebufferTexture2D( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , - GL_TEXTURE_2D , _midTextureColor , 0 ); - - glGenRenderbuffers( 1 , &_midRBODepth ); - glBindRenderbuffer( GL_RENDERBUFFER , _midRBODepth ); - glRenderbufferStorage( GL_RENDERBUFFER , GL_DEPTH_COMPONENT32 , - width( ) * FRAMEBUFFER_SCALE_FACTOR , - height( ) * FRAMEBUFFER_SCALE_FACTOR ); - glBindRenderbuffer( GL_RENDERBUFFER , 0 ); - - glFramebufferRenderbuffer( GL_FRAMEBUFFER , GL_DEPTH_ATTACHMENT , - GL_RENDERBUFFER , _midRBODepth ); - - if ( glCheckFramebufferStatus( GL_FRAMEBUFFER ) != GL_FRAMEBUFFER_COMPLETE ) - std::cerr << "ERROR::FRAMEBUFFER:: Mid Framebuffer is not complete!" - << std::endl; + 1.0f , 1.0f , 0.0f , + -1.0f , 1.0f , 0.0f , + -1.0f , -1.0f , 0.0f + }; - glBindFramebuffer( GL_FRAMEBUFFER , defaultFramebufferObject( )); + // quad VAO + unsigned int quadVBO; + _gl.glGenVertexArrays( 1 , &_quadVAO ); + _gl.glGenBuffers( 1 , &quadVBO ); + _gl.glBindVertexArray( _quadVAO ); + _gl.glBindBuffer( GL_ARRAY_BUFFER , quadVBO ); + _gl.glBufferData( GL_ARRAY_BUFFER , sizeof( quadVertices ) , quadVertices , + GL_STATIC_DRAW ); + _gl.glEnableVertexAttribArray( 0 ); + _gl.glVertexAttribPointer( 0 , 3 , GL_FLOAT , GL_FALSE , + 3 * sizeof( float ) , + ( void* ) 0 ); + _gl.glBindVertexArray( 0 ); } void OpenGLWidget::_configureSimulationFrame( void ) @@ -738,39 +689,60 @@ void main() } // if player && player->isPlaying - - glBindFramebuffer( GL_FRAMEBUFFER , _msaaFrameBuffer ); - glViewport( 0 , 0 , width( ) * FRAMEBUFFER_SCALE_FACTOR , - height( ) * FRAMEBUFFER_SCALE_FACTOR ); - glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); - glEnable( GL_DEPTH_TEST ); - - _paintPlanes( ); - _paintParticles( ); - glViewport( 0 , 0 , width( ) , height( )); - // Perform MSAA - glBindFramebuffer( GL_READ_FRAMEBUFFER , _msaaFrameBuffer ); - glBindFramebuffer( GL_DRAW_FRAMEBUFFER , _midFrameBuffer ); - int w = width( ) * FRAMEBUFFER_SCALE_FACTOR; - int h = height( ) * FRAMEBUFFER_SCALE_FACTOR; - glBlitFramebuffer( - 0 , 0 , - w , h , - 0 , 0 , - w , h , - GL_COLOR_BUFFER_BIT , GL_NEAREST ); - - // Perform super-sampling - glBindFramebuffer( GL_READ_FRAMEBUFFER , _midFrameBuffer ); - glBindFramebuffer( GL_DRAW_FRAMEBUFFER , defaultFramebufferObject( )); - glBlitFramebuffer( - 0 , 0 , - w , h , - 0 , 0 , - width( ) , height( ) , - GL_COLOR_BUFFER_BIT , GL_LINEAR ); + if ( _domainManager.isAccumulativeModeEnabled( )) + { + _gl.glBindFramebuffer( GL_FRAMEBUFFER , defaultFramebufferObject( )); + _gl.glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + _gl.glDisable( GL_DEPTH_TEST ); + _gl.glDepthMask( GL_FALSE ); + _gl.glEnable( GL_BLEND ); + _gl.glBlendFunc( GL_SRC_ALPHA , GL_ONE_MINUS_CONSTANT_ALPHA ); + _gl.glBlendEquation( GL_FUNC_ADD ); + _paintPlanes( ); + _paintParticles( ); + } + else + { + _gl.glBindFramebuffer( GL_FRAMEBUFFER , _weightFrameBuffer ); + _gl.glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + _gl.glEnable( GL_DEPTH_TEST ); + + + _gl.glDepthMask( GL_FALSE ); + _gl.glEnable( GL_BLEND ); + _gl.glBlendFunci( 0 , GL_ONE , GL_ONE ); + _gl.glBlendFunci( 1 , GL_ZERO , GL_ONE_MINUS_SRC_COLOR ); + _gl.glBlendEquation( GL_FUNC_ADD ); + + glm::vec4 zeroFillerVec( 0.0f ); + glm::vec4 oneFillerVec( 1.0f ); + _gl.glClearBufferfv( GL_COLOR , 0 , &zeroFillerVec[ 0 ] ); + _gl.glClearBufferfv( GL_COLOR , 1 , &oneFillerVec[ 0 ] ); + + _paintPlanes( ); + _paintParticles( ); + + // Perform blend + + _gl.glDepthFunc( GL_ALWAYS ); + _gl.glEnable( GL_BLEND ); + _gl.glBlendFunc( GL_SRC_ALPHA , GL_ONE_MINUS_SRC_ALPHA ); + + _gl.glBindFramebuffer( GL_FRAMEBUFFER , defaultFramebufferObject( )); + _gl.glClear( + GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); + + _screenPlaneShader->use( ); + _gl.glActiveTexture( GL_TEXTURE0 ); + _gl.glBindTexture( GL_TEXTURE_2D , _accumulationTexture ); + _gl.glActiveTexture( GL_TEXTURE1 ); + _gl.glBindTexture( GL_TEXTURE_2D , _revealTexture ); + _gl.glBindVertexArray( _quadVAO ); + _gl.glDrawArrays( GL_TRIANGLES , 0 , 6 ); + } + } if ( _player && _elapsedTimeSliderAcc > _sliderUpdatePeriodMicroseconds ) @@ -1055,7 +1027,7 @@ void main() { if ( _player && ( _player->isPlaying( ) || _firstFrame )) { - _domainManager.addTime( renderDelta, _player->endTime() ); + _domainManager.addTime( renderDelta , _player->endTime( )); _firstFrame = false; } } @@ -1111,35 +1083,21 @@ void main() // _pickRenderer->setWindowSize( w , h ); //} - if ( _msaaTextureColor != 0 ) + if ( _accumulationTexture != 0 ) { - int rw = width( ) * FRAMEBUFFER_SCALE_FACTOR; - int rh = height( ) * FRAMEBUFFER_SCALE_FACTOR; // Resize MSAA buffers - glBindTexture( GL_TEXTURE_2D_MULTISAMPLE , _msaaTextureColor ); - glTexImage2DMultisample( - GL_TEXTURE_2D_MULTISAMPLE , SAMPLES , GL_RGB , - rw , rh , GL_TRUE ); - - glBindRenderbuffer( GL_RENDERBUFFER , _msaaRBODepth ); - glRenderbufferStorageMultisample( - GL_RENDERBUFFER , SAMPLES , GL_DEPTH_COMPONENT32 , - rw , rh ); - - // And mid-buffers too! - - glBindTexture( GL_TEXTURE_2D , _midTextureColor ); - glTexImage2D( GL_TEXTURE_2D , 0 , GL_RGB , - rw , rh , 0 , - GL_RGB , GL_UNSIGNED_BYTE , nullptr ); - - glBindRenderbuffer( GL_RENDERBUFFER , _midRBODepth ); - glRenderbufferStorage( GL_RENDERBUFFER , GL_DEPTH_COMPONENT32 , - rw , rh ); - - glBindTexture( GL_TEXTURE_2D_MULTISAMPLE , 0 ); - glBindTexture( GL_TEXTURE_2D , 0 ); - glBindRenderbuffer( GL_RENDERBUFFER , 0 ); + _gl.glBindTexture( GL_TEXTURE_2D , _accumulationTexture ); + _gl.glTexImage2D( GL_TEXTURE_2D , 0 , GL_RGBA32F , width( ) , height( ) , + 0 , + GL_RGBA , GL_FLOAT , nullptr ); + + _gl.glBindTexture( GL_TEXTURE_2D , _revealTexture ); + _gl.glTexImage2D( GL_TEXTURE_2D , 0 , GL_R8 , width( ) , height( ) , 0 , + GL_RED , GL_FLOAT , nullptr ); + + _gl.glBindTexture( GL_TEXTURE_2D_MULTISAMPLE , 0 ); + _gl.glBindTexture( GL_TEXTURE_2D , 0 ); + //_gl.glBindRenderbuffer( GL_RENDERBUFFER , defaultFramebufferObject( )); } } diff --git a/visimpl/OpenGLWidget.h b/visimpl/OpenGLWidget.h index 421376b872441e0021f464e87bd988258abdb1d5..252d7136cdeeb8c542f2f39c966b0cc287257c17 100644 --- a/visimpl/OpenGLWidget.h +++ b/visimpl/OpenGLWidget.h @@ -50,6 +50,7 @@ #include <plab/plab.h> #include <sstream> +#include <QOpenGLFunctions_4_0_Core> #include "types.h" #include "render/Plane.h" @@ -157,8 +158,7 @@ namespace visimpl AB_REPEAT } TPlaybackMode; - class OpenGLWidget - : public QOpenGLWidget , public QOpenGLFunctions_3_3_Core + class OpenGLWidget : public QOpenGLWidget { Q_OBJECT; @@ -443,6 +443,8 @@ namespace visimpl #endif + QOpenGLFunctions_4_0_Core _gl; + QLabel* _fpsLabel; QLabel* _labelCurrentTime; bool _showFps; @@ -481,8 +483,8 @@ namespace visimpl reto::ShaderProgram* _shaderClippingPlanes; simil::SpikesPlayer* _player; - std::shared_ptr<reto::ClippingPlane> _clippingPlaneLeft; - std::shared_ptr<reto::ClippingPlane> _clippingPlaneRight; + std::shared_ptr< reto::ClippingPlane > _clippingPlaneLeft; + std::shared_ptr< reto::ClippingPlane > _clippingPlaneRight; evec3 _planesCenter; evec3 _planeNormalLeft; evec3 _planeNormalRight; @@ -570,13 +572,10 @@ namespace visimpl // Render to texture reto::ShaderProgram* _screenPlaneShader; - unsigned int _msaaFrameBuffer; - unsigned int _msaaTextureColor; - unsigned int _msaaRBODepth; - - unsigned int _midFrameBuffer; - unsigned int _midTextureColor; - unsigned int _midRBODepth; + unsigned int _quadVAO; + unsigned int _weightFrameBuffer; + unsigned int _accumulationTexture; + unsigned int _revealTexture; }; } // namespace visimpl diff --git a/visimpl/particlelab/ParticleLabShaders.h b/visimpl/particlelab/ParticleLabShaders.h index 896cc5756279e73a34d07a88e69b0fdc8eba4abe..0eb42eea18ddd9c92fae6b95d04fac10b4007533 100644 --- a/visimpl/particlelab/ParticleLabShaders.h +++ b/visimpl/particlelab/ParticleLabShaders.h @@ -28,7 +28,7 @@ namespace visimpl { -const static std::string PARTICLE_VERTEX_SHADER = R"(#version 400 + const static std::string PARTICLE_VERTEX_SHADER = R"(#version 330 //#extension GL_ARB_separate_shader_objects: enable uniform mat4 viewProjectionMatrix; @@ -117,26 +117,56 @@ void main() )"; -const static std::string PARTICLE_DEFAULT_FRAGMENT_SHADER = R"( -#version 400 -in vec4 color; + const static std::string PARTICLE_DEFAULT_FRAGMENT_SHADER = R"(#version 330 +in vec4 color; in vec2 uvCoord; -out vec4 outputColor; + +layout (location = 0) out vec4 accumulation; +layout (location = 1) out float reveal; + void main() { - vec2 p = -1.0 + 2.0 * uvCoord; - float l = sqrt(dot(p,p)); - l = 1.0 - clamp(l, 0.0, 1.0); - l *= color.a; - outputColor = vec4(color.rgb, l); + vec2 p = -1.0 + 2.0 * uvCoord; + float l = sqrt(dot(p, p)); + l = 1.0 - clamp(l, 0.0, 1.0); + l *= color.a; + + vec4 c = vec4(color.rgb, l); + + float weight = clamp(pow(min(1.0, c.a * 10.0) + 0.01, 3.0) * 1e8 + * pow(1.0 - gl_FragCoord.z * 0.9, 3.0), 1e-2, 3e3); + + accumulation = vec4 (c.rgb * c.a, c.a) * weight; + reveal = c.a; } )"; -const static std::string PARTICLE_SOLID_FRAGMENT_SHADER = R"(#version 400 + const static std::string PARTICLE_ACC_DEFAULT_FRAGMENT_SHADER = R"(#version 330 in vec4 color; in vec2 uvCoord; -out vec4 outputColor; + +out vec4 fragColor; + +void main() +{ + vec2 p = -1.0 + 2.0 * uvCoord; + float l = sqrt(dot(p, p)); + l = 1.0 - clamp(l, 0.0, 1.0); + l *= color.a; + + fragColor = vec4(color.rgb, l); +} + +)"; + + const static std::string PARTICLE_SOLID_FRAGMENT_SHADER = R"(#version 330 +in vec4 color; +in vec2 uvCoord; + +layout (location = 0) out vec4 accumulation; +layout (location = 1) out float reveal; + void main() { vec2 p = -1.0 + 2.0 * uvCoord; @@ -146,10 +176,37 @@ void main() if( l > 0.8 ) discard; - outputColor = vec4(color.rgb, 1.0f); + vec4 c = vec4(color.rgb, 1.0f); + + float weight = clamp(pow(min(1.0, c.a * 10.0) + 0.01, 3.0) * 1e8 + * pow(1.0 - gl_FragCoord.z * 0.9, 3.0), 1e-2, 3e3); + + accumulation = vec4 (c.rgb * c.a, c.a) * weight; + reveal = c.a; })"; -const static std::string PICK_VERTEX_SHADER = R"(#version 400 + const static std::string PARTICLE_ACC_SOLID_FRAGMENT_SHADER = R"(#version 330 +in vec4 color; +in vec2 uvCoord; + +out vec4 fragColor; + +void main() +{ + vec2 p = -1.0 + 2.0 * uvCoord; + float l = sqrt(dot(p,p)); + l = clamp(l, 0.0, 1.0); + + if( l > 0.8 ) + discard; + + fragColor = vec4(color.rgb, 1.0f); +} + +)"; + + + const static std::string PICK_VERTEX_SHADER = R"(#version 330 #extension GL_ARB_separate_shader_objects: enable uniform mat4 modelViewProjM; @@ -189,7 +246,7 @@ void main() id = gl_InstanceID; })"; -const static std::string PICK_FRAGMENT_SHADER = R"(#version 400 + const static std::string PICK_FRAGMENT_SHADER = R"(#version 330 uniform float radiusThreshold; @@ -222,8 +279,7 @@ void main( ) outputColor = vec4(cc, 1.0); })"; -const static std::string SHADER_PLANE_VERTEX = R"( -#version 400 + const static std::string SHADER_PLANE_VERTEX = R"(#version 330 in vec3 inPos; @@ -243,8 +299,7 @@ void main( ) )"; -const static std::string SHADER_PLANE_FRAGMENT = R"( -#version 400 + const static std::string SHADER_PLANE_FRAGMENT = R"(#version 330 in vec4 outColor; out vec4 outputColor; @@ -256,6 +311,71 @@ void main( ) } +)"; + + + const static std::string SHADER_SCREEN_VERTEX = R"(#version 330 + +// shader inputs +layout (location = 0) in vec3 position; + +void main() +{ + gl_Position = vec4(position, 1.0f); +} +)"; + + const static std::string SHADER_SCREEN_FRAGMENT = R"(#version 330 + +// shader outputs +layout (location = 0) out vec4 frag; + +// color accumulation buffer +uniform sampler2D accumulation; + +// revealage threshold buffer +uniform sampler2D reveal; + +// epsilon number +const float EPSILON = 0.00001f; + +// caluclate floating point numbers equality accurately +bool isApproximatelyEqual(float a, float b) +{ + return abs(a - b) <= (abs(a) < abs(b) ? abs(b) : abs(a)) * EPSILON; +} + +// get the max value between three values +float max3(vec3 v) +{ + return max(max(v.x, v.y), v.z); +} + +void main() +{ + // fragment coordination + ivec2 coords = ivec2(gl_FragCoord.xy); + + // fragment revealage + float revealage = texelFetch(reveal, coords, 0).r; + + // save the blending and color texture fetch cost if there is not a transparent fragment + if (isApproximatelyEqual(revealage, 1.0f)) + discard; + + // fragment color + vec4 accumulation = texelFetch(accumulation, coords, 0); + + // suppress overflow + if (isinf(max3(abs(accumulation.rgb)))) + accumulation.rgb = vec3(accumulation.a); + + // prevent floating point precision bug + vec3 average_color = accumulation.rgb / max(accumulation.a, EPSILON); + + // blend pixels + frag = vec4(average_color, 1.0f - revealage); +} )"; }