Divide Framework 0.1
A free and open-source 3D Framework under heavy development
Loading...
Searching...
No Matches
RenderPassCuller.cpp
Go to the documentation of this file.
1
2
4
14
15namespace Divide
16{
17
18 namespace
19 {
21 }
22
23 [[nodiscard]] inline U32 RenderPassCuller::FilterMask(const PlatformContext& context) noexcept
24 {
25 const auto& filter = context.config().debug.renderFilter;
26 return (filter.primitives ? 0u : to_base(EntityFilter::PRIMITIVES)) |
27 (filter.meshes ? 0u : to_base(EntityFilter::MESHES )) |
28 (filter.terrain ? 0u : to_base(EntityFilter::TERRAIN )) |
29 (filter.vegetation ? 0u : to_base(EntityFilter::VEGETATION )) |
30 (filter.water ? 0u : to_base(EntityFilter::WATER )) |
31 (filter.sky ? 0u : to_base(EntityFilter::SKY )) |
32 (filter.particles ? 0u : to_base(EntityFilter::PARTICLES ));
33 }
34
35 void RenderPassCuller::PostCullNodes( const NodeCullParams& params, const U16 cullFlags, const U32 filterMask, VisibleNodeList<>& nodesInOut )
36 {
38
39 {
41 const I32 nodeCount = to_I32( nodesInOut.size() );
42 for ( I32 i = nodeCount - 1; i >= 0; i-- )
43 {
44 const VisibleNode& node = nodesInOut.node( i );
45
47 {
48 nodesInOut.remove( i );
49 }
50 }
51 }
52
54 {
56 const I32 nodeCount = to_I32( nodesInOut.size() );
57 for ( I32 i = nodeCount - 1; i >= 0; i-- )
58 {
59 const FrustumCollision collisionResult = Attorney::SceneGraphNodeRenderPassCuller::clippingCullNode( nodesInOut.node( i )._node, params );
60 if ( collisionResult == FrustumCollision::FRUSTUM_OUT )
61 {
62 nodesInOut.remove( i );
63 }
64 }
65 }
66 }
67
68 void RenderPassCuller::FrustumCull( const NodeCullParams& params, U16 cullFlags, const SceneGraph& sceneGraph, const SceneState& sceneState, PlatformContext& context, VisibleNodeList<>& nodesOut )
69 {
71
72 nodesOut.reset();
73
76 {
77 for ( const bool state : params._clippingPlanes.planeState() )
78 {
79 if ( state )
80 {
81 cullFlags &= ~to_base(CullOptions::CULL_AGAINST_CLIPPING_PLANES);
82 break;
83 }
84 }
85
86 const SceneGraphNode::ChildContainer& rootChildren = sceneGraph.getRoot()->getChildren();
87
88 SharedLock<SharedMutex> r_lock( rootChildren._lock );
89 const U32 iterCount = rootChildren._count.load();
90
91 if ( iterCount > g_nodesPerCullingPartition * 2 )
92 {
93 ParallelForDescriptor descriptor = {};
94 descriptor._iterCount = iterCount;
95 descriptor._partitionSize = g_nodesPerCullingPartition;
97 descriptor._useCurrentThread = true;
98 Parallel_For( context.taskPool( TaskPoolType::RENDERER ), descriptor, [&]( const Task*, const U32 start, const U32 end )
99 {
100 for ( U32 i = start; i < end; ++i )
101 {
102 FrustumCullNode( rootChildren._data[i], params, cullFlags, 0u, nodesOut );
103 }
104 });
105 }
106 else
107 {
108 for ( U32 i = 0u; i < iterCount; ++i )
109 {
110 FrustumCullNode( rootChildren._data[i], params, cullFlags, 0u, nodesOut );
111 };
112 }
113 }
114
115 PostCullNodes( params, cullFlags, FilterMask( context ), nodesOut );
116 }
117
119 void RenderPassCuller::FrustumCullNode( SceneGraphNode* currentNode, const NodeCullParams& params, U16 cullFlags, U8 recursionLevel, VisibleNodeList<>& nodes )
120 {
121 PROFILE_SCOPE_AUTO( Profiler::Category::Scene );
122
123 // We can manually exclude nodes by GUID, so check that
124 if ( params._ignoredGUIDS._count > 0u )
125 {
126 // This is used, for example, by reflective nodes that should exclude themselves (mirrors, water, etc)
127 const I64 nodeGUID = currentNode->getGUID();
128 for ( size_t i = 0u; i < params._ignoredGUIDS._count; ++i )
129 {
130 if ( nodeGUID == params._ignoredGUIDS._guids[i] )
131 {
132 return;
133 }
134 }
135 }
136
137 // Internal node cull (check against camera frustum and all that ...)
138 F32 distanceSqToCamera = 0.0f;
139 const FrustumCollision collisionResult = Attorney::SceneGraphNodeRenderPassCuller::frustumCullNode( currentNode, params, cullFlags, distanceSqToCamera );
140 if ( collisionResult != FrustumCollision::FRUSTUM_OUT )
141 {
142 if ( !currentNode->hasFlag( SceneGraphNode::Flags::IS_CONTAINER ) )
143 {
144 // Only add non-container nodes to the visible list. Otherwise, proceed and check children
145 nodes.append( { currentNode, distanceSqToCamera } );
146 }
147
148 // Parent node intersects the view, so check children
149 if ( collisionResult == FrustumCollision::FRUSTUM_IN )
150 {
151 // If the parent node is all in, we don't need to frustum check the children, but we still
152 // need to grab the distance to each of them
153 cullFlags &= ~to_base(CullOptions::CULL_AGAINST_FRUSTUM);
154 }
155
156 SceneGraphNode::ChildContainer& children = currentNode->getChildren();
157
158 ParallelForDescriptor descriptor = {};
159 descriptor._iterCount = children._count.load();
160
161 if ( descriptor._iterCount > 0u )
162 {
163 SharedLock<SharedMutex> r_lock( children._lock );
164
165 if ( descriptor._iterCount > g_nodesPerCullingPartition * 2 )
166 {
167 descriptor._partitionSize = g_nodesPerCullingPartition;
168 descriptor._priority = recursionLevel < 2 ? TaskPriority::DONT_CARE : TaskPriority::REALTIME;
169 descriptor._useCurrentThread = true;
170 Parallel_For( currentNode->context().taskPool( TaskPoolType::RENDERER ), descriptor, [&]( const Task*, const U32 start, const U32 end )
171 {
172 for ( U32 i = start; i < end; ++i )
173 {
174 FrustumCullNode( children._data[i], params, cullFlags, recursionLevel + 1, nodes );
175 }
176 });
177 }
178 else
179 {
180 for ( U32 i = 0u; i < descriptor._iterCount; ++i )
181 {
182 FrustumCullNode( children._data[i], params, cullFlags, recursionLevel + 1, nodes );
183 };
184 }
185 }
186 }
187 }
188
189 void RenderPassCuller::FrustumCull( const PlatformContext& context, const NodeCullParams& params, const U16 cullFlags, const vector<SceneGraphNode*>& nodes, VisibleNodeList<>& nodesOut )
190 {
191 PROFILE_SCOPE_AUTO( Profiler::Category::Scene );
192
193 nodesOut.reset();
194
195 F32 distanceSqToCamera = F32_MAX;
196 for ( SceneGraphNode* node : nodes )
197 {
198 if ( Attorney::SceneGraphNodeRenderPassCuller::frustumCullNode( node, params, cullFlags, distanceSqToCamera ) != FrustumCollision::FRUSTUM_OUT )
199 {
200 nodesOut.append( { node, distanceSqToCamera } );
201 }
202 }
203
204 PostCullNodes( params, cullFlags, FilterMask( context ), nodesOut );
205 }
206
207 void RenderPassCuller::ToVisibleNodes(const Camera* camera, const vector<SceneGraphNode*>& nodes, VisibleNodeList<>& nodesOut )
208 {
209 PROFILE_SCOPE_AUTO( Profiler::Category::Scene );
210
211 nodesOut.reset();
212
213 const vec3<F32>& cameraEye = camera->snapshot()._eye;
214 for ( SceneGraphNode* node : nodes )
215 {
216 BoundsComponent* bComp = node->get<BoundsComponent>();
217 const F32 distanceSqToCamera = bComp != nullptr ? bComp->getBoundingSphere().getCenter().distanceSquared( cameraEye ) : F32_MAX;
218 nodesOut.append( { node, distanceSqToCamera } );
219 }
220 }
221} //namespace Divide
#define PROFILE_SCOPE_AUTO(CATEGORY)
Definition: Profiler.h:87
#define PROFILE_SCOPE(NAME, CATEGORY)
Definition: Profiler.h:86
static FrustumCollision clippingCullNode(const SceneGraphNode *node, const NodeCullParams &params)
static FrustumCollision stateCullNode(const SceneGraphNode *node, const NodeCullParams &params, const U16 cullFlags, const U32 filterMask, F32 distanceToClosestPointSQ)
const vec3< F32 > & getCenter() const noexcept
const BoundingSphere & getBoundingSphere() const noexcept
const CameraSnapshot & snapshot() const noexcept
Returns the internal camera snapshot data (eye, orientation, etc)
Definition: Camera.inl:43
FORCE_INLINE I64 getGUID() const noexcept
Definition: GUIDWrapper.h:51
PlatformContext & context() noexcept
TaskPool & taskPool(const TaskPoolType type) noexcept
const SceneGraphNode * getRoot() const noexcept
Definition: SceneGraph.h:75
bool hasFlag(const Flags flag) const noexcept
Returns true only if the current node has the specified flag. Does not check children!
ChildContainer & getChildren() noexcept
@ RENDER_WIREFRAME
Render wireframe for all scene geometry.
bool isEnabledOption(RenderOptions option) const noexcept
Definition: SceneState.cpp:74
SceneRenderState & renderState() noexcept
Definition: SceneState.h:226
T distanceSquared(const vec3 &v) const noexcept
compute the vector's squared distance to another specified vector
constexpr Optick::Category::Type Scene
Definition: Profiler.h:66
Handle console commands that start with a forward slash.
Definition: AIProcessor.cpp:7
int32_t I32
uint8_t U8
eastl::vector< Type > vector
Definition: Vector.h:42
std::shared_lock< mutex > SharedLock
Definition: SharedMutex.h:49
constexpr F32 F32_MAX
uint16_t U16
void Parallel_For(TaskPool &pool, const ParallelForDescriptor &descriptor, const DELEGATE< void, const Task *, U32, U32 > &cbk)
Definition: TaskPool.cpp:428
constexpr I32 to_I32(const T value)
int64_t I64
uint32_t U32
constexpr auto to_base(const Type value) -> Type
const std::array< bool, N > & planeState() const noexcept
Definition: ClipPlanes.h:76
FrustumClipPlanes _clippingPlanes
U32 _partitionSize
How many elements should we process per async task.
Definition: TaskPool.h:45
bool _useCurrentThread
If true, we'll process a for partition on the calling thread.
Definition: TaskPool.h:51
TaskPriority _priority
Each async task will start with the same priority specified here.
Definition: TaskPool.h:47
U32 _iterCount
For loop iteration count.
Definition: TaskPool.h:43
static void FrustumCull(const NodeCullParams &params, U16 cullFlags, const SceneGraph &sceneGraph, const SceneState &sceneState, PlatformContext &context, VisibleNodeList<> &nodesOut)
static void PostCullNodes(const NodeCullParams &params, U16 cullFlags, U32 filterMask, VisibleNodeList<> &nodesInOut)
static U32 FilterMask(const PlatformContext &context) noexcept
static void FrustumCullNode(SceneGraphNode *currentNode, const NodeCullParams &params, U16 cullFlags, U8 recursionLevel, VisibleNodeList<> &nodes)
This method performs the visibility check on the given node and all of its children and adds them to ...
eastl::fixed_vector< SceneGraphNode *, 32, true > _data
SceneGraphNode * _node
void remove(const size_t idx)
void append(const VisibleNodeList &other) noexcept
size_t size() const noexcept
const T & node(const size_t idx) const noexcept