-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathEveryCulling.h
293 lines (246 loc) · 9.64 KB
/
EveryCulling.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
#pragma once
#include "EveryCullingCore.h"
#include "DataType/EntityGridCell.h"
#include "DataType/EntityBlockViewer.h"
#ifdef PROFILING_CULLING
#include "EveryCullingProfiler.h"
#endif
#include <array>
#include <vector>
#include <atomic>
#include <thread>
namespace culling
{
class CullingModule;
class ViewFrustumCulling;
class ScreenSpaceBoundingSphereCulling;
class MaskedSWOcclusionCulling;
class QueryOcclusionCulling;
class PreCulling;
class DistanceCulling;
struct EntityBlock;
struct EntityInfoInEntityBlock
{
EntityBlock* mEntityBlock;
size_t mIndexInEntityBlock;
};
/// <summary>
///
/// This is implementation of Data Oriented ViewFrustumCulling of Frostbite in 2011
///
/// [Slide Resource](https://www.ea.com/frostbite/news/culling-the-battlefield-data-oriented-design-in-practice)
/// [GDC Talk Video](https://www.gdcvault.com/play/1014491/Culling-the-Battlefield-Data-Oriented)
/// [�ѱ��� ���α� ��] (https ://sungjjinkang.github.io/doom/2021/04/02/viewfrustumculling.html)
///
///
/// This culling use SIMD DotProduct, So Check LightMath_Cpp/Mat4x4Float_Aligned.inl
///
/// Feature :
/// 1. Linear arrays scale great. All entity's position data is stored linearlly.
/// 2. Tree based sturucture or other Acceleration strucutures isn;t required
/// 3. Frustum vs Sphere intersections check per loop
/// 3. Threads solve intersections(blocks) parrallily
///
/// this library require math library : https://github.com/SungJJinKang/LightMath_Cpp/blob/main/Mat4x4Float_Aligned.inl
///
/// references :
/// https://www.gdcvault.com/play/1014491/Culling-the-Battlefield-Data-Oriented
/// https://www.slideshare.net/DICEStudio/culling-the-battlefield-data-oriented-design-in-practice
/// https://macton.smugmug.com/Other/2008-07-15-by-Eye-Fi/n-xmKDH/
///
/// </summary>
class EveryCulling
{
private:
size_t mThreadCount;
size_t mCameraCount;
std::array<culling::Mat4x4, MAX_CAMERA_COUNT> mCameraModelMatrixes;
std::array<culling::Mat4x4, MAX_CAMERA_COUNT> mCameraViewProjectionMatrixes;
std::array<culling::Vec3, MAX_CAMERA_COUNT> mCameraWorldPositions;
std::array<culling::Vec4, MAX_CAMERA_COUNT> mCameraRotations;
std::array<float, MAX_CAMERA_COUNT> mCameraFieldOfView;
std::array<float, MAX_CAMERA_COUNT> mFarClipPlaneDistance;
std::array<float, MAX_CAMERA_COUNT> mNearClipPlaneDistance;
bool bmIsEntityBlockPoolInitialized{ false };
/// <summary>
/// List of EntityBlock with no entity ( maybe entity was destroyed)
/// </summary>
std::vector<EntityBlock*> mFreeEntityBlockList{};
/// <summary>
/// List of EntityBlock containing Entities
/// </summary>
std::vector<EntityBlock*> mActiveEntityBlockList{};
/// <summary>
/// Allocated EntityBlock Arrays
/// This objects will be released at destructor
/// </summary>
std::vector<EntityBlock*> mAllocatedEntityBlockChunkList{};
void AllocateEntityBlockPool();
culling::EntityBlock* AllocateNewEntityBlockFromPool();
void RemoveEntityFromBlock(EntityBlock* ownerEntityBlock, std::uint32_t entityIndexInBlock);
/// <summary>
/// Block Swap removedblock with last block, and return swapped lastblock to pool
/// </summary>
void FreeEntityBlock(EntityBlock* freedEntityBlock);
EntityBlock* GetNewEntityBlockFromPool();
void ResetCullingModules();
/// <summary>
/// Reset VisibleFlag
/// </summary>
void ResetEntityBlocks();
public:
std::unique_ptr<PreCulling> mPreCulling;
std::unique_ptr<DistanceCulling> mDistanceCulling;
std::unique_ptr<ViewFrustumCulling> mViewFrustumCulling;
#ifdef ENABLE_SCREEN_SAPCE_BOUDING_SPHERE_CULLING
std::unique_ptr<ScreenSpaceBoundingSphereCulling> mScreenSpaceBoudingSphereCulling;
#endif
std::unique_ptr<MaskedSWOcclusionCulling> mMaskedSWOcclusionCulling;
#ifdef ENABLE_QUERY_OCCLUSION
std::unique_ptr<QueryOcclusionCulling> mQueryOcclusionCulling;
#endif
#ifdef PROFILING_CULLING
EveryCullingProfiler mEveryCullingProfiler;
#endif
private:
size_t mSortedEntityCount;
std::array<std::vector<EntityInfoInEntityBlock>, MAX_CAMERA_COUNT> mSortedEntityInfo;
std::vector<culling::CullingModule*> mUpdatedCullingModules;
// this function is called by multiple threads
FORCE_INLINE void OnStartCullingModule(const culling::CullingModule* const cullingModule);
// this function is called by multiple threads
FORCE_INLINE void OnEndCullingModule(const culling::CullingModule* const cullingModule);
void SetViewProjectionMatrix(const size_t cameraIndex, const culling::Mat4x4& viewProjectionMatrix);
void SetFieldOfViewInDegree(const size_t cameraIndex, const float fov);
void SetCameraNearFarClipPlaneDistance(const size_t cameraIndex, const float nearPlaneDistance, const float farPlaneDistance);;
void SetCameraWorldPosition(const size_t cameraIndex, const culling::Vec3& cameraWorldPos);
void SetCameraRotation(const size_t cameraIndex, const culling::Vec4& cameraRotation);
public:
enum class CullingModuleType
{
_ViewFrustumCulling,
_MaskedSWOcclusionCulling,
_HwQueryOcclusionCulling,
_DistanceCulling
};
EveryCulling() = delete;
EveryCulling(const std::uint32_t resolutionWidth, const std::uint32_t resolutionHeight);
EveryCulling(const EveryCulling&) = delete;
EveryCulling(EveryCulling&&) noexcept = delete;
EveryCulling& operator=(const EveryCulling&) = delete;
EveryCulling& operator=(EveryCulling&&) noexcept = delete;
~EveryCulling();
void SetCameraCount(const size_t cameraCount);
void SetThreadCount(const size_t threadCount);
struct SettingParameters
{
culling::Mat4x4 mViewProjectionMatrix;
float mFieldOfViewInDegree;
float mCameraNearPlaneDistance;
float mCameraFarPlaneDistance;
culling::Vec3 mCameraWorldPosition;
culling::Vec4 mCameraRotation;
};
void Configure(const size_t cameraIndex, const SettingParameters& settingParameters);
FORCE_INLINE size_t GetCameraCount() const
{
return mCameraCount;
}
FORCE_INLINE const culling::Vec3& GetCameraWorldPosition(const size_t cameraIndex) const
{
assert(cameraIndex >= 0 && cameraIndex < MAX_CAMERA_COUNT);
return mCameraWorldPositions[cameraIndex];
}
FORCE_INLINE const culling::Mat4x4& GetCameraModelMatrix(const size_t cameraIndex) const
{
assert(cameraIndex >= 0 && cameraIndex < MAX_CAMERA_COUNT);
return mCameraModelMatrixes[cameraIndex];
}
FORCE_INLINE const culling::Mat4x4& GetCameraViewProjectionMatrix(const size_t cameraIndex) const
{
assert(cameraIndex >= 0 && cameraIndex < MAX_CAMERA_COUNT);
return mCameraViewProjectionMatrixes[cameraIndex];
}
FORCE_INLINE float GetCameraFieldOfView(const size_t cameraIndex) const
{
assert(cameraIndex >= 0 && cameraIndex < MAX_CAMERA_COUNT);
return mCameraFieldOfView[cameraIndex];
}
FORCE_INLINE float GetCameraFarClipPlaneDistance(const size_t cameraIndex) const
{
assert(cameraIndex >= 0 && cameraIndex < MAX_CAMERA_COUNT);
return mFarClipPlaneDistance[cameraIndex];
}
FORCE_INLINE float GetCameraNearClipPlaneDistance(const size_t cameraIndex) const
{
assert(cameraIndex >= 0 && cameraIndex < MAX_CAMERA_COUNT);
return mNearClipPlaneDistance[cameraIndex];
}
/// <summary>
/// Get EntityBlock List with entities
/// </summary>
/// <returns></returns>
const std::vector<EntityBlock*>& GetActiveEntityBlockList() const;
size_t GetActiveEntityBlockCount() const;
/// <summary>
/// You should call this function on your Transform Component or In your game engine
///
/// increment EntityCountInBlock of TargetBlock.
/// If All blocks is full, Get new block from Block Pool
///
/// Allocating New Entity isn't thread safe
/// </summary>
EntityBlockViewer AllocateNewEntity();
/// <summary>
/// You should call this function on your Transform Component or In your game engine
///
/// Remove Entity is nothing, Just decrement AllocatedEntityCountInBlocks
/// And if AllocatedEntityCountInBlocks Of Block become zero, Remove the block using RemoveBlock function
///
/// Removing Entity isn't thread safe
/// </summary>
void RemoveEntityFromBlock(EntityBlockViewer& entityBlockViewer);
void CullBlockEntityJob(const size_t cameraIndex);
//void CullBlockEntityJob(const std::uint32_t threadIndex, const std::uint32_t threadCount);
/// <summary>
/// Caller thread will stall until cull job of all entity block is finished
/// </summary>
void WaitToFinishCullJob(const std::uint32_t cameraIndex) const;
void WaitToFinishCullJobOfAllCameras() const;
/// <summary>
/// Reset cull job state before pushing cull jobs to job pool
/// </summary>
void ResetCullJobState();
constexpr auto GetCullJobInLambda(const size_t cameraIndex)
{
return [this, cameraIndex]()
{
this->CullBlockEntityJob(cameraIndex);
};
}
const culling::CullingModule* GetLastEnabledCullingModule() const;
void SetEnabledCullingModule(const CullingModuleType cullingModuleType, const bool isEnabled);
void ResetSortedEntityCount();
FORCE_INLINE void SetSortedEntityInfo
(
const size_t cameraIndex,
const size_t objectOrder,
EntityBlock* const entityBlock,
const size_t IndexInEntityBlock
)
{
if (mSortedEntityInfo[cameraIndex].size() <= objectOrder)
{
mSortedEntityInfo[cameraIndex].resize(MAX(objectOrder + 1, (mSortedEntityInfo[cameraIndex].size() * 2) - 1));
}
mSortedEntityInfo[cameraIndex][objectOrder].mEntityBlock = entityBlock;
mSortedEntityInfo[cameraIndex][objectOrder].mIndexInEntityBlock = IndexInEntityBlock;
mSortedEntityCount = MAX(mSortedEntityCount, objectOrder + 1);
}
FORCE_INLINE size_t GetSortedEntityCount() const
{
return mSortedEntityCount;
}
std::vector<EntityInfoInEntityBlock>& GetSortedEntityInfo(const size_t cameraIndex);
};
}