From f1628c0cd5782a1ab2b6d14aabe156c7b9d11375 Mon Sep 17 00:00:00 2001 From: Emmanuel Benoit Date: Sat, 30 Sep 2017 17:58:48 +0200 Subject: [PATCH] Partial bloom (missing highpass filter) --- bloom-combine.glsl | 20 ++++++++ blur-pass.glsl | 26 ++++++++++ copy.glsl | 11 ++++- main.cc | 110 +++++++++++++++++++++++++++++++++++++++++-- map.glsl | 2 +- raymarch-header.glsl | 3 +- raymarcher.glsl | 3 ++ rendertarget.cc | 4 ++ rendertarget.hh | 3 ++ texture.cc | 71 +++++++++++++++++++++++++--- texture.hh | 24 ++++++++-- 11 files changed, 258 insertions(+), 19 deletions(-) create mode 100644 bloom-combine.glsl create mode 100644 blur-pass.glsl diff --git a/bloom-combine.glsl b/bloom-combine.glsl new file mode 100644 index 0000000..f1997c6 --- /dev/null +++ b/bloom-combine.glsl @@ -0,0 +1,20 @@ +#version 450 core + +layout( location = 0 ) uniform sampler2D u_MainInput; +layout( location = 1 ) uniform sampler2D u_BlurInput; +layout( location = 2 ) uniform vec2 u_OutputSize; + +layout( location = 0 ) out vec3 color; + +void main( void ) +{ + vec2 tmp = gl_FragCoord.xy / u_OutputSize; + float f = .8; + color = textureLod( u_MainInput , tmp , 0 ).rgb; + for ( int i = 0 ; i < 5 ; i ++ ) { + color += f * textureLod( u_BlurInput , tmp , i ).rgb; + f *= .90; + } + color = color / ( color + 1. ); + color = pow( color , vec3( 2.2 ) ); +} diff --git a/blur-pass.glsl b/blur-pass.glsl new file mode 100644 index 0000000..5d1ff0e --- /dev/null +++ b/blur-pass.glsl @@ -0,0 +1,26 @@ +#version 450 core + +layout( location = 0 ) uniform sampler2D u_InputTexture; +layout( location = 1 ) uniform vec2 u_OutputSize; +layout( location = 2 ) uniform vec2 u_InputSize; +layout( location = 3 ) uniform int u_SourceLOD; +layout( location = 4 ) uniform vec2 u_Direction; +layout( location = 5 ) uniform vec3 u_Weights; + +layout( location = 0 ) out vec3 color; + +void main( void ) +{ + vec2 tmp = gl_FragCoord.xy / u_OutputSize; + vec2 displace1 = vec2( 2.5 ) * u_Direction / u_InputSize; + vec2 displace2 = vec2( 5. ) * u_Direction / u_InputSize; + float wt = u_Weights.x + u_Weights.y * 2 + u_Weights.z * 2; + color = u_Weights.x * textureLod( u_InputTexture , tmp , u_SourceLOD ).xyz + + u_Weights.y * ( + textureLod( u_InputTexture , tmp + displace1 , u_SourceLOD ).xyz + + textureLod( u_InputTexture , tmp - displace1 , u_SourceLOD ).xyz ) + + u_Weights.z * ( + textureLod( u_InputTexture , tmp + displace2 , u_SourceLOD ).xyz + + textureLod( u_InputTexture , tmp - displace2 , u_SourceLOD ).xyz ); + color /= wt; +} diff --git a/copy.glsl b/copy.glsl index dcd0402..4b65478 100644 --- a/copy.glsl +++ b/copy.glsl @@ -1,13 +1,20 @@ #version 450 core layout( location = 0 ) uniform sampler2D u_InputTexture; +layout( location = 1 ) uniform int u_LOD; layout( location = 0 ) out vec4 color; void main( void ) { +#if 1 + vec2 ts = textureSize( u_InputTexture , u_LOD ); vec2 tmp = gl_FragCoord.xy / vec2( 1280. , 720. ); - color = textureLod( u_InputTexture , tmp , 0 ); - //color.xy *= .75 + tmp * .25; + ivec2 pos = ivec2( ts * tmp ); + color = texelFetch( u_InputTexture , pos , u_LOD ); +#else + vec2 tmp = gl_FragCoord.xy / vec2( 1280. , 720. ); + color = textureLod( u_InputTexture , tmp , float( u_LOD ) ); +#endif } diff --git a/main.cc b/main.cc index 961c2a2..b516c30 100644 --- a/main.cc +++ b/main.cc @@ -30,10 +30,15 @@ struct T_Main T_FilesWatcher watcher; std::unique_ptr< T_ShaderProgram > spRaymarch; std::unique_ptr< T_ShaderProgram > spCopy; + std::unique_ptr< T_ShaderProgram > spBlur; + std::unique_ptr< T_ShaderProgram > spBloomCombine; std::unique_ptr< T_Texture > txRaymarchOutput; std::unique_ptr< T_Rendertarget > rtRaymarchOutput; + std::unique_ptr< T_Texture > txBlur0 , txBlur1; + std::vector< std::unique_ptr< T_Rendertarget > > rtBlur0 , rtBlur1; + void startIteration( ); void handleCapture( ); void makeUI( ); @@ -65,10 +70,22 @@ T_Main::T_Main( ) ImGui_ImplSdl_Init( window ); initProgram( ); + txRaymarchOutput = std::make_unique< T_Texture >( - 1280 , 720 , E_TexType::RGBA8 ); + 1280 , 720 , E_TexType::RGB16F ); rtRaymarchOutput = std::make_unique < T_Rendertarget >( T_RendertargetSetup( ).add( *txRaymarchOutput ).create( ) ); + + txBlur0 = std::make_unique< T_Texture >( 1280 , 720 , E_TexType::RGB16F , 5 ); + txBlur0->wrap( E_TexWrap::CLAMP_EDGE ).samplingMode( E_TexSampling::LINEAR ); + txBlur1 = std::make_unique< T_Texture >( 1280 , 720 , E_TexType::RGB16F , 5 ); + txBlur1->wrap( E_TexWrap::CLAMP_EDGE ).samplingMode( E_TexSampling::LINEAR ); + for ( int i = 0 ; i < 5 ; i ++ ) { + rtBlur0.push_back( std::make_unique< T_Rendertarget >( + T_RendertargetSetup( ).add( *txBlur0 , i ).create( ) ) ); + rtBlur1.push_back( std::make_unique< T_Rendertarget >( + T_RendertargetSetup( ).add( *txBlur1 , i ).create( ) ) ); + } } void T_Main::mainLoop( ) @@ -165,6 +182,8 @@ void T_Main::makeUI( ) void T_Main::render( ) { + auto const& dspSize( ImGui::GetIO( ).DisplaySize ); + if ( spRaymarch->activate( ) && rtRaymarchOutput->activate( ) ) { glClearColor( 0 , 1 , 1 , 1 ); glClear( GL_COLOR_BUFFER_BIT ); @@ -179,7 +198,6 @@ void T_Main::render( ) U_RENDER = 7 , }; - auto const& dspSize( ImGui::GetIO( ).DisplaySize ); glUniform1f( U_TIME , 0 ); glUniform2f( U_RESOLUTION , dspSize.x , dspSize.y ); @@ -194,16 +212,91 @@ void T_Main::render( ) glRectf( -1, -1 , 1 , 1 ); } + if ( spBlur->activate( ) ) { + enum { + U_TEXTURE = 0 , + U_OUTPUT_SIZE = 1 , + U_INPUT_SIZE = 2 , + U_SOURCE_LOD = 3 , + U_DIRECTION = 4 , + U_WEIGHTS = 5 , + }; + glUniform3f( U_WEIGHTS , 0.5 , 0.25 , 0.125 ); + for ( int i = 0 ; i < 5 ; i ++ ) { + // IB RMO B0 B1 B0 B1 B0 + // OB B0/0 B1/0 B0/1 B1/1 B0/2 B1/2 + // SLOD: 0 0 0 1 1 2 + // IW: W W W W/2 W/2 W/4 + // OW: W W W/2 W/2 W/4 W/4 + T_TextureBinding tb( 0 ); + uint32_t w , h; + if ( i == 0 ) { + tb.set( U_TEXTURE , *txRaymarchOutput ); + w = txRaymarchOutput->width( ); + h = txRaymarchOutput->height( ); + } else { + tb.set( U_TEXTURE , *txBlur1 ); + w = txBlur1->width( ) >> ( i - 1 ); + h = txBlur1->height( ) >> ( i - 1 ); + } + + const uint32_t slod = i > 0 ? ( i - 1 ) : 0; + rtBlur0[ i ]->activate( ); +#ifdef INTRUSIVE_TRACES + printf( "BLUR %d/H IT %p SLOD %d IS %dx%d OS %dx%d\n" , + i , &(*( i == 0 ? txRaymarchOutput : txBlur1 ) ) , + slod , w , h , rtBlur0[ i ]->width( ) , rtBlur0[ i ]->height( ) ); +#endif + glUniform2f( U_OUTPUT_SIZE , rtBlur0[ i ]->width( ) , rtBlur0[ i ]->height( ) ); + glUniform1i( U_SOURCE_LOD , slod ); + glUniform2f( U_INPUT_SIZE , w , h ); + + glUniform2f( U_DIRECTION , 1 , 0 ); + tb.bind( ); + glRectf( -1 , -1 , 1 , 1 ); + + rtBlur1[ i ]->activate( ); + tb.set( U_TEXTURE , *txBlur0 ); + tb.bind( ); + glUniform2f( U_DIRECTION , 0 , 1 ); + glUniform1i( U_SOURCE_LOD , i ); + glUniform2f( U_INPUT_SIZE , + rtBlur0[ i ]->width( ) , + rtBlur0[ i ]->height( ) ); + glRectf( -1 , -1 , 1 , 1 ); +#ifdef INTRUSIVE_TRACES + printf( "BLUR %d/V IT %p SLOD %d IS %dx%d OS %dx%d\n" , + i , &(*( txBlur0 ) ) , + i , rtBlur0[ i ]->width( ) , rtBlur0[ i ]->height( ) , + rtBlur0[ i ]->width( ) , rtBlur0[ i ]->height( ) ); +#endif + } + } + T_Rendertarget::MainOutput( ); glClearColor( 1 , 0 , 1 , 1 ); glClear( GL_COLOR_BUFFER_BIT ); +#if 0 if ( spCopy->activate( ) ) { T_TextureBinding tb( 0 ); - tb.set( 0 , *txRaymarchOutput ); + tb.set( 0 , *txBlur1 ); tb.bind( ); + glUniform1i( 1 , 3 ); glRectf( -1, -1 , 1 , 1 ); glBindTexture( GL_TEXTURE_2D , 0 ); } +#else + if ( spBloomCombine->activate( ) ) { + T_TextureBinding main( 0 ) , blur( 1 ); + main.set( 0 , *txRaymarchOutput ); + main.bind( ); + blur.set( 1 , *txBlur1 ); + blur.bind( ); + glUniform2f( 2 , dspSize.x , dspSize.y ); + glRectf( -1, -1 , 1 , 1 ); + glBindTexture( GL_TEXTURE_2D , 0 ); + } +#endif glUseProgram( 0 ); ImGui::Render( ); @@ -220,10 +313,17 @@ void T_Main::initProgram( ) spRaymarch->addFile( "raymarcher.glsl" ); spRaymarch->load( ); - spCopy = std::make_unique< T_ShaderProgram >( GL_FRAGMENT_SHADER , - watcher ); + spCopy = std::make_unique< T_ShaderProgram >( GL_FRAGMENT_SHADER , watcher ); spCopy->addFile( "copy.glsl" ); spCopy->load( ); + + spBlur = std::make_unique< T_ShaderProgram >( GL_FRAGMENT_SHADER , watcher ); + spBlur->addFile( "blur-pass.glsl" ); + spBlur->load( ); + + spBloomCombine = std::make_unique< T_ShaderProgram >( GL_FRAGMENT_SHADER , watcher ); + spBloomCombine->addFile( "bloom-combine.glsl" ); + spBloomCombine->load( ); } diff --git a/map.glsl b/map.glsl index 3aec80b..3681bbe 100644 --- a/map.glsl +++ b/map.glsl @@ -2,5 +2,5 @@ vec2 map( vec3 pos ) { vec3 q = pos; q.xy = mod( q.xy + 2. , 4. ) - 2.; - return vec2( length( q ) - 2.1 , 0. ); + return vec2( length( q ) - 1.8 , step( 0. , 1.9 - length( pos.xy ) ) ); } diff --git a/raymarch-header.glsl b/raymarch-header.glsl index 107b97c..2821952 100644 --- a/raymarch-header.glsl +++ b/raymarch-header.glsl @@ -12,7 +12,8 @@ layout( location = 7 ) uniform vec4 u_Render; vec3 camPos , lookAt , camUp; float nearPlane; -out vec4 color; +layout( location = 0 ) out vec4 color; + void setCamFromUniforms( ) { camPos = u_CamPos; lookAt = u_LookAt; diff --git a/raymarcher.glsl b/raymarcher.glsl index 9ef9cad..afc7e7a 100644 --- a/raymarcher.glsl +++ b/raymarcher.glsl @@ -70,6 +70,9 @@ void main( ) float si = pow( clamp( ndoth , 0 , 1 ) , 4 ) , di = .6 + .3 * clamp( ndotl , 0 , 1 ); bc = mix( bc * di , vec3( 1. ) , si ); + if ( r.y >= 1. ) { + bc += vec3( 5. , .1 , 4. ) * 4; + } } else { bc = vec3( 0. ); } diff --git a/rendertarget.cc b/rendertarget.cc index 5d944cb..49c1863 100644 --- a/rendertarget.cc +++ b/rendertarget.cc @@ -55,6 +55,10 @@ T_Rendertarget T_RendertargetSetup::create( ) glGenFramebuffers( 1 , &id ); glBindFramebuffer( GL_FRAMEBUFFER , id ); for ( auto i = 0u ; i < nca ; i ++ ) { + printf( "init fb %p att %d tx %p level %d\n" , + this , i , + colorAttachments_[ i ].texture , + colorAttachments_[ i ].level ); glFramebufferTexture( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 + i , colorAttachments_[ i ].texture->id( ) , diff --git a/rendertarget.hh b/rendertarget.hh index e83ca2f..32b5bd7 100644 --- a/rendertarget.hh +++ b/rendertarget.hh @@ -60,6 +60,9 @@ struct T_Rendertarget bool activate( ); + uint32_t width( ) const { return width_; } + uint32_t height( ) const { return height_; } + static void MainOutput( ); private: diff --git a/texture.cc b/texture.cc index 3047615..1ea5fde 100644 --- a/texture.cc +++ b/texture.cc @@ -7,7 +7,7 @@ T_Texture::T_Texture( __rd__ const uint32_t height , __rd__ const E_TexType type , __rd__ const uint32_t levels ) - : width_( width ) , height_( height ) + : levels_( levels ) , width_( width ) , height_( height ) { assert( levels > 0 ); @@ -28,6 +28,18 @@ T_Texture::T_Texture( dt = GL_FLOAT; break; + case E_TexType::RGB8: + ifmt = GL_RGB8; + fmt = GL_RGB; + dt = GL_UNSIGNED_BYTE; + break; + + case E_TexType::RGB16F: + ifmt = GL_RGB16F; + fmt = GL_RGB; + dt = GL_FLOAT; + break; + case E_TexType::R8: ifmt = GL_R8; fmt = GL_RED; @@ -41,11 +53,16 @@ T_Texture::T_Texture( break; } - glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MIN_LOD , 0 ); - glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MAX_LOD , levels - 1 ); + glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_BASE_LEVEL , 0 ); + glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MAX_LEVEL , levels - 1 ); + glTexParameterf( GL_TEXTURE_2D , GL_TEXTURE_MIN_LOD , 0 ); + glTexParameterf( GL_TEXTURE_2D , GL_TEXTURE_MAX_LOD , levels - 1 ); + glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ); + glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ); uint32_t w = width , h = height; for ( auto i = 0u ; i < levels ; i ++ ) { + printf( "init tx %p l %d w %d h %d\n" , this , i , w , h ); glTexImage2D( GL_TEXTURE_2D , i , ifmt , w , h , 0 , fmt , dt , nullptr ); w >>= 1; h >>= 1; @@ -53,8 +70,6 @@ T_Texture::T_Texture( } assert( glGetError( ) == GL_NO_ERROR ); - - glBindTexture( GL_TEXTURE_2D , 0 ); } T_Texture::~T_Texture( ) @@ -63,6 +78,48 @@ T_Texture::~T_Texture( ) } +T_Texture& T_Texture::samplingMode( + __rd__ const E_TexSampling mode ) +{ + glBindTexture( GL_TEXTURE_2D , id_ ); + + GLenum min , max; + switch ( mode ) { + case E_TexSampling::NEAREST: + min = levels_ > 1 ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST; + max = GL_NEAREST; + break; + case E_TexSampling::LINEAR: + min = levels_ > 1 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR; + max = GL_LINEAR; + break; + + } + glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , min ); + glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , max ); + return *this; +} + +T_Texture& T_Texture::wrap( + __rd__ const E_TexWrap mode ) +{ + GLenum gm; + switch ( mode ) { + case E_TexWrap::REPEAT: + gm = GL_REPEAT; + break; + case E_TexWrap::CLAMP_EDGE: + gm = GL_CLAMP_TO_EDGE; + break; + case E_TexWrap::CLAMP_BORDER: + gm = GL_CLAMP_TO_BORDER; + break; + } + glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , gm ); + glTexParameteri( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , gm ); + return *this; +} + /*============================================================================*/ @@ -87,8 +144,8 @@ void T_TextureBinding::set( void T_TextureBinding::bind( ) const { - glActiveTexture( GL_TEXTURE0 + binding_ ); - glBindTexture( GL_TEXTURE_2D , texture_ ? texture_->id( ) : 0 ); + glBindTextureUnit( binding_ , + texture_ ? texture_->id( ) : 0 ); glUniform1i( uniform_ , binding_ ); assert( glGetError( ) == GL_NO_ERROR ); } diff --git a/texture.hh b/texture.hh index 3fcf4a3..03c4e0f 100644 --- a/texture.hh +++ b/texture.hh @@ -4,14 +4,26 @@ #endif -enum class E_TexType -{ +enum class E_TexType { RGBA8 , RGBA16F , + RGB8 , + RGB16F , R8 , R16F , }; +enum class E_TexSampling { + NEAREST , + LINEAR , +}; + +enum class E_TexWrap { + REPEAT , + CLAMP_EDGE , + CLAMP_BORDER +}; + struct T_Texture { T_Texture( ) = delete; @@ -25,13 +37,19 @@ struct T_Texture __rd__ const uint32_t levels = 1 ); ~T_Texture( ); + T_Texture& samplingMode( + __rd__ const E_TexSampling mode ); + T_Texture& wrap( + __rd__ const E_TexWrap mode ); + GLuint id( ) const noexcept { return id_; } + uint32_t levels( ) const noexcept { return levels_; } uint32_t width( ) const noexcept { return width_; } uint32_t height( ) const noexcept { return height_; } private: GLuint id_; - uint32_t width_ , height_; + uint32_t levels_ , width_ , height_; }; struct T_TextureBinding