Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
RenderingComponent.cpp
Go to the documentation of this file.
1
2
3#include "config.h"
4
10
11#include "Core/Headers/Kernel.h"
14
16
19
21
26
28
31
36
37namespace Divide
38{
39
40 namespace
41 {
43 }
45 const SceneGraphNode* sgn,
46 const SceneRenderState& sceneRenderState,
47 const RenderTargetID& renderTarget,
48 const U16 passIndex,
49 const U8 passVariant,
50 Camera* camera ) noexcept
51 : _context( context )
52 , _sgn( sgn )
53 , _sceneRenderState( sceneRenderState )
54 , _renderTarget( renderTarget )
55 , _camera( camera )
56 , _passIndex( passIndex )
57 , _passVariant( passVariant )
58 {
59 }
60
63 _gfxContext( context.gfx() ),
64 _config( context.config() ),
65 _reflectionProbeIndex( SceneEnvironmentProbePool::SkyProbeLayerIndex() )
66 {
67 _lodLevels.fill( 0u );
68 _lodLockLevels.fill( { false, U8_ZERO } );
69 _renderRange.min = 0.f;
70 _renderRange.max = g_renderRangeLimit;
71
72 instantiateMaterial( parentSGN->getNode().getMaterialTpl() );
73
78
82 {
83 EditorComponentField occlusionCullField = {};
84 occlusionCullField._name = "HiZ Occlusion Cull";
85 occlusionCullField._data = &_occlusionCull;
87 occlusionCullField._basicType = PushConstantType::BOOL;
88 occlusionCullField._readOnly = false;
89 _editorComponent.registerField( MOV( occlusionCullField ) );
90 }
91 {
92 EditorComponentField vaxisField = {};
93 vaxisField._name = "Show Debug Axis";
94 vaxisField._data = &_showAxis;
97 vaxisField._readOnly = false;
98 _editorComponent.registerField( MOV( vaxisField ) );
99 }
100 {
101 EditorComponentField receivesShadowsField = {};
102 receivesShadowsField._name = "Receives Shadows";
103 receivesShadowsField._data = &_receiveShadows;
104 receivesShadowsField._type = EditorComponentFieldType::SWITCH_TYPE;
105 receivesShadowsField._basicType = PushConstantType::BOOL;
106 receivesShadowsField._readOnly = false;
107 _editorComponent.registerField( MOV( receivesShadowsField ) );
108 }
109 {
110 EditorComponentField castsShadowsField = {};
111 castsShadowsField._name = "Casts Shadows";
112 castsShadowsField._data = &_castsShadows;
114 castsShadowsField._basicType = PushConstantType::BOOL;
115 castsShadowsField._readOnly = false;
116 _editorComponent.registerField( MOV( castsShadowsField ) );
117 }
118 _editorComponent.onChangedCbk( [this]( const std::string_view field )
119 {
120 if ( field == "Show Axis" )
121 {
123 }
124 else if ( field == "Receives Shadows" )
125 {
127 }
128 else if ( field == "Casts Shadows" )
129 {
131 }
132 } );
133
134 const SceneNode& node = _parentSGN->getNode();
135 if ( Is3DObject (node.type()) )
136 {
137 // Do not cull the sky
138 if ( static_cast<const Object3D&>(node).type() == SceneNodeType::TYPE_SKY )
139 {
140 occlusionCull( false );
141 }
142 }
143
145 }
146
148 {
151 }
152
154 {
155 if ( material == INVALID_HANDLE<Material> )
156 {
157 return;
158 }
159
160 _materialInstance = Get(material)->clone( (_parentSGN->name() + "_instance").c_str() );
161
162 if ( _materialInstance != INVALID_HANDLE<Material> )
163 {
165
166 DIVIDE_ASSERT( !mat->resourceName().empty() );
167
168 EditorComponentField materialField = {};
169 materialField._name = "Material";
170 materialField._data = mat;
172 materialField._readOnly = false;
173 // should override any existing entry
174 _editorComponent.registerField( MOV( materialField ) );
175
176 EditorComponentField lockLodField = {};
177 lockLodField._name = "Rendered LOD Level";
180 lockLodField._basicType = PushConstantType::UINT;
181 lockLodField._data = &_lodLevels[to_base( RenderStage::DISPLAY )];
182 lockLodField._readOnly = true;
183 lockLodField._serialise = false;
184 _editorComponent.registerField( MOV( lockLodField ) );
185
186 EditorComponentField lockLodLevelField = {};
187 lockLodLevelField._name = "Lock LoD Level";
188 lockLodLevelField._type = EditorComponentFieldType::PUSH_TYPE;
189 lockLodLevelField._range = { 0.0f, to_F32( MAX_LOD_LEVEL ) };
190 lockLodLevelField._basicType = PushConstantType::UINT;
191 lockLodLevelField._basicTypeSize = PushConstantSize::BYTE;
192 lockLodLevelField._data = &_lodLockLevels[to_base( RenderStage::DISPLAY )].second;
193 lockLodLevelField._readOnly = false;
194 _editorComponent.registerField( MOV( lockLodLevelField ) );
195
196 EditorComponentField renderLodField = {};
197 renderLodField._name = "Lock LoD";
199 renderLodField._basicType = PushConstantType::BOOL;
200 renderLodField._data = &_lodLockLevels[to_base( RenderStage::DISPLAY )].first;
201 renderLodField._readOnly = false;
202 _editorComponent.registerField( MOV( renderLodField ) );
203
204 mat->properties().isStatic( _parentSGN->usageContext() == NodeUsageContext::NODE_STATIC );
205 mat->properties().isInstanced( mat->properties().isInstanced() || isInstanced() );
206 }
207 }
208
209 void RenderingComponent::setMinRenderRange( const F32 minRange ) noexcept
210 {
211 _renderRange.min = std::max( minRange, 0.f );
212 }
213
214 void RenderingComponent::setMaxRenderRange( const F32 maxRange ) noexcept
215 {
216 _renderRange.max = std::min( maxRange, 1.0f * g_renderRangeLimit );
217 }
218
220 {
222 auto& packagesPerPassType = _renderPackages[to_base( stage )];
223 auto& packagesPerVariant = packagesPerPassType[to_base( pass )];
224 for ( auto& packagesPerPassIndex : packagesPerVariant )
225 {
226 for ( auto& pacakgesPerIndex : packagesPerPassIndex )
227 {
228 for ( PackageEntry& entry : pacakgesPerIndex )
229 {
230 Clear( entry._package );
231 }
232 }
233 }
234 }
235
236 void RenderingComponent::updateReflectRefractDescriptors(const bool reflectState, const bool refractState )
237 {
238 _updateReflection = reflectState;
239 _updateRefraction = refractState;
240 }
241
243 {
245 for ( auto& packagesPerPassType : _renderPackages )
246 {
247 for ( auto& packagesPerVariant : packagesPerPassType )
248 {
249 for ( auto& packagesPerPassIndex : packagesPerVariant )
250 {
251 for ( auto& pacakgesPerIndex : packagesPerPassIndex )
252 {
253 for ( PackageEntry& entry : pacakgesPerIndex )
254 {
255 Clear( entry._package );
256 }
257 }
258 }
259 }
260 }
261 }
262
263 bool RenderingComponent::canDraw( const RenderStagePass& renderStagePass )
264 {
266 PROFILE_TAG( "Node", (_parentSGN->name().c_str()) );
267
268 // Can we render without a material? Maybe. IDK.
269 bool shaderJustFinishedLoading = false;
270 if ( _materialInstance == INVALID_HANDLE<Material> || Get(_materialInstance)->canDraw( renderStagePass, shaderJustFinishedLoading ) )
271 {
272 if ( shaderJustFinishedLoading )
273 {
274 _parentSGN->SendEvent(
275 {
277 ._sourceCmp = this
278 });
279 }
280
282 }
283
284 return false;
285 }
286
288 {
289 if ( _materialInstance != INVALID_HANDLE<Material> )
290 {
291 Get(_materialInstance)->properties().isStatic( context == NodeUsageContext::NODE_STATIC );
292 }
293 }
294
296 {
297 if ( _materialInstance != INVALID_HANDLE<Material> )
298 {
299 Get(_materialInstance)->rebuild();
300 rebuildDrawCommands( true );
301 }
302
303 const SceneGraphNode::ChildContainer& children = _parentSGN->getChildren();
304 SharedLock<SharedMutex> r_lock( children._lock );
305 const U32 childCount = children._count;
306 for ( U32 i = 0u; i < childCount; ++i )
307 {
308 if ( children._data[i]->HasComponents( ComponentType::RENDERING ) )
309 {
310 children._data[i]->get<RenderingComponent>()->rebuildMaterial();
311 }
312 }
313 }
314
315 void RenderingComponent::setLoDIndexOffset( const U8 lodIndex, size_t indexOffset, size_t indexCount ) noexcept
316 {
317 if ( lodIndex < _lodIndexOffsets.size() )
318 {
319 _lodIndexOffsets[lodIndex] = { indexOffset, indexCount };
320 }
321 }
322
324 {
326 return !_drawCommands._data.empty();
327 }
328
330 {
332
333 if ( _materialInstance != INVALID_HANDLE<Material> )
334 {
335 Get(_materialInstance)->getData( _reflectionProbeIndex, dataOut );
336 }
337 }
338
340 void RenderingComponent::postRender( const SceneRenderState& sceneRenderState, const RenderStagePass& renderStagePass, GFX::CommandBuffer& bufferInOut )
341 {
342 if ( renderStagePass._stage != RenderStage::DISPLAY ||
343 renderStagePass._passType != RenderPassType::MAIN_PASS )
344 {
345 return;
346 }
347
348 // Draw bounding box if needed and only in the final stage to prevent Shadow/PostFX artifacts
352
356 {
358 }
359
362 {
363 drawSkeleton();
364 }
365
367 {
369 }
370
371
372 SceneGraphNode* parent = _parentSGN->parent();
373 if ( parent != nullptr && !parent->hasFlag( SceneGraphNode::Flags::PARENT_POST_RENDERED ) )
374 {
376 if ( parent->HasComponents( ComponentType::RENDERING ) )
377 {
378 parent->get<RenderingComponent>()->postRender( sceneRenderState, renderStagePass, bufferInOut );
379 }
380 }
381 }
382
383 U8 RenderingComponent::getLoDLevel( const RenderStage renderStage ) const noexcept
384 {
385 const auto& [_, level] = _lodLockLevels[to_base( renderStage )];
386 return CLAMPED( level, U8_ZERO, MAX_LOD_LEVEL );
387 }
388
389 U8 RenderingComponent::getLoDLevel( const F32 distSQtoCenter, const RenderStage renderStage, const vec4<U16> lodThresholds )
390 {
391 return getLoDLevelInternal( distSQtoCenter, renderStage, lodThresholds );
392 }
393
394 U8 RenderingComponent::getLoDLevelInternal( const F32 distSQtoCenter, const RenderStage renderStage, const vec4<U16> lodThresholds )
395 {
396 const auto& [state, level] = _lodLockLevels[to_base( renderStage )];
397
398 if ( state )
399 {
400 return CLAMPED( level, U8_ZERO, MAX_LOD_LEVEL );
401 }
402
403 const F32 distSQtoCenterClamped = std::max( distSQtoCenter, EPSILON_F32 );
404 for ( U8 i = 0u; i < MAX_LOD_LEVEL; ++i )
405 {
406 if ( distSQtoCenterClamped <= to_F32( SQUARED( lodThresholds[i] ) ) )
407 {
408 return i;
409 }
410 }
411
412 return MAX_LOD_LEVEL;
413 }
414
416 const SceneRenderState& sceneRenderState,
417 const RenderStagePass& renderStagePass,
418 GFX::MemoryBarrierCommand& postDrawMemCmd,
419 const bool refreshData )
420 {
422
423 bool hasCommands = hasDrawCommands();
424
425 if ( refreshData )
426 {
427 U8 drawCmdOptions = 0u;
429 {
430 drawCmdOptions |= to_base( CmdRenderOptions::RENDER_GEOMETRY );
431 }
432 else
433 {
434 drawCmdOptions &= ~to_base( CmdRenderOptions::RENDER_GEOMETRY );
435 }
436
438 {
439 drawCmdOptions |= to_base( CmdRenderOptions::RENDER_WIREFRAME );
440 }
441 else
442 {
443 drawCmdOptions &= ~to_base( CmdRenderOptions::RENDER_WIREFRAME );
444 }
445
446 if ( !hasCommands )
447 {
449 _parentSGN->getNode().buildDrawCommands( _parentSGN, _drawCommands._data );
451 {
452 hasCommands = true;
453 cmd._renderOptions = drawCmdOptions;
454 if ( cmd._cmd.instanceCount > 1 )
455 {
456 isInstanced( true );
457 }
458 }
459 }
460 else
461 {
464 {
465 cmd._renderOptions = drawCmdOptions;
466 }
467 }
468
469 if ( hasCommands )
470 {
471 const BoundsComponent* bComp = _parentSGN->get<BoundsComponent>();
472 const vec3<F32>& cameraEye = cameraSnapshot._eye;
473 const SceneNodeRenderState& renderState = _parentSGN->getNode<>().renderState();
474 if ( renderState.lod0OnCollision() && bComp->getBoundingBox().containsPoint( cameraEye ) )
475 {
476 _lodLevels[to_base( renderStagePass._stage )] = 0u;
477 }
478 else
479 {
480 const BoundingBox& aabb = bComp->getBoundingBox();
481 const vec3<F32> LoDtarget = renderState.useBoundsCenterForLoD() ? aabb.getCenter() : aabb.nearestPoint( cameraEye );
482 const F32 distanceSQToCenter = LoDtarget.distanceSquared( cameraEye );
483 _lodLevels[to_base( renderStagePass._stage )] = getLoDLevelInternal( distanceSQToCenter, renderStagePass._stage, sceneRenderState.lodThresholds( renderStagePass._stage ) );
484 }
485 }
486 }
487
488 if ( hasCommands )
489 {
490 RenderPackage& pkg = getDrawPackage( renderStagePass );
491
492 if ( pkg.pipelineCmd()._pipeline == nullptr )
493 {
494 // New packages will not have any reflect/refract data
496
497 if ( isInstanced() )
498 {
499 pkg.pushConstantsCmd()._uniformData->set( _ID( "INDIRECT_DATA_IDX" ), PushConstantType::UINT, 0u );
500 if ( _materialInstance != INVALID_HANDLE<Material> )
501 {
502 Get(_materialInstance)->properties().isInstanced( true );
503 }
504 }
505 PipelineDescriptor pipelineDescriptor = {};
506
507 if ( _materialInstance != INVALID_HANDLE<Material> )
508 {
510 pipelineDescriptor._stateBlock = mat->getOrCreateRenderStateBlock( renderStagePass );
511 pipelineDescriptor._shaderProgramHandle = mat->getProgramHandle( renderStagePass );
512 pipelineDescriptor._primitiveTopology = mat->topology();
513 pipelineDescriptor._vertexFormat = mat->shaderAttributes();
514 pkg.descriptorSetCmd()._usage = DescriptorSetUsage::PER_DRAW;
515 pkg.descriptorSetCmd()._set = mat->getDescriptorSet( renderStagePass );
516 }
517 else
518 {
519 pipelineDescriptor._stateBlock = {};
520 pipelineDescriptor._shaderProgramHandle = _gfxContext.imShaders()->imWorldShader();
522 }
523 if ( renderStagePass._passType == RenderPassType::TRANSPARENCY_PASS )
524 {
526 state0.enabled( true );
527 state0.blendSrc( BlendProperty::SRC_ALPHA );
528 state0.blendDest( BlendProperty::INV_SRC_ALPHA );
529 state0.blendOp( BlendOperation::ADD );
530 }
531 else if ( renderStagePass._passType == RenderPassType::OIT_PASS )
532 {
534 state0.enabled( true );
535 state0.blendSrc( BlendProperty::ONE );
536 state0.blendDest( BlendProperty::ONE );
537 state0.blendOp( BlendOperation::ADD );
538
540 state1.enabled( true );
541 state1.blendSrc( BlendProperty::ZERO );
542 state1.blendDest( BlendProperty::INV_SRC_COLOR );
543 state1.blendOp( BlendOperation::ADD );
544
546 state2.enabled( true );
547 state2.blendSrc( BlendProperty::ZERO );
548 state2.blendDest( BlendProperty::INV_SRC_COLOR );
549 state2.blendOp( BlendOperation::ADD );
550 }
551
552 pipelineDescriptor._stateBlock._primitiveRestartEnabled = primitiveRestartRequired();
553 pkg.pipelineCmd()._pipeline = _gfxContext.newPipeline( pipelineDescriptor );
554 }
555
556 if ( !IsDepthPass( renderStagePass ) )
557 {
558 const auto updateBinding = [](DescriptorSet& targetSet, const U8 slot, DescriptorSetBindingData& data )
559 {
560 for ( U8 i = 0u; i < targetSet._bindingCount; ++i )
561 {
562 DescriptorSetBinding& bindingEntry = targetSet._bindings[i];
563
564 if ( bindingEntry._slot == slot )
565 {
566 bindingEntry._data = data;
567 return;
568 }
569 }
570 AddBinding(targetSet, slot, ShaderStageVisibility::FRAGMENT )._data = data;
571 };
572
573 if ( _updateReflection )
574 {
576 if ( _reflectionPlanar.first != INVALID_HANDLE<Texture> && renderStagePass._stage != RenderStage::REFLECTION)
577 {
578 //ToDo: Find a way to render reflected items that also have reflections -Ionut
579 Set( data, _reflectionPlanar.first, _reflectionPlanar.second);
580 }
581 else
582 {
584 }
585
586 updateBinding( pkg.descriptorSetCmd()._set, 10, data);
587 }
588 if ( _updateRefraction )
589 {
591 if ( _refractionPlanar.first != INVALID_HANDLE<Texture> && renderStagePass._stage != RenderStage::REFRACTION )
592 {
593 //ToDo: Find a way to render refracted items that also have refractions -Ionut
594 Set( data, _refractionPlanar.first, _refractionPlanar.second );
595 }
596 else
597 {
599 }
600 updateBinding( pkg.descriptorSetCmd()._set, 11, data );
601 }
602 }
603 Attorney::SceneGraphNodeComponent::prepareRender( _parentSGN, *this, pkg, postDrawMemCmd, cameraSnapshot, renderStagePass, refreshData );
604 }
605
606 return hasCommands;
607 }
608
609 void RenderingComponent::retrieveDrawCommands( const RenderStagePass& stagePass, const U32 cmdOffset, DrawCommandContainer& cmdsInOut )
610 {
612
613 const U32 iBufferEntry = _indirectionBufferEntry;
614
615 {
616 RenderPackage& pkg = getDrawPackage( stagePass );
617 if ( isInstanced() )
618 {
619 pkg.pushConstantsCmd()._uniformData->set( _ID( "INDIRECT_DATA_IDX" ), PushConstantType::UINT, iBufferEntry );
620 }
621 pkg.stagePassBaseIndex( BaseIndex( stagePass ) );
622
623 pkg.drawCmdOffset( cmdOffset + to_U32( cmdsInOut.size() ) );
624
625 }
626
627 const auto& [offset, count] = _lodIndexOffsets[std::min( _lodLevels[to_U8( stagePass._stage )], to_U8( _lodIndexOffsets.size() - 1 ) )];
628 const bool autoIndex = offset != 0u || count != 0u;
629 {
631 for ( const GenericDrawCommand& gCmd : _drawCommands._data )
632 {
633 cmdsInOut.push_back( gCmd._cmd );
634 IndirectIndexedDrawCommand& iCmd = cmdsInOut.back();
635 iCmd.baseInstance = isInstanced() ? 0u : (iBufferEntry + 1u); //Make sure to substract 1 in the shader!
636 if ( autoIndex )
637 {
638 iCmd.firstIndex = to_U32( offset );
639 iCmd.indexCount = to_U32( count );
640 }
641 }
642 }
643 }
644
646 {
647 bufferInOut.add( GetCommandBuffer( *pkg ) );
648 bufferInOut.add( pkg->pipelineCmd() );
649 bufferInOut.add( pkg->descriptorSetCmd() );
650 bufferInOut.add( pkg->pushConstantsCmd() );
651 {
652 U32 startOffset = pkg->drawCmdOffset();
653
656 {
657 gCmd._commandOffset = startOffset++;
658 }
659
660 GFX::EnqueueCommand<GFX::DrawCommand>( bufferInOut )->_drawCommands = _drawCommands._data;
661 }
662 }
663
665 {
666 PackagesPerPassType& packagesPerPassType = _renderPackages[to_base( renderStagePass._stage )];
667 PackagesPerVariant& packagesPerVariant = packagesPerPassType[to_base( renderStagePass._passType )];
668 PackagesPerPassIndex& packagesPerPassIndex = packagesPerVariant[to_base( renderStagePass._variant )];
669 PackagesPerIndex& pacakgesPerIndex = packagesPerPassIndex[to_base( renderStagePass._pass )];
670
671 {
673 for ( PackageEntry& entry : pacakgesPerIndex )
674 {
675 if ( entry._index == renderStagePass._index )
676 {
677 return entry._package;
678 }
679 }
680 }
681
683 // check again
684 for ( PackageEntry& entry : pacakgesPerIndex )
685 {
686 if ( entry._index == renderStagePass._index )
687 {
688 return entry._package;
689 }
690 }
691
692 PackageEntry& entry = pacakgesPerIndex.emplace_back();
693 entry._index = renderStagePass._index;
694 return entry._package;
695 }
696
697 bool RenderingComponent::updateReflection( const U16 reflectionIndex,
698 const bool inBudget,
699 Camera* camera,
700 const SceneRenderState& renderState,
701 GFX::CommandBuffer& bufferInOut,
702 GFX::MemoryBarrierCommand& memCmdInOut )
703 {
704 std::pair<Handle<Texture>, SamplerDescriptor> temp = { INVALID_HANDLE<Texture>, {} };
705
706 bool ret = false;
707 //Target texture: the opposite of what we bind during the regular passes
708 if ( _materialInstance != INVALID_HANDLE<Material> && _reflectorType != ReflectorType::COUNT && _reflectionCallback )
709 {
711 ? RenderTargetNames::REFLECTION_PLANAR[reflectionIndex]
713
714 if ( inBudget )
715 {
716 RenderPassManager* passManager = _gfxContext.context().kernel().renderPassManager().get();
717 RenderCbkParams params{ _gfxContext, _parentSGN, renderState, reflectRTID, reflectionIndex, to_U8( _reflectorType ), camera };
718 _reflectionCallback( passManager, params, bufferInOut, memCmdInOut );
719 ret = true;
720 }
721
723 {
725 temp = { targetAtt->texture(), targetAtt->_descriptor._sampler };
726 }
727 }
728
729 if ( _reflectionPlanar != temp )
730 {
731 _reflectionPlanar = temp;
733 }
734
735 return ret;
736 }
737
738 bool RenderingComponent::updateRefraction( const U16 refractionIndex,
739 const bool inBudget,
740 Camera* camera,
741 const SceneRenderState& renderState,
742 GFX::CommandBuffer& bufferInOut,
743 GFX::MemoryBarrierCommand& memCmdInOut )
744 {
745 std::pair<Handle<Texture>, SamplerDescriptor> temp = { INVALID_HANDLE<Texture>, {} };
746
747 bool ret = false;
748 // no default refraction system!
749 if ( _materialInstance != INVALID_HANDLE<Material> && _refractorType != RefractorType::COUNT && _refractionCallback )
750 {
751 const RenderTargetID refractRTID( RenderTargetNames::REFRACTION_PLANAR[refractionIndex] );
752
753 // Only planar for now
755
756 if ( inBudget )
757 {
758 RenderPassManager* passManager = _gfxContext.context().kernel().renderPassManager().get();
759 RenderCbkParams params{ _gfxContext, _parentSGN, renderState, refractRTID, refractionIndex, 0u, camera };
760 _refractionCallback( passManager, params, bufferInOut, memCmdInOut );
761 ret = true;
762 }
763
765 temp = { targetAtt->texture(), targetAtt->_descriptor._sampler };
766 }
767
768 if ( _refractionPlanar != temp )
769 {
770 _refractionPlanar = temp;
772 }
773
774 return ret;
775 }
776
778 {
779 _envProbes.resize( 0 );
781
782 const SceneEnvironmentProbePool* probePool = _context.kernel().projectManager()->getEnvProbes();
783 if ( probePool != nullptr )
784 {
785 probePool->lockProbeList();
786 const auto& probes = probePool->getLocked();
787 _envProbes.reserve( probes.size() );
788
789 U8 idx = 0u;
790 for ( const auto& probe : probes )
791 {
793 {
794 break;
795 }
796 _envProbes.push_back( probe );
797 }
798 probePool->unlockProbeList();
799
800 if ( idx > 0u )
801 {
802 eastl::sort( begin( _envProbes ),
803 end( _envProbes ),
804 [&position]( const auto& a, const auto& b ) noexcept -> bool
805 {
806 return a->distanceSqTo( position ) < b->distanceSqTo( position );
807 } );
808
809 // We need to update this probe because we are going to use it. This will always lag one frame, but at least we keep updates separate from renders.
811 {
812 if ( probe->getBounds().containsPoint( position ) )
813 {
814 _reflectionProbeIndex = probe->poolIndex();
815 probe->queueRefresh();
816 break;
817 }
818 }
819 }
820 }
821 }
822
825 {
827 {
828 _selectionGizmoDirty = false;
829
830 UColour4 colour = UColour4( 64, 255, 128, 255 );
831 if constexpr( Config::Build::ENABLE_EDITOR )
832 {
833 if ( _context.editor().inEditMode() )
834 {
835 colour = UColour4( 255, 255, 255, 255 );
836 }
837 }
838 //draw something else (at some point ...)
839 BoundsComponent* bComp = _parentSGN->get<BoundsComponent>();
840 DIVIDE_ASSERT( bComp != nullptr );
843 }
844
845 _gfxContext.debugDrawOBB( _parentSGN->getGUID() + 12345, _selectionGizmoDescriptor );
846 }
847
850 {
851 if ( _axisGizmoLinesDescriptor._lines.empty() )
852 {
853 Line temp = {};
854 temp._widthStart = 10.0f;
855 temp._widthEnd = 10.0f;
857
858 // Red X-axis
859 temp._positionEnd = WORLD_X_AXIS * 4;
860 temp._colourStart = UColour4( 255, 0, 0, 255 );
861 temp._colourEnd = UColour4( 255, 0, 0, 255 );
862 _axisGizmoLinesDescriptor._lines.push_back( temp );
863
864 // Green Y-axis
865 temp._positionEnd = WORLD_Y_AXIS * 4;
866 temp._colourStart = UColour4( 0, 255, 0, 255 );
867 temp._colourEnd = UColour4( 0, 255, 0, 255 );
868 _axisGizmoLinesDescriptor._lines.push_back( temp );
869
870 // Blue Z-axis
871 temp._positionEnd = WORLD_Z_AXIS * 4;
872 temp._colourStart = UColour4( 0, 0, 255, 255 );
873 temp._colourEnd = UColour4( 0, 0, 255, 255 );
874 _axisGizmoLinesDescriptor._lines.push_back( temp );
875
876 mat4<F32> worldOffsetMatrixCache( GetMatrix( _parentSGN->get<TransformComponent>()->getWorldOrientation() ), false );
877 worldOffsetMatrixCache.setTranslation( _parentSGN->get<TransformComponent>()->getWorldPosition() );
878 _axisGizmoLinesDescriptor.worldMatrix = worldOffsetMatrixCache;
879 }
880
881 _gfxContext.debugDrawLines( _parentSGN->getGUID() + 321, _axisGizmoLinesDescriptor );
882 }
883
885 {
886 const SceneNode& node = _parentSGN->getNode();
887 if ( node.type() != SceneNodeType::TYPE_SUBMESH )
888 {
889 return;
890 }
891
892 // Get the animation component of any submesh. They should be synced anyway.
893 if ( _parentSGN->HasComponents( ComponentType::ANIMATION ) )
894 {
895 // Get the skeleton lines from the submesh's animation component
896 _skeletonLinesDescriptor._lines = _parentSGN->get<AnimationComponent>()->skeletonLines();
898 // Submit the skeleton lines to the GPU for rendering
899 _gfxContext.debugDrawLines( _parentSGN->getGUID() + 213, _skeletonLinesDescriptor );
900 }
901 }
902
903 void RenderingComponent::drawBounds( const bool AABB, const bool OBB, const bool Sphere )
904 {
905 if ( !AABB && !Sphere && !OBB )
906 {
907 return;
908 }
909
910 const SceneNode& node = _parentSGN->getNode();
911 const bool isSubMesh = node.type() == SceneNodeType::TYPE_SUBMESH;
912
913 if ( AABB )
914 {
915 const BoundingBox& bb = _parentSGN->get<BoundsComponent>()->getBoundingBox();
916 IM::BoxDescriptor descriptor;
917 descriptor.min = bb.getMin();
918 descriptor.max = bb.getMax();
919 descriptor.colour = isSubMesh ? UColour4( 0, 0, 255, 255 ) : UColour4( 255, 0, 255, 255 );
920 _gfxContext.debugDrawBox( _parentSGN->getGUID() + 123, descriptor );
921 }
922
923 if ( OBB )
924 {
925 const auto& obb = _parentSGN->get<BoundsComponent>()->getOBB();
926 IM::OBBDescriptor descriptor;
927 descriptor.box = obb;
928 descriptor.colour = isSubMesh ? UColour4( 128, 0, 255, 255 ) : UColour4( 255, 0, 128, 255 );
929
930 _gfxContext.debugDrawOBB( _parentSGN->getGUID() + 123, descriptor );
931 }
932
933 if ( Sphere )
934 {
935 const BoundingSphere& bs = _parentSGN->get<BoundsComponent>()->getBoundingSphere();
936 IM::SphereDescriptor descriptor;
937 descriptor.center = bs.getCenter();
938 descriptor.radius = bs.getRadius();
939 descriptor.colour = isSubMesh ? UColour4( 0, 255, 0, 255 ) : UColour4( 255, 255, 0, 255 );
940 descriptor.slices = 16u;
941 descriptor.stacks = 16u;
942 _gfxContext.debugDrawSphere( _parentSGN->getGUID() + 123, descriptor );
943 }
944 }
945
947 {
948 SGNComponent::OnData( data );
949
950 switch ( data._type )
951 {
953 {
954 const TransformComponent* tComp = static_cast<TransformComponent*>(data._sourceCmp);
955 assert( tComp != nullptr );
957
960 } break;
962 {
963 const BoundsComponent* bComp = static_cast<BoundsComponent*>(data._sourceCmp);
964 toggleBoundsDraw( bComp->showAABB(), bComp->showBS(), bComp->showOBB(), false );
965 } break;
967 {
969 } break;
970 default: break;
971 }
972 }
973}
#define MOV(...)
#define DIVIDE_ASSERT(...)
#define PROFILE_SCOPE_AUTO(CATEGORY)
Definition: Profiler.h:87
#define PROFILE_TAG(NAME,...)
Definition: Profiler.h:88
static void prepareRender(SceneGraphNode *node, RenderingComponent &rComp, RenderPackage &pkg, GFX::MemoryBarrierCommand &postDrawMemCmd, const CameraSnapshot &cameraSnapshot, const RenderStagePass &renderStagePass, const bool refreshData)
vec3< F32 > nearestPoint(const vec3< F32 > &pos) const noexcept
vec3< F32 > getCenter() const noexcept
const vec3< F32 > & getMax() const noexcept
const vec3< F32 > & getMin() const noexcept
bool containsPoint(const vec3< F32 > &point) const noexcept
Definition: BoundingBox.inl:37
const vec3< F32 > & getCenter() const noexcept
F32 getRadius() const noexcept
void showAABB(bool state)
const BoundingBox & getBoundingBox() const noexcept
Rough around the edges Adapter pattern abstracting the actual rendering API and access to the GPU.
Definition: GFXDevice.h:215
GFXRTPool & renderTargetPool() noexcept
Definition: GFXDevice.inl:133
void debugDrawSphere(const I64 ID, IM::SphereDescriptor descriptor) noexcept
Definition: GFXDevice.cpp:2936
Pipeline * newPipeline(const PipelineDescriptor &descriptor)
Create and return a new graphics pipeline. This is only used for caching and doesn't use the object a...
Definition: GFXDevice.cpp:3074
void debugDrawOBB(const I64 ID, IM::OBBDescriptor descriptor) noexcept
Definition: GFXDevice.cpp:2907
void debugDrawBox(const I64 ID, IM::BoxDescriptor descriptor) noexcept
Definition: GFXDevice.cpp:2877
void debugDrawLines(const I64 ID, IM::LineDescriptor descriptor) noexcept
Definition: GFXDevice.cpp:2846
RenderTarget * getRenderTarget(const RenderTargetID target) const
Definition: GFXRTPool.cpp:50
PlatformContext & context() noexcept
Kernel & kernel() noexcept
ProjectManager & parent() noexcept
Handle< Texture > texture() const
RTAttachmentDescriptor _descriptor
Definition: RTAttachment.h:128
static void OnRenderingComponentCreation(RenderingComponent *rComp)
static void OnRenderingComponentDestruction(RenderingComponent *rComp)
RTAttachment * getAttachment(RTAttachmentType type, RTColourAttachmentSlot slot=RTColourAttachmentSlot::SLOT_0) const
std::pair< Handle< Texture >, SamplerDescriptor > _reflectionPlanar
void OnData(const ECS::CustomEvent &data) override
std::array< std::pair< size_t, size_t >, MAX_LOD_LEVEL > _lodIndexOffsets
std::array< PackagesPerVariant, to_base(RenderPassType::COUNT)> PackagesPerPassType
bool renderOptionEnabled(RenderOptions option) const noexcept
Returns true if the specified render option is enabled.
IM::LineDescriptor _skeletonLinesDescriptor
std::array< PackagesPerPassType, to_base(RenderStage::COUNT)> _renderPackages
std::pair< Handle< Texture >, SamplerDescriptor > _refractionPlanar
void drawSelectionGizmo()
Draw some kind of selection doodad. May differ if editor is running or not.
vector< EnvironmentProbeComponent * > _envProbes
void setLoDIndexOffset(U8 lodIndex, size_t indexOffset, size_t indexCount) noexcept
std::array< std::pair< bool, U8 >, to_base(RenderStage::COUNT)> _lodLockLevels
static constexpr U8 MAX_LOD_LEVEL
std::array< PackagesPerPassIndex, to_base(RenderStagePass::VariantType::COUNT)> PackagesPerVariant
void setMinRenderRange(F32 minRange) noexcept
vector< PackageEntry > PackagesPerIndex
U8 getLoDLevelInternal(const F32 distSQtoCenter, RenderStage renderStage, vec4< U16 > lodThresholds)
RenderPackage & getDrawPackage(const RenderStagePass &renderStagePass)
bool updateRefraction(U16 refractionIndex, bool inBudget, Camera *camera, const SceneRenderState &renderState, GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
void instantiateMaterial(Handle< Material > material)
void toggleBoundsDraw(bool showAABB, bool showBS, bool showOBB, bool recursive)
IM::OBBDescriptor _selectionGizmoDescriptor
RenderingComponent(SceneGraphNode *parentSGN, PlatformContext &context)
std::array< PackagesPerIndex, to_base(RenderStagePass::PassIndex::COUNT)> PackagesPerPassIndex
U8 getLoDLevel(RenderStage renderStage) const noexcept
void retrieveDrawCommands(const RenderStagePass &stagePass, const U32 cmdOffset, DrawCommandContainer &cmdsInOut)
void getCommandBuffer(RenderPackage *const pkg, GFX::CommandBuffer &bufferInOut)
void updateReflectRefractDescriptors(bool reflectState, bool refractState)
bool canDraw(const RenderStagePass &renderStagePass)
Handle< Material > _materialInstance
void drawBounds(bool AABB, bool OBB, bool Sphere)
void getMaterialData(NodeMaterialData &dataOut) const
void updateNearestProbes(const vec3< F32 > &position)
void drawDebugAxis()
Draw the axis arrow gizmo.
std::array< U8, to_base(RenderStage::COUNT)> _lodLevels
bool prepareDrawPackage(const CameraSnapshot &cameraSnapshot, const SceneRenderState &sceneRenderState, const RenderStagePass &renderStagePass, GFX::MemoryBarrierCommand &postDrawMemCmd, bool refreshData)
IM::LineDescriptor _axisGizmoLinesDescriptor
void onParentUsageChanged(NodeUsageContext context) const
void toggleRenderOption(RenderOptions option, bool state, bool recursive=true)
bool updateReflection(U16 reflectionIndex, bool inBudget, Camera *camera, const SceneRenderState &renderState, GFX::CommandBuffer &bufferInOut, GFX::MemoryBarrierCommand &memCmdInOut)
void postRender(const SceneRenderState &sceneRenderState, const RenderStagePass &renderStagePass, GFX::CommandBuffer &bufferInOut)
Called after the parent node was rendered.
void setMaxRenderRange(F32 maxRange) noexcept
virtual void OnData(const ECS::CustomEvent &data)
const EnvironmentProbeList & getLocked() const noexcept
T & getNode() noexcept
@ RENDER_WIREFRAME
Render wireframe for all scene geometry.
@ RENDER_OBB
Show/hide oriented bounding boxes.
@ RENDER_SKELETONS
Render skeletons for animated geometry.
@ RENDER_AABB
Show/hide axis aligned bounding boxes.
@ RENDER_BSPHERES
Show/hide bounding spheres.
bool isEnabledOption(RenderOptions option) const noexcept
Definition: SceneState.cpp:74
vec4< U16 > & lodThresholds() noexcept
Definition: SceneState.h:123
static const SamplerDescriptor DefaultSampler() noexcept
Definition: Texture.cpp:100
static Handle< Texture > DefaultTexture2D() noexcept
Definition: Texture.cpp:90
void getWorldMatrix(mat4< F32 > &matOut) const
Quaternion< F32 > getWorldOrientation() const
Return the orientation quaternion.
vec3< F32 > getWorldPosition() const
Return the position.
void setTranslation(const vec3< U > &v) noexcept
void set(std::initializer_list< T > matrix) noexcept
T distanceSquared(const vec3 &v) const noexcept
compute the vector's squared distance to another specified vector
constexpr bool ENABLE_EDITOR
Definition: config.h:66
constexpr U8 MAX_REFLECTIVE_PROBES_PER_PASS
Maximum number of environment probes we are allowed to update per frame.
Definition: config.h:141
constexpr Optick::Category::Type Scene
Definition: Profiler.h:66
Handle console commands that start with a forward slash.
Definition: AIProcessor.cpp:7
NodeUsageContext
Usage context affects lighting, navigation, physics, etc.
Definition: SceneNodeFwd.h:41
std::lock_guard< mutex > LockGuard
Definition: SharedMutex.h:55
static constexpr bool IsDepthPass(const RenderStagePass stagePass) noexcept
constexpr U32 to_U32(const T value)
FORCE_INLINE void DestroyResource(Handle< T > &handle, const bool immediate=false)
constexpr T SQUARED(T input) noexcept
Definition: MathHelper.inl:156
static const vec3< F32 > WORLD_X_AXIS
Definition: MathVectors.h:1439
T * ResourcePtr
Definition: Resource.h:112
uint8_t U8
Handle< GFX::CommandBuffer > GetCommandBuffer(RenderPackage &pkg)
static const vec3< F32 > WORLD_Z_AXIS
Definition: MathVectors.h:1441
int16_t I16
constexpr F32 to_F32(const T value)
constexpr F32 EPSILON_F32
constexpr I16 I16_MAX
std::shared_lock< mutex > SharedLock
Definition: SharedMutex.h:49
Project & parent
Definition: DefaultScene.h:41
uint16_t U16
void Set(DescriptorSetBindingData &dataInOut, ShaderBuffer *buffer, const BufferRange range) noexcept
constexpr U64 _ID(const char *const str, const U64 value=val_64_const) noexcept
DescriptorSetBinding & AddBinding(DescriptorSet &setInOut, U8 slot, U16 stageVisibilityMask)
SGNComponent::Registrar< T, C > BaseComponentType
Definition: SGNComponent.h:207
constexpr U8 to_U8(const T value)
::value constexpr T CLAMPED(T n, T min, T max) noexcept
Definition: MathHelper.inl:126
FORCE_INLINE constexpr bool Is3DObject(const SceneNodeType type) noexcept
Definition: SceneNodeFwd.h:98
mat3< T > GetMatrix(const Quaternion< T > &q) noexcept
Definition: Quaternion.inl:719
static constexpr U8 BaseIndex(const RenderStage stage, const RenderPassType passType) noexcept
vec4< U8 > UColour4
Definition: MathHelper.h:72
static const vec3< F32 > VECTOR3_ZERO
Definition: MathVectors.h:1434
U32 RenderTargetID
void Clear(RenderPackage &pkg) noexcept
FORCE_INLINE T * Get(const Handle< T > handle)
uint32_t U32
Project const SceneEntry & entry
Definition: DefaultScene.h:41
static const vec3< F32 > WORLD_Y_AXIS
Definition: MathVectors.h:1440
constexpr U8 U8_ZERO
eastl::fixed_vector< IndirectIndexedDrawCommand, Config::MAX_VISIBLE_NODES, false > DrawCommandContainer
constexpr auto to_base(const Type value) -> Type
DescriptorSetBindingData _data
std::array< DescriptorSetBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET > _bindings
vec2< F32 > _range
Used by slider_type as a min / max range or dropdown as selected_index / count.
EditorComponentFieldType _type
static constexpr RTColourAttachmentSlot ALBEDO
Definition: GFXDevice.h:228
static constexpr RTColourAttachmentSlot MODULATE
Definition: GFXDevice.h:231
static constexpr RTColourAttachmentSlot ACCUMULATION
Definition: GFXDevice.h:232
static constexpr RTColourAttachmentSlot REVEALAGE
Definition: GFXDevice.h:233
IndirectIndexedDrawCommand _cmd
vec3< F32 > _positionStart
Definition: Line.h:42
F32 _widthStart
Definition: Line.h:46
vec3< F32 > _positionEnd
Definition: Line.h:43
UColour4 _colourStart
Definition: Line.h:44
F32 _widthEnd
Definition: Line.h:47
UColour4 _colourEnd
Definition: Line.h:45
PrimitiveTopology _primitiveTopology
Definition: Pipeline.h:48
AttributeMap _vertexFormat
Definition: Pipeline.h:49
Handle< ShaderProgram > _shaderProgramHandle
Definition: Pipeline.h:47
RTBlendStates _blendStates
Definition: Pipeline.h:45
RenderStateBlock _stateBlock
Definition: Pipeline.h:46
SamplerDescriptor _sampler
Definition: RTAttachment.h:64
std::array< BlendingSettings, to_base(RTColourAttachmentSlot::COUNT)> _settings
RenderCbkParams(GFXDevice &context, const SceneGraphNode *sgn, const SceneRenderState &sceneRenderState, const RenderTargetID &renderTarget, const U16 passIndex, const U8 passVariant, Camera *camera) noexcept
RenderPassType _passType
static RenderTargetID REFLECTION_CUBE
Definition: GFXDevice.h:207
static std::array< RenderTargetID, Config::MAX_REFRACTIVE_NODES_IN_VIEW > REFRACTION_PLANAR
Definition: GFXDevice.h:210
static std::array< RenderTargetID, Config::MAX_REFLECTIVE_NODES_IN_VIEW > REFLECTION_PLANAR
Definition: GFXDevice.h:209
eastl::fixed_vector< SceneGraphNode *, 32, true > _data
Divide::SGNComponent * _sourceCmp
Definition: SGNComponent.h:66