/src/ogre/OgreMain/include/OgreInstanceManager.h
Line | Count | Source |
1 | | /* |
2 | | ----------------------------------------------------------------------------- |
3 | | This source file is part of OGRE |
4 | | (Object-oriented Graphics Rendering Engine) |
5 | | For the latest info, see http://www.ogre3d.org/ |
6 | | |
7 | | Copyright (c) 2000-2014 Torus Knot Software Ltd |
8 | | |
9 | | Permission is hereby granted, free of charge, to any person obtaining a copy |
10 | | of this software and associated documentation files (the "Software"), to deal |
11 | | in the Software without restriction, including without limitation the rights |
12 | | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
13 | | copies of the Software, and to permit persons to whom the Software is |
14 | | furnished to do so, subject to the following conditions: |
15 | | |
16 | | The above copyright notice and this permission notice shall be included in |
17 | | all copies or substantial portions of the Software. |
18 | | |
19 | | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
20 | | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
21 | | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
22 | | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
23 | | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
24 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
25 | | THE SOFTWARE. |
26 | | ----------------------------------------------------------------------------- |
27 | | */ |
28 | | #ifndef __InstanceManager_H__ |
29 | | #define __InstanceManager_H__ |
30 | | |
31 | | #include "OgrePrerequisites.h" |
32 | | #include "OgreRenderOperation.h" |
33 | | #include "OgreHeaderPrefix.h" |
34 | | |
35 | | namespace Ogre |
36 | | { |
37 | | /** \addtogroup Core |
38 | | * @{ |
39 | | */ |
40 | | /** \addtogroup Scene |
41 | | * @{ |
42 | | */ |
43 | | |
44 | | /** This is the main starting point for the manual instancing system. |
45 | | |
46 | | Instancing allows to save both memory and draw calls. While |
47 | | StaticGeometry stores 500 times the same object in a batch to display 500 |
48 | | objects, a hardware instancing implementation stores the object once, |
49 | | and then re-uses the vertex data with different shader parameter. |
50 | | You can move the batched objects independently of one another which |
51 | | you cannot do with StaticGeometry. |
52 | | |
53 | | Each InstanceManager can control one technique and one mesh, but it can manage |
54 | | multiple materials at the same time. |
55 | | @ref SceneManager::createInstanceManager, which creates this InstanceManager. Each one |
56 | | must have a unique name. It's wasteless to create two InstanceManagers with the same |
57 | | mesh reference, instancing technique and instances per batch count. |
58 | | This class takes care of managing batches automatically, so that more are created when |
59 | | needed, and reuse existing ones as much as possible; thus the user doesn't have to worry |
60 | | of managing all those low level issues. |
61 | | |
62 | | @see @ref InstanceBatch |
63 | | @see @ref InstancedEntity |
64 | | @see Design discussion thread: http://www.ogre3d.org/forums/viewtopic.php?f=4&t=59902 |
65 | | */ |
66 | | class _OgreExport InstanceManager : public FactoryAlloc |
67 | | { |
68 | | public: |
69 | | enum InstancingTechnique |
70 | | { |
71 | | ShaderBased, ///< %Any SM 2.0+ @ref InstanceBatchShader |
72 | | TextureVTF, ///< Needs Vertex Texture Fetch & SM 3.0+ @ref InstanceBatchVTF |
73 | | HWInstancingBasic, ///< Needs SM 3.0+ and HW instancing support @ref InstanceBatchHW |
74 | | HWInstancingVTF, ///< Needs SM 3.0+, HW instancing support & VTF @ref InstanceBatchHW_VTF |
75 | | InstancingTechniquesCount |
76 | | }; |
77 | | |
78 | | /** Values to be used in setSetting() & BatchSettings::setting */ |
79 | | enum BatchSettingId |
80 | | { |
81 | | /// Makes all batches from same material cast shadows |
82 | | CAST_SHADOWS = 0, |
83 | | /// Makes each batch to display it's bounding box. Useful for debugging or profiling |
84 | | SHOW_BOUNDINGBOX, |
85 | | |
86 | | NUM_SETTINGS |
87 | | }; |
88 | | |
89 | | private: |
90 | | struct BatchSettings |
91 | | { |
92 | | //These are all per material |
93 | | bool setting[NUM_SETTINGS]; |
94 | | |
95 | | BatchSettings() |
96 | 0 | { |
97 | 0 | setting[CAST_SHADOWS] = true; |
98 | 0 | setting[SHOW_BOUNDINGBOX] = false; |
99 | 0 | } |
100 | | }; |
101 | | |
102 | | typedef std::vector<InstanceBatch*> InstanceBatchVec; //vec[batchN] = Batch |
103 | | typedef std::map<String, InstanceBatchVec> InstanceBatchMap; //map[materialName] = Vec |
104 | | |
105 | | typedef std::map<String, BatchSettings> BatchSettingsMap; |
106 | | |
107 | | const String mName; //Not the name of the mesh |
108 | | MeshPtr mMeshReference; |
109 | | InstanceBatchMap mInstanceBatches; |
110 | | size_t mIdCount; |
111 | | |
112 | | InstanceBatchVec mDirtyBatches; |
113 | | |
114 | | RenderOperation mSharedRenderOperation; |
115 | | |
116 | | size_t mInstancesPerBatch; |
117 | | InstancingTechnique mInstancingTechnique; |
118 | | uint16 mInstancingFlags; ///< @see InstanceManagerFlags |
119 | | unsigned short mSubMeshIdx; |
120 | | |
121 | | BatchSettingsMap mBatchSettings; |
122 | | SceneManager* mSceneManager; |
123 | | |
124 | | size_t mMaxLookupTableInstances; |
125 | | unsigned char mNumCustomParams; //Number of custom params per instance. |
126 | | |
127 | | /** Finds a batch with at least one free instanced entity we can use. |
128 | | If none found, creates one. |
129 | | */ |
130 | | inline InstanceBatch* getFreeBatch( const String &materialName ); |
131 | | |
132 | | /** Called when batches are fully exhausted (can't return more instances) so a new batch |
133 | | is created. |
134 | | For the first time use, it can take big build time. |
135 | | It takes care of getting the render operation which will be shared by further batches, |
136 | | which decreases their build time, and prevents GPU RAM from skyrocketing. |
137 | | @param materialName The material name, to know where to put this batch in the map |
138 | | @param firstTime True if this is the first time it is called |
139 | | @return The created InstancedManager for convenience |
140 | | */ |
141 | | InstanceBatch* buildNewBatch( const String &materialName, bool firstTime ); |
142 | | |
143 | | /** @see defragmentBatches overload, this takes care of an array of batches |
144 | | for a specific material */ |
145 | | void defragmentBatches( bool optimizeCull, std::vector<InstancedEntity*> &entities, |
146 | | std::vector<Ogre::Vector4f> &usedParams, |
147 | | InstanceBatchVec &fragmentedBatches ); |
148 | | |
149 | | /** @see setSetting. This function helps it by setting the given parameter to all batches |
150 | | in container. |
151 | | */ |
152 | | void applySettingToBatches( BatchSettingId id, bool value, const InstanceBatchVec &container ); |
153 | | |
154 | | /** Called when we you use a mesh which has shared vertices, the function creates separate |
155 | | vertex/index buffers and also recreates the bone assignments. |
156 | | */ |
157 | | static void unshareVertices(const Ogre::MeshPtr &mesh); |
158 | | |
159 | | public: |
160 | | InstanceManager( const String &customName, SceneManager *sceneManager, |
161 | | const String &meshName, const String &groupName, |
162 | | InstancingTechnique instancingTechnique, uint16 instancingFlags, |
163 | | size_t instancesPerBatch, unsigned short subMeshIdx, bool useBoneMatrixLookup = false); |
164 | | ~InstanceManager(); |
165 | | |
166 | 0 | const String& getName() const { return mName; } |
167 | | |
168 | 0 | SceneManager* getSceneManager() const { return mSceneManager; } |
169 | | |
170 | | /** Raises an exception if trying to change it after creating the first InstancedEntity |
171 | | The actual value may be less if the technique doesn't support having so much. |
172 | | See @ref getMaxOrBestNumInstancesPerBatch for the usefulness of this function |
173 | | @param instancesPerBatch New instances per batch number |
174 | | */ |
175 | | void setInstancesPerBatch( size_t instancesPerBatch ); |
176 | | |
177 | | /** Sets the size of the lookup table for techniques supporting bone lookup table. |
178 | | Raises an exception if trying to change it after creating the first InstancedEntity. |
179 | | Setting this value below the number of unique (non-sharing) entity instance animations |
180 | | will produce a crash during runtime. Setting this value above will increase memory |
181 | | consumption and reduce framerate. |
182 | | @remarks The value should be as close but not below the actual value. |
183 | | @param maxLookupTableInstances New size of the lookup table |
184 | | */ |
185 | | void setMaxLookupTableInstances( size_t maxLookupTableInstances ); |
186 | | |
187 | | /** Sets the number of custom parameters per instance. Some techniques (i.e. HWInstancingBasic) |
188 | | support this, but not all of them. They also may have limitations to the max number. All |
189 | | instancing implementations assume each instance param is a Vector4 (4 floats). |
190 | | |
191 | | This function cannot be called after the first batch has been created. Otherwise |
192 | | it will raise an exception. If the technique doesn't support custom params, it will |
193 | | raise an exception at the time of building the first InstanceBatch. |
194 | | |
195 | | HWInstancingBasic: |
196 | | * Each custom params adds an additional float4 TEXCOORD. |
197 | | HWInstancingVTF: |
198 | | * Not implemented. (Recommendation: Implement this as an additional float4 VTF fetch) |
199 | | TextureVTF: |
200 | | * Not implemented. (see HWInstancingVTF's recommendation) |
201 | | ShaderBased: |
202 | | * Not supported. |
203 | | @param numCustomParams Number of custom parameters each instance will have. Default: 0 |
204 | | */ |
205 | | void setNumCustomParams( unsigned char numCustomParams ); |
206 | | |
207 | | unsigned char getNumCustomParams() const |
208 | 0 | { return mNumCustomParams; } |
209 | | |
210 | | /** @return Instancing technique this manager was created for. Can't be changed after creation */ |
211 | | InstancingTechnique getInstancingTechnique() const |
212 | 0 | { return mInstancingTechnique; } |
213 | | |
214 | | /** Calculates the maximum (or the best amount, depending on flags) of instances |
215 | | per batch given the suggested size for the technique this manager was created for. |
216 | | |
217 | | This is done automatically when creating an instanced entity, but this function in conjunction |
218 | | with @ref setInstancesPerBatch allows more flexible control over the amount of instances |
219 | | per batch |
220 | | @param materialName Name of the material to base on |
221 | | @param suggestedSize Suggested amount of instances per batch |
222 | | @param flags @ref InstanceManagerFlags to pass to the InstanceManager |
223 | | @return The max/best amount of instances per batch given the suggested size and flags |
224 | | */ |
225 | | size_t getMaxOrBestNumInstancesPerBatch( const String &materialName, size_t suggestedSize, uint16 flags ); |
226 | | |
227 | | /// Creates an InstancedEntity |
228 | | InstancedEntity* createInstancedEntity( const String &materialName ); |
229 | | |
230 | | /** This function can be useful to improve CPU speed after having too many instances |
231 | | created, which where now removed, thus freeing many batches with zero used Instanced Entities |
232 | | However the batches aren't automatically removed from memory until the InstanceManager is |
233 | | destroyed, or this function is called. This function removes those batches which are completely |
234 | | unused (only wasting memory). |
235 | | */ |
236 | | void cleanupEmptyBatches(void); |
237 | | |
238 | | /** After creating many entities (which turns in many batches) and then removing entities that |
239 | | are in the middle of these batches, there might be many batches with many free entities. |
240 | | Worst case scenario, there could be left one batch per entity. Imagine there can be |
241 | | 80 entities per batch, there are 80 batches, making a total of 6400 entities. Then |
242 | | 6320 of those entities are removed in a very specific way, which leads to having |
243 | | 80 batches, 80 entities, and GPU vertex shader still needs to process 6400! |
244 | | This is called fragmentation. This function reparents the InstancedEntities |
245 | | to fewer batches, in this case leaving only one batch with 80 entities |
246 | | |
247 | | |
248 | | @note This function takes time. Make sure to call this only when you're sure there's |
249 | | too much of fragmentation and you won't be creating more InstancedEntities soon |
250 | | Also in many cases cleanupEmptyBatches() ought to be enough |
251 | | Defragmentation is done per material |
252 | | Static batches won't be defragmented. If you want to degragment them, set them |
253 | | to dynamic again, and switch back to static after calling this function. |
254 | | |
255 | | @param optimizeCulling When true, entities close together will be reorganized |
256 | | in the same batch for more efficient CPU culling. This can take more CPU |
257 | | time. You want this to be false if you now you're entities are moving very |
258 | | randomly which tends them to get separated and spread all over the scene |
259 | | (which nullifies any CPU culling) |
260 | | */ |
261 | | void defragmentBatches( bool optimizeCulling ); |
262 | | |
263 | | /** Applies a setting for all batches using the same material |
264 | | |
265 | | If the material name hasn't been used, the settings are still stored |
266 | | This allows setting up batches before they get even created. |
267 | | @par Examples |
268 | | `setSetting(InstanceManager::CAST_SHADOWS, false, "")` disables shadow |
269 | | casting for all instanced entities (see @ref MovableObject::setCastShadows) |
270 | | @par |
271 | | `setSetting(InstanceManager::SHOW_BOUNDINGBOX, true, "MyMat")` |
272 | | will display the bounding box of the batch (not individual InstancedEntities) |
273 | | from all batches using material "MyMat" |
274 | | @param id @ref BatchSettingId to setup |
275 | | @param enabled Boolean value. It's meaning depends on the id. |
276 | | @param materialName When Blank, the setting is applied to all existing materials |
277 | | */ |
278 | | void setSetting( BatchSettingId id, bool enabled, const String &materialName = BLANKSTRING ); |
279 | | |
280 | | /// If settings for the given material didn't exist, default value is returned |
281 | | bool getSetting( BatchSettingId id, const String &materialName ) const; |
282 | | |
283 | | /** Returns true if settings were already created for the given material name. |
284 | | If false is returned, it means getSetting will return default settings. |
285 | | */ |
286 | | bool hasSettings( const String &materialName ) const; |
287 | | |
288 | | /** @copydoc InstanceBatch::setStaticAndUpdate */ |
289 | | void setBatchesAsStaticAndUpdate( bool bStatic ); |
290 | | |
291 | | /** Called by an InstanceBatch when it requests their bounds to be updated for proper culling |
292 | | @param dirtyBatch The batch which is dirty, usually same as caller. |
293 | | */ |
294 | | void _addDirtyBatch( InstanceBatch *dirtyBatch ); |
295 | | |
296 | | /** Called by SceneManager when we told it we have at least one dirty batch */ |
297 | | void _updateDirtyBatches(void); |
298 | | |
299 | | typedef ConstMapIterator<InstanceBatchMap> InstanceBatchMapIterator; |
300 | | typedef ConstVectorIterator<InstanceBatchVec> InstanceBatchIterator; |
301 | | |
302 | | /// Get non-updateable iterator over instance batches per material |
303 | | InstanceBatchMapIterator getInstanceBatchMapIterator(void) const |
304 | 0 | { return InstanceBatchMapIterator( mInstanceBatches.begin(), mInstanceBatches.end() ); } |
305 | | |
306 | | /** Get non-updateable iterator over instance batches for given material |
307 | | |
308 | | Each InstanceBatch pointer may be modified for low level usage (i.e. |
309 | | setCustomParameter), but there's no synchronization mechanism when |
310 | | multithreading or creating more instances, that's up to the user. |
311 | | */ |
312 | | InstanceBatchIterator getInstanceBatchIterator( const String &materialName ) const; |
313 | | }; |
314 | | } // namespace Ogre |
315 | | |
316 | | #include "OgreHeaderSuffix.h" |
317 | | |
318 | | #endif // __InstanceManager_H__ |