Radium Engine  1.5.20
Loading...
Searching...
No Matches
ForwardRenderer.cpp
1#include <Engine/Data/ShaderConfigFactory.hpp>
2#include <Engine/Data/ShaderConfiguration.hpp>
3#include <Engine/Rendering/ForwardRenderer.hpp>
4
5#include <Core/Containers/MakeShared.hpp>
6#include <Core/Containers/VariableSetEnumManagement.hpp>
7#include <Core/Geometry/TopologicalMesh.hpp>
8#include <Core/Utils/Color.hpp>
9#include <Core/Utils/Log.hpp>
10
11#include <Engine/Data/LambertianMaterial.hpp>
12#include <Engine/Data/Material.hpp>
13#include <Engine/Data/RenderParameters.hpp>
14#include <Engine/Data/ShaderProgramManager.hpp>
15#include <Engine/Data/Texture.hpp>
16#include <Engine/Data/ViewingParameters.hpp>
17#include <Engine/OpenGL.hpp>
18#include <Engine/Rendering/DebugRender.hpp>
19#include <Engine/Rendering/RenderObject.hpp>
20#include <Engine/Scene/DefaultLightManager.hpp>
21#include <Engine/Scene/Light.hpp>
22#include <globjects/Framebuffer.h>
23
24/* Test Point cloud parameter provider */
25#include <Core/RaCore.hpp>
26#include <Engine/Data/ShaderProgram.hpp>
27#include <Engine/Scene/GeometryComponent.hpp>
28
30
31#include <map>
32
33#include <globjects/Texture.h>
34
35namespace Ra {
36using namespace Core;
37using namespace Core::Utils; // log
38
39namespace Engine {
40namespace Rendering {
41namespace {
42const GLenum buffers[] = { GL_COLOR_ATTACHMENT0,
43 GL_COLOR_ATTACHMENT1,
44 GL_COLOR_ATTACHMENT2,
45 GL_COLOR_ATTACHMENT3,
46 GL_COLOR_ATTACHMENT4,
47 GL_COLOR_ATTACHMENT5,
48 GL_COLOR_ATTACHMENT6,
49 GL_COLOR_ATTACHMENT7 };
50}
51
52ForwardRenderer::ForwardRenderer() : Renderer() {}
53
54ForwardRenderer::~ForwardRenderer() = default;
55
56void ForwardRenderer::initializeInternal() {
57 initShaders();
58 initBuffers();
59
60 auto lightManager = new Scene::DefaultLightManager();
61 Ra::Engine::RadiumEngine::getInstance()->registerSystem( "DefaultLightManager", lightManager );
62 m_lightmanagers.push_back( lightManager );
63
64 if ( !DebugRender::getInstance() ) {
65 DebugRender::createInstance();
66 DebugRender::getInstance()->initialize();
67 }
68}
69
70void ForwardRenderer::initShaders() {
72 auto resourcesRootDir { RadiumEngine::getInstance()->getResourcesDir() };
73 m_shaderProgramManager->addShaderProgram(
74 { { "Hdr2Ldr" },
75 resourcesRootDir + "Shaders/2DShaders/Basic2D.vert.glsl",
76 resourcesRootDir + "Shaders/2DShaders/Hdr2Ldr.frag.glsl" } );
77 m_shaderProgramManager->addShaderProgram(
78 { { "ComposeOIT" },
79 resourcesRootDir + "Shaders/2DShaders/Basic2D.vert.glsl",
80 resourcesRootDir + "Shaders/2DShaders/ComposeOIT.frag.glsl" } );
81
82 Data::ShaderConfiguration wireframe { { "Wireframe" },
83 resourcesRootDir + "Shaders/Lines/Wireframe.vert.glsl",
84 resourcesRootDir + "Shaders/Lines/Wireframe.frag.glsl" };
85 wireframe.addShader( Data::ShaderType::ShaderType_GEOMETRY,
86 resourcesRootDir + "Shaders/Lines/Wireframe.geom.glsl" );
87 Data::ShaderConfigurationFactory::addConfiguration( wireframe );
88 m_shaderProgramManager->addShaderProgram( wireframe );
89}
90
91void ForwardRenderer::initBuffers() {
92 m_fbo = std::make_unique<globjects::Framebuffer>();
93 m_oitFbo = std::make_unique<globjects::Framebuffer>();
94 m_postprocessFbo = std::make_unique<globjects::Framebuffer>();
95 m_uiXrayFbo = std::make_unique<globjects::Framebuffer>();
96 m_volumeFbo = std::make_unique<globjects::Framebuffer>();
97 // Forward renderer internal textures texture
98
99 Data::TextureParameters texparams;
100 texparams.image.width = m_width;
101 texparams.image.height = m_height;
102 texparams.image.target = GL_TEXTURE_2D;
103
104 // Depth texture
105 texparams.sampler.minFilter = GL_NEAREST;
106 texparams.sampler.magFilter = GL_NEAREST;
107 texparams.image.internalFormat = GL_DEPTH_COMPONENT24;
108 texparams.image.format = GL_DEPTH_COMPONENT;
109 texparams.image.type = GL_UNSIGNED_INT;
110 texparams.name = m_textureNames[0];
111 m_textures[RendererTextures_Depth] = std::make_unique<Data::Texture>( texparams );
112
113 m_secondaryTextures[m_textureNames[RendererTextures_Depth]] =
114 m_textures[RendererTextures_Depth].get();
115
116 // Color texture
117 texparams.image.internalFormat = GL_RGBA32F;
118 texparams.image.format = GL_RGBA;
119 texparams.image.type = GL_SCALAR;
120 texparams.sampler.minFilter = GL_LINEAR;
121 texparams.sampler.magFilter = GL_LINEAR;
122
123 // init textures other than depth (which is the first in the array, index 0)
124 for ( int i = RendererTextures_Depth + 1; i < RendererTexture_Count; ++i ) {
125 texparams.name = m_textureNames[i];
126 m_textures[i] = std::make_unique<Data::Texture>( texparams );
127 m_secondaryTextures[m_textureNames[i]] = m_textures[i].get();
128 }
129}
130
131void ForwardRenderer::updateStepInternal( const Data::ViewingParameters& renderData ) {
132 CORE_UNUSED( renderData );
133 // TODO : Improve the way RO are distributed in fancy (opaque), transparent and volume
134 // to simplify rendering loop and code maintenance
135 // i.e. Volume should considered as transparent but stored in the volumetric list and
136 // transparent-but-not-volume object should be kept in the fancy list, ...
137 m_transparentRenderObjects.clear();
138 m_volumetricRenderObjects.clear();
139 for ( auto it = m_fancyRenderObjects.begin(); it != m_fancyRenderObjects.end(); ) {
140 if ( ( *it )->isTransparent() ) {
141 m_transparentRenderObjects.push_back( *it );
142 it = m_fancyRenderObjects.erase( it );
143 }
144 else {
145 auto material = ( *it )->getMaterial();
146 if ( material &&
147 material->getMaterialAspect() == Data::Material::MaterialAspect::MAT_DENSITY ) {
148 m_volumetricRenderObjects.push_back( *it );
149 it = m_fancyRenderObjects.erase( it );
150 }
151 else { ++it; }
152 }
153 }
154 m_fancyTransparentCount = m_transparentRenderObjects.size();
155 m_fancyVolumetricCount = m_volumetricRenderObjects.size();
156
157 // simple hack to clean wireframes ...
158 if ( m_fancyRenderObjects.size() < m_wireframes.size() ) { m_wireframes.clear(); }
159}
160
161template <typename IndexContainerType>
162void computeIndices( Core::Geometry::LineMesh::IndexContainerType& indices,
163 IndexContainerType& other ) {
164
165 for ( const auto& index : other ) {
166 auto s = index.size();
167 for ( unsigned int i = 0; i < s; ++i ) {
168 int i1 = index[i];
169 int i2 = index[( i + 1 ) % s];
170 if ( i1 > i2 ) std::swap( i1, i2 );
171 indices.emplace_back( i1, i2 );
172 }
173 }
174
175 std::sort( indices.begin(),
176 indices.end(),
177 []( const Core::Geometry::LineMesh::IndexType& a,
178 const Core::Geometry::LineMesh::IndexType& b ) {
179 return a[0] < b[0] || ( a[0] == b[0] && a[1] < b[1] );
180 } );
181 indices.erase( std::unique( indices.begin(), indices.end() ), indices.end() );
182}
183
184// store LineMesh and Core, define the observer functor to update data one core update for wireframe
185// linemesh
186template <typename CoreGeometry>
187class VerticesUpdater
188{
189 public:
190 VerticesUpdater( std::shared_ptr<Data::LineMesh> disp, CoreGeometry& core ) :
191 m_disp { disp }, m_core { core } {};
192
193 void operator()() { m_disp->getCoreGeometry().setVertices( m_core.vertices() ); }
195 CoreGeometry& m_core;
196};
197
198template <typename CoreGeometry>
199class IndicesUpdater
200{
201 public:
202 IndicesUpdater( std::shared_ptr<Data::LineMesh> disp, CoreGeometry& core ) :
203 m_disp { disp }, m_core { core } {};
204
205 void operator()() {
206 auto lineIndices = m_disp->getCoreGeometry().getIndicesWithLock();
207 computeIndices( lineIndices, m_core.getIndices() );
208 m_disp->getCoreGeometry().indicesUnlock();
209 }
211 CoreGeometry& m_core;
212};
213
214// create a linemesh to draw wireframe given a core mesh
215template <typename CoreGeometry>
216void setupLineMesh( std::shared_ptr<Data::LineMesh>& disp, CoreGeometry& core ) {
217
218 Core::Geometry::LineMesh lines;
219 Core::Geometry::LineMesh::IndexContainerType indices;
220
221 lines.setVertices( core.vertices() );
222 computeIndices( indices, core.getIndices() );
223 if ( indices.size() > 0 ) {
224 lines.setIndices( std::move( indices ) );
225 disp =
227 disp->updateGL();
228
229 // add observer
230 auto handle = core.template getAttribHandle<typename CoreGeometry::Point>(
231 Ra::Core::Geometry::getAttribName( Ra::Core::Geometry::VERTEX_POSITION ) );
232 core.vertexAttribs().getAttrib( handle ).attach( VerticesUpdater( disp, core ) );
233 core.attach( IndicesUpdater( disp, core ) );
234 }
235 else { disp.reset(); }
236}
237
238void ForwardRenderer::renderInternal( const Data::ViewingParameters& renderData ) {
239
240 m_fbo->bind();
241
242 GL_ASSERT( glEnable( GL_DEPTH_TEST ) );
243 GL_ASSERT( glDepthMask( GL_TRUE ) );
244 GL_ASSERT( glColorMask( 1, 1, 1, 1 ) );
245
246 GL_ASSERT( glDrawBuffers( 4, buffers ) );
247 if ( m_wireframe ) {
249 glEnable( GL_POLYGON_OFFSET_FILL );
250 glPolygonOffset( 1.f, 3.f );
251 // GL_ASSERT( glDepthRange( 0.001, 1.0 ) );
252 }
253 else { glDisable( GL_POLYGON_OFFSET_FILL ); }
254 static const auto clearZeros = Core::Utils::Color::Black().cast<GL_SCALAR_PLAIN>().eval();
255 static const auto clearOnes = Core::Utils::Color::White().cast<GL_SCALAR_PLAIN>().eval();
256 static const float clearDepth { 1.0f };
257
259 auto bgColor = getBackgroundColor().cast<GL_SCALAR_PLAIN>().eval();
260 GL_ASSERT( glClearBufferfv( GL_COLOR, 0, bgColor.data() ) ); // Clear color
261 GL_ASSERT( glClearBufferfv( GL_COLOR, 1, clearZeros.data() ) ); // Clear normals
262 GL_ASSERT( glClearBufferfv( GL_COLOR, 2, clearZeros.data() ) ); // Clear diffuse
263 GL_ASSERT( glClearBufferfv( GL_COLOR, 3, clearZeros.data() ) ); // Clear specular
264 GL_ASSERT( glClearBufferfv( GL_DEPTH, 0, &clearDepth ) ); // Clear depth
265
266 // render background objects (eg sky box)
267 renderBackground( renderData );
268
269 // Z prepass
270 GL_ASSERT( glDepthFunc( GL_LESS ) );
271 GL_ASSERT( glDisable( GL_BLEND ) );
272 GL_ASSERT( glPointSize( 3.f ) );
273
274 // Set in RenderParam the configuration about ambiant lighting (instead of hard constant
275 // direclty in shaders)
276
277 for ( const auto& ro : m_fancyRenderObjects ) {
278 ro->render( {}, renderData, DefaultRenderingPasses::Z_PREPASS );
279 }
280 // Transparent objects are rendered in the Z-prepass, but only their fully opaque fragments
281 // (if any) might influence the z-buffer.
282 // Rendering transparent objects assuming that they
283 // discard all their non-opaque fragments
284 for ( const auto& ro : m_transparentRenderObjects ) {
285 ro->render( {}, renderData, DefaultRenderingPasses::Z_PREPASS );
286 }
287 // Volumetric objects are not rendered in the Z-prepass
288
289 // Opaque Lighting pass
290 GL_ASSERT( glDepthFunc( GL_LEQUAL ) );
291 GL_ASSERT( glDepthMask( GL_FALSE ) );
292
293 GL_ASSERT( glEnable( GL_BLEND ) );
294 GL_ASSERT( glBlendFunc( GL_ONE, GL_ONE ) );
295
296 GL_ASSERT( glDrawBuffers( 1, buffers ) ); // Draw color texture
297
298 // Radium V2 : this render loop might be greatly improved by inverting light and objects
299 // loop.
300 // Make shaders bounded only once, minimize full stats-changes, ...
301 if ( m_lightmanagers[0]->count() > 0 ) {
302 // for ( const auto& l : m_lights )
303 for ( size_t i = 0; i < m_lightmanagers[0]->count(); ++i ) {
304 const auto l = m_lightmanagers[0]->getLight( i );
305 for ( const auto& ro : m_fancyRenderObjects ) {
306 ro->render(
307 l->getRenderParameters(), renderData, DefaultRenderingPasses::LIGHTING_OPAQUE );
308 }
309 // Rendering transparent objects assuming that they discard all their non-opaque
310 // fragments
311 for ( const auto& ro : m_transparentRenderObjects ) {
312 ro->render(
313 l->getRenderParameters(), renderData, DefaultRenderingPasses::LIGHTING_OPAQUE );
314 }
315 }
316 }
317 else { LOG( logINFO ) << "Opaque : no light sources, unable to render"; }
318
319 // Transparency (blending) pass
320 if ( !m_transparentRenderObjects.empty() ) {
321 m_fbo->unbind();
322
323 m_oitFbo->bind();
324
325 GL_ASSERT( glDrawBuffers( 2, buffers ) );
326 GL_ASSERT( glClearBufferfv( GL_COLOR, 0, clearZeros.data() ) );
327 GL_ASSERT( glClearBufferfv( GL_COLOR, 1, clearOnes.data() ) );
328
329 GL_ASSERT( glDepthFunc( GL_LESS ) );
330 GL_ASSERT( glEnable( GL_BLEND ) );
331
332 GL_ASSERT( glBlendEquation( GL_FUNC_ADD ) );
333 GL_ASSERT( glBlendFunci( 0, GL_ONE, GL_ONE ) );
334 GL_ASSERT( glBlendFunci( 1, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA ) );
335
336 if ( m_lightmanagers[0]->count() > 0 ) {
337 // for ( const auto& l : m_lights )
338 for ( size_t i = 0; i < m_lightmanagers[0]->count(); ++i ) {
339 const auto l = m_lightmanagers[0]->getLight( i );
340
341 for ( const auto& ro : m_transparentRenderObjects ) {
342 ro->render( l->getRenderParameters(),
343 renderData,
344 DefaultRenderingPasses::LIGHTING_TRANSPARENT );
345 }
346 }
347 }
348 else { LOG( logINFO ) << "Transparent : no light sources, unable to render"; }
349
350 m_oitFbo->unbind();
351
352 m_fbo->bind();
353 GL_ASSERT( glDrawBuffers( 1, buffers ) );
354 GL_ASSERT( glDisable( GL_DEPTH_TEST ) );
355 GL_ASSERT( glBlendFunc( GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA ) );
356 {
357 auto shader = m_shaderProgramManager->getShaderProgram( "ComposeOIT" );
358 shader->bind();
359 shader->setUniform( "u_OITSumColor", m_textures[RendererTextures_OITAccum].get(), 0 );
360 shader->setUniform(
361 "u_OITSumWeight", m_textures[RendererTextures_OITRevealage].get(), 1 );
362
363 m_quadMesh->render( shader );
364 }
365 GL_ASSERT( glEnable( GL_DEPTH_TEST ) );
366 }
367
368 // Volumetric pass
369 // Z-test is enabled but z-write must be disable to allow access to the z-buffer in the
370 // shader.
371 // This pass render in its own FBO and copy the result to the main colortexture
372 if ( m_lightmanagers[0]->count() > 0 ) {
373 if ( !m_volumetricRenderObjects.empty() ) {
374
375 m_volumeFbo->bind();
376 GL_ASSERT( glDrawBuffers( 1, buffers ) );
377 static const auto alpha = Core::Utils::Color::Alpha().cast<GL_SCALAR_PLAIN>().eval();
378 GL_ASSERT( glClearBufferfv( GL_COLOR, 0, alpha.data() ) );
379 GL_ASSERT( glDisable( GL_BLEND ) );
380
381 Data::RenderParameters composeParams;
382 composeParams.setTexture( "imageColor", m_textures[RendererTextures_HDR].get() );
383 composeParams.setTexture( "imageDepth", m_textures[RendererTextures_Depth].get() );
384 Data::RenderParameters passParams;
385 passParams.setVariable( "compose_data", composeParams );
386
387 for ( size_t i = 0; i < m_lightmanagers[0]->count(); ++i ) {
388 const auto l = m_lightmanagers[0]->getLight( i );
389
390 passParams.setVariable( "light_source", l->getRenderParameters() );
391
392 for ( const auto& ro : m_volumetricRenderObjects ) {
393 ro->render(
394 passParams, renderData, DefaultRenderingPasses::LIGHTING_VOLUMETRIC );
395 }
396 }
397 m_volumeFbo->unbind();
398 m_fbo->bind();
399 GL_ASSERT( glDrawBuffers( 1, buffers ) );
400 GL_ASSERT( glDisable( GL_DEPTH_TEST ) );
401 GL_ASSERT( glEnable( GL_BLEND ) );
402 GL_ASSERT( glBlendFunc( GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA ) );
403 {
404 auto shader = m_shaderProgramManager->getShaderProgram( "ComposeVolume" );
405 shader->bind();
406 shader->setUniform( "volumeImage", m_textures[RendererTextures_Volume].get(), 0 );
407 m_quadMesh->render( shader );
408 }
409 GL_ASSERT( glEnable( GL_DEPTH_TEST ) );
410 }
411 }
412
413 if ( m_wireframe ) {
414 m_fbo->bind();
415
416 glDisable( GL_POLYGON_OFFSET_FILL );
417 GL_ASSERT( glDepthFunc( GL_LEQUAL ) );
418 GL_ASSERT( glEnable( GL_BLEND ) );
419 glBlendEquationSeparate( GL_FUNC_ADD, GL_FUNC_ADD );
420 glBlendFuncSeparate( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO );
421 GL_ASSERT( glDrawBuffers( 1, buffers ) ); // Draw color texture
422
423 auto drawWireframe = [this, &renderData]( const auto& ro ) {
425
426 WireMap::iterator it = m_wireframes.find( ro.get() );
427 if ( it == m_wireframes.end() ) {
429
433
434 auto displayable = ro->getMesh();
435 auto tm = std::dynamic_pointer_cast<trimesh>( displayable );
436 auto tp = std::dynamic_pointer_cast<polymesh>( displayable );
437 auto tq = std::dynamic_pointer_cast<quadmesh>( displayable );
438
439 auto processLineMesh = []( auto cm, std::shared_ptr<Data::LineMesh>& lm ) {
440 if ( cm->getRenderMode() ==
441 Data::AttribArrayDisplayable::MeshRenderMode::RM_TRIANGLES ) {
442 setupLineMesh( lm, cm->getCoreGeometry() );
443 }
444 };
445 if ( tm ) { processLineMesh( tm, disp ); }
446 if ( tp ) { processLineMesh( tp, disp ); }
447 if ( tq ) { processLineMesh( tq, disp ); }
448
449 m_wireframes[ro.get()] = disp;
450 wro = disp;
451 }
452 else { wro = it->second; }
453
454 const Data::ShaderProgram* shader =
455 m_shaderProgramManager->getShaderProgram( "Wireframe" );
456
457 if ( shader && wro ) {
458 shader->bind();
459 if ( ro->isVisible() ) {
460 wro->updateGL();
461
462 Core::Matrix4 modelMatrix = ro->getTransformAsMatrix();
463 shader->setUniform( "transform.proj", renderData.projMatrix );
464 shader->setUniform( "transform.view", renderData.viewMatrix );
465 shader->setUniform( "transform.model", modelMatrix );
466 shader->setUniform( "viewport", Core::Vector2 { m_width, m_height } );
467 wro->render( shader );
468
469 GL_CHECK_ERROR;
470 }
471 }
472 };
473
474 for ( const auto& ro : m_fancyRenderObjects ) {
475 drawWireframe( ro );
476 }
477 for ( const auto& ro : m_transparentRenderObjects ) {
478 drawWireframe( ro );
479 }
480 }
481
482 // Restore state
483 GL_ASSERT( glDepthFunc( GL_LESS ) );
484 GL_ASSERT( glDisable( GL_BLEND ) );
485 m_fbo->unbind();
486}
487
488// Draw debug stuff, do not overwrite depth map but do depth testing
489void ForwardRenderer::debugInternal( const Data::ViewingParameters& renderData ) {
490 if ( m_drawDebug ) {
491 m_postprocessFbo->bind();
492 GL_ASSERT( glDisable( GL_BLEND ) );
493 GL_ASSERT( glEnable( GL_DEPTH_TEST ) );
494 GL_ASSERT( glDepthMask( GL_FALSE ) );
495 GL_ASSERT( glDepthFunc( GL_LESS ) );
496
497 glDrawBuffers( 1, buffers );
498 for ( const auto& ro : m_debugRenderObjects ) {
499 ro->render( {}, renderData );
500 }
501
502 DebugRender::getInstance()->render( renderData.viewMatrix, renderData.projMatrix );
503
504 m_postprocessFbo->unbind();
505
506 m_uiXrayFbo->bind();
507 // Draw X rayed objects always on top of normal objects
508 GL_ASSERT( glDepthMask( GL_TRUE ) );
509 GL_ASSERT( glClear( GL_DEPTH_BUFFER_BIT ) );
510 Data::RenderParameters xrayLightParams;
511 using namespace Core::VariableSetEnumManagement;
512 xrayLightParams.setVariable( "light.color", Ra::Core::Utils::Color::Grey( 5.0 ) );
513 setEnumVariable( xrayLightParams, "light.type", Scene::Light::LightType::DIRECTIONAL );
514 xrayLightParams.setVariable( "light.directional.direction", Core::Vector3( 0, -1, 0 ) );
515 for ( const auto& ro : m_xrayRenderObjects ) {
516 if ( ro->isVisible() ) { ro->render( xrayLightParams, renderData ); }
517 }
518 m_uiXrayFbo->unbind();
519 }
520}
521
522// Draw UI stuff, always drawn on top of everything else + clear ZMask
523void ForwardRenderer::uiInternal( const Data::ViewingParameters& renderData ) {
524
525 m_uiXrayFbo->bind();
526 glDrawBuffers( 1, buffers );
527 // Enable z-test
528 GL_ASSERT( glDepthMask( GL_TRUE ) );
529 GL_ASSERT( glEnable( GL_DEPTH_TEST ) );
530 GL_ASSERT( glDepthFunc( GL_LESS ) );
531 GL_ASSERT( glClear( GL_DEPTH_BUFFER_BIT ) );
532 for ( const auto& ro : m_uiRenderObjects ) {
533 if ( ro->isVisible() ) {
534 auto shader = ro->getRenderTechnique()->getShader();
535 if ( !shader ) {
536 LOG( logERROR ) << "shader not found" << ro->getName() << " "
537 << ro->getRenderTechnique()->getConfiguration().getName();
538 }
539 else {
540
541 // bind data
542 shader->bind();
543
544 Core::Matrix4 M = ro->getTransformAsMatrix();
545 Core::Matrix4 MV = renderData.viewMatrix * M;
546 Core::Vector3 V = MV.block<3, 1>( 0, 3 );
547 Scalar d = V.norm();
548
549 Core::Matrix4 S = Core::Matrix4::Identity();
550 S.coeffRef( 0, 0 ) = S.coeffRef( 1, 1 ) = S.coeffRef( 2, 2 ) = d;
551
552 M = M * S;
553
554 shader->setUniform( "transform.proj", renderData.projMatrix );
555 shader->setUniform( "transform.view", renderData.viewMatrix );
556 shader->setUniform( "transform.model", M );
557
558 auto shaderParameter = ro->getRenderTechnique()->getParametersProvider();
559 if ( shaderParameter != nullptr ) shaderParameter->getParameters().bind( shader );
560
561 // render
562 ro->getMesh()->render( shader );
563 }
564 }
565 }
566 m_uiXrayFbo->unbind();
567}
568
569void ForwardRenderer::postProcessInternal( const Data::ViewingParameters& renderData ) {
570 CORE_UNUSED( renderData );
571
572 m_postprocessFbo->bind();
573
574 GL_ASSERT( glDrawBuffers( 1, buffers ) );
575
576 GL_ASSERT( glDisable( GL_DEPTH_TEST ) );
577 GL_ASSERT( glDepthMask( GL_FALSE ) );
578
579 const Data::ShaderProgram* shader = m_shaderProgramManager->getShaderProgram( "Hdr2Ldr" );
580 shader->bind();
581 shader->setUniform( "screenTexture", m_textures[RendererTextures_HDR].get(), 0 );
582 m_quadMesh->render( shader );
583
584 GL_ASSERT( glDepthMask( GL_TRUE ) );
585 GL_ASSERT( glEnable( GL_DEPTH_TEST ) );
586
587 m_postprocessFbo->unbind();
588}
589
590void ForwardRenderer::resizeInternal() {
591 m_pingPongSize = std::pow( uint( 2 ), uint( std::log2( std::min( m_width, m_height ) ) ) );
592
593 for ( auto& tex : m_textures ) {
594 tex->resize( m_width, m_height );
595 }
596
597 m_fbo->bind();
598 m_fbo->attachTexture( GL_DEPTH_ATTACHMENT,
599 m_textures[RendererTextures_Depth]->getGpuTexture() );
600 m_fbo->attachTexture( GL_COLOR_ATTACHMENT0, m_textures[RendererTextures_HDR]->getGpuTexture() );
601 m_fbo->attachTexture( GL_COLOR_ATTACHMENT1,
602 m_textures[RendererTextures_Normal]->getGpuTexture() );
603 m_fbo->attachTexture( GL_COLOR_ATTACHMENT2,
604 m_textures[RendererTextures_Diffuse]->getGpuTexture() );
605 m_fbo->attachTexture( GL_COLOR_ATTACHMENT3,
606 m_textures[RendererTextures_Specular]->getGpuTexture() );
607 if ( m_fbo->checkStatus() != GL_FRAMEBUFFER_COMPLETE ) {
608 LOG( logERROR ) << "FBO Error (ForwardRenderer::m_fbo): " << m_fbo->checkStatus();
609 }
610
611 m_volumeFbo->bind();
612 m_volumeFbo->attachTexture( GL_DEPTH_ATTACHMENT,
613 m_textures[RendererTextures_Depth]->getGpuTexture() );
614 m_volumeFbo->attachTexture( GL_COLOR_ATTACHMENT0,
615 m_textures[RendererTextures_Volume]->getGpuTexture() );
616 if ( m_volumeFbo->checkStatus() != GL_FRAMEBUFFER_COMPLETE ) {
617 LOG( logERROR ) << "FBO Error (ForwardRenderer::m_volumeFbo) : "
618 << m_volumeFbo->checkStatus();
619 }
620
621 m_oitFbo->bind();
622 m_oitFbo->attachTexture( GL_DEPTH_ATTACHMENT,
623 m_textures[RendererTextures_Depth]->getGpuTexture() );
624 m_oitFbo->attachTexture( GL_COLOR_ATTACHMENT0,
625 m_textures[RendererTextures_OITAccum]->getGpuTexture() );
626 m_oitFbo->attachTexture( GL_COLOR_ATTACHMENT1,
627 m_textures[RendererTextures_OITRevealage]->getGpuTexture() );
628 if ( m_oitFbo->checkStatus() != GL_FRAMEBUFFER_COMPLETE ) {
629 LOG( logERROR ) << "FBO Error (ForwardRenderer::m_oitFbo) : " << m_oitFbo->checkStatus();
630 }
631
632 m_postprocessFbo->bind();
633 m_postprocessFbo->attachTexture( GL_DEPTH_ATTACHMENT,
634 m_textures[RendererTextures_Depth]->getGpuTexture() );
635 m_postprocessFbo->attachTexture( GL_COLOR_ATTACHMENT0, m_fancyTexture->getGpuTexture() );
636 if ( m_postprocessFbo->checkStatus() != GL_FRAMEBUFFER_COMPLETE ) {
637 LOG( logERROR ) << "FBO Error (ForwardRenderer::m_postprocessFbo) : "
638 << m_postprocessFbo->checkStatus();
639 }
640
641 // FIXED : when m_postprocessFbo use the RendererTextures_Depth, the depth buffer is erased
642 // and is therefore useless for future computation. Do not use this post-process FBO to
643 // render eveything else than the scene. Create several FBO with ther own configuration
644 // (uncomment Renderer::m_depthTexture->texture() to see the difference.)
645 m_uiXrayFbo->bind();
646 m_uiXrayFbo->attachTexture( GL_DEPTH_ATTACHMENT, Renderer::m_depthTexture->getGpuTexture() );
647 m_uiXrayFbo->attachTexture( GL_COLOR_ATTACHMENT0, m_fancyTexture->getGpuTexture() );
648 if ( m_uiXrayFbo->checkStatus() != GL_FRAMEBUFFER_COMPLETE ) {
649 LOG( logERROR ) << "FBO Error (ForwardRenderer::m_uiXrayFbo) : "
650 << m_uiXrayFbo->checkStatus();
651 }
652 // finished with fbo, undbind to bind default
653 globjects::Framebuffer::unbind();
654}
655
656/* Test Point cloud parameter provider */
657/*
658 * WARNING : this class is here only for testing and experimentation purpose.
659 * It will be replace soon by a better management of the way components could add specific
660 * properties to a rendertechnique
661 * TODO : see PR Draft and gist subShaderBlob
662 */
663class PointCloudParameterProvider : public Data::ShaderParameterProvider
664{
665 public:
666 PointCloudParameterProvider( std::shared_ptr<Data::Material> mat,
667 Scene::PointCloudComponent* pointCloud ) :
668 ShaderParameterProvider(), m_displayMaterial( mat ), m_component( pointCloud ) {}
669 ~PointCloudParameterProvider() override = default;
670 void updateGL() override {
671 m_displayMaterial->updateGL();
672 auto& renderParameters = getParameters();
673 renderParameters.mergeReplaceVariables( m_displayMaterial->getParameters() );
674 renderParameters.setVariable( "pointCloudSplatRadius", m_component->getSplatSize() );
675 }
676
677 private:
678 std::shared_ptr<Data::Material> m_displayMaterial;
679 Scene::PointCloudComponent* m_component;
680};
681
682/*
683 * Build renderTechnique for Forward Renderer : this is the default in Radium, so create Default
684 * Render Technique
685 */
686bool ForwardRenderer::buildRenderTechnique( RenderObject* ro ) const {
687 auto material = ro->getMaterial();
688 if ( !material ) {
689 LOG( logWARNING ) << "ForwardRenderer : no material found when building RenderTechnique"
690 << " - adding red Lambertian material";
691 auto defMat = new Data::LambertianMaterial( "ForwardRenderer::Default material" );
692 defMat->setColor( Ra::Core::Utils::Color::Red() );
693 material.reset( defMat );
694 }
695 auto builder = EngineRenderTechniques::getDefaultTechnique( material->getMaterialName() );
696 auto rt = Core::make_shared<RenderTechnique>();
697 // define the technique for rendering this RenderObject (here, using the default from
698 // Material name)
699 // NOTE : Setting transparency to true does not hurt performances here. It will just allow to
700 // change the transparency of an object online
701 builder.second( *rt, true /*material->isTransparent()*/ );
702 // If renderObject is a point cloud, add geometry shader for splatting
703 auto RenderedGeometry = ro->getMesh().get();
704
705 /*
706 * WARNING : this way of managing specific geometries is here only for testing and
707 * experimentation purpose. It will be replace soon by a better management of the way
708 * components could add specific properties to a rendertechnique
709 * TODO : see PR Draft and gist subShaderBlob
710 */
711 if ( RenderedGeometry && RenderedGeometry->getNumFaces() == 0 ) {
712 auto pointCloud = dynamic_cast<Scene::PointCloudComponent*>( ro->getComponent() );
713 if ( pointCloud ) {
714 auto addGeomShader = [&rt]( Core::Utils::Index pass ) {
715 if ( rt->hasConfiguration( pass ) ) {
716 Data::ShaderConfiguration config = rt->getConfiguration( pass );
717 config.addShader( Data::ShaderType_GEOMETRY,
718 RadiumEngine::getInstance()->getResourcesDir() +
719 "Shaders/Points/PointCloud.geom.glsl" );
720 rt->setConfiguration( config, pass );
721 }
722 };
723
724 addGeomShader( DefaultRenderingPasses::LIGHTING_OPAQUE );
725 addGeomShader( DefaultRenderingPasses::LIGHTING_TRANSPARENT );
726 addGeomShader( DefaultRenderingPasses::Z_PREPASS );
727 // construct the parameter provider for the technique
728 auto pr = std::make_shared<PointCloudParameterProvider>( material, pointCloud );
729 rt->setParametersProvider( pr );
730 }
731 else { rt->setParametersProvider( material ); }
732 }
733 else {
734 // make the material the parameter provider for the technique
735 rt->setParametersProvider( material );
736 }
737 ro->setRenderTechnique( rt );
738 return true;
739}
740
741void ForwardRenderer::updateShadowMaps() {
742 // Radium V2 : implement shadow mapping
743}
744
745} // namespace Rendering
746} // namespace Engine
747} // namespace Ra
T begin(T... args)
An engine mesh owning CoreGeometry, with indices.
Definition Mesh.hpp:335
Implementation of the Lambertian Material BSDF.
Management of shader parameters with automatic binding of a named parameter to the corresponding glsl...
void setVariable(const std::string &name, RenderParameters &rp)
overload create ref wrapper for RenderParameters variable
void setTexture(const std::string &name, T *tex, int texUnit=-1)
Adding a texture parameter.
void addShader(ShaderType type, const std::string &name)
Shader program parameter provider.
void setUniform(const char *name, const T &value) const
Uniform setters.
DefaultLightManager. A simple Light Manager with a list of lights.
T emplace_back(T... args)
T end(T... args)
T erase(T... args)
T make_shared(T... args)
T min(T... args)
T move(T... args)
std::shared_ptr< T > make_shared(Args &&... args)
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
T dynamic_pointer_cast(T... args)
T pow(T... args)
T reset(T... args)
T sort(T... args)
the set of viewing parameters extracted from the camera and given to the renderer
T swap(T... args)
T unique(T... args)