/src/ogre/OgreMain/include/OgreInstanceBatch.h
Line | Count | Source (jump to first uncovered line) |
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 __InstanceBatch_H__ |
29 | | #define __InstanceBatch_H__ |
30 | | |
31 | | #include "OgrePrerequisites.h" |
32 | | #include "OgreRenderOperation.h" |
33 | | #include "OgreRenderable.h" |
34 | | #include "OgreMovableObject.h" |
35 | | #include "OgreMesh.h" |
36 | | #include "OgreHeaderPrefix.h" |
37 | | |
38 | | namespace Ogre |
39 | | { |
40 | | /** \addtogroup Core |
41 | | * @{ |
42 | | */ |
43 | | /** \addtogroup Scene |
44 | | * @{ |
45 | | */ |
46 | | |
47 | | /** InstanceBatch forms part of the new Instancing system |
48 | | This is an abstract class that must be derived to implement different instancing techniques |
49 | | (@ref InstanceManager::InstancingTechnique) |
50 | | OGRE wasn't truly thought for instancing. OGRE assumes that either: |
51 | | 1. One MovableObject -> No Renderable |
52 | | 2. One MovableObject -> One Renderable |
53 | | 3. One MovableObject -> Many Renderable. |
54 | | |
55 | | However, instances work on reverse: Many MovableObject have the same Renderable. |
56 | | <b>Instancing is already difficult to cull by a CPU</b>, but the main drawback from this assumption |
57 | | is that it makes it even harder to take advantage from OGRE's culling capabilities |
58 | | (i.e. @ref OctreeSceneManager) |
59 | | @par |
60 | | To workaround this problem, InstanceBatch updates on almost every frame, |
61 | | growing the bounding box to fit all instances that are not being culled individually. |
62 | | This helps by avoiding a huge bbox that may cover the whole scene, which decreases shadow |
63 | | quality considerably (as it is seen as large shadow receiver) |
64 | | Furthermore, if no individual instance is visible, the InstanceBatch switches it's visibility |
65 | | (@ref MovableObject::setVisible) to avoid sending this Renderable to the GPU. This happens because |
66 | | even when no individual instance is visible, their merged bounding box may cause OGRE to think |
67 | | the batch is visible (i.e. the camera is looking between object A & B, but A & B aren't visible) |
68 | | @par |
69 | | <b>As it happens with instancing in general, all instanced entities from the same batch will share |
70 | | the same textures and materials</b> |
71 | | @par |
72 | | Each InstanceBatch preallocates a fixed amount of mInstancesPerBatch instances once it's been |
73 | | built (@ref build, @ref buildFrom). |
74 | | @ref createInstancedEntity and @ref removeInstancedEntity on how to retrieve those instances |
75 | | remove them from scene. |
76 | | Note that, on GPU side, removing an instance from scene doesn't save GPU cycles on what |
77 | | respects vertex shaders, but saves a little fillrate and pixel shaders; unless all instances |
78 | | are removed, which saves GPU. |
79 | | For more information, @ref InstancedEntity |
80 | | For information on how Ogre manages multiple Instance batches, @ref InstanceManager |
81 | | |
82 | | @author |
83 | | Matias N. Goldberg ("dark_sylinc") |
84 | | */ |
85 | | class _OgreExport InstanceBatch : public Renderable, public MovableObject |
86 | | { |
87 | | public: |
88 | | typedef std::vector<InstancedEntity*> InstancedEntityVec; |
89 | | typedef std::vector<Vector4f> CustomParamsVec; |
90 | | protected: |
91 | | typedef TransformBase<3, float> Matrix3x4f; |
92 | | RenderOperation mRenderOperation; |
93 | | size_t mInstancesPerBatch; |
94 | | |
95 | | InstanceManager *mCreator; |
96 | | |
97 | | MaterialPtr mMaterial; |
98 | | |
99 | | MeshPtr mMeshReference; |
100 | | Mesh::IndexMap const *mIndexToBoneMap; |
101 | | |
102 | | //InstancedEntities are all allocated at build time and kept as "unused" |
103 | | //when they're requested, they're removed from there when requested, |
104 | | //and put back again when they're no longer needed |
105 | | //Note each InstancedEntity has a unique ID ranging from [0; mInstancesPerBatch) |
106 | | InstancedEntityVec mInstancedEntities; |
107 | | InstancedEntityVec mUnusedEntities; |
108 | | |
109 | | ///@see InstanceManager::setNumCustomParams(). Because this may not even be used, |
110 | | ///our implementations keep the params separate from the InstancedEntity to lower |
111 | | ///the memory overhead. They default to Vector4::ZERO |
112 | | CustomParamsVec mCustomParams; |
113 | | |
114 | | /// This bbox contains all (visible) instanced entities |
115 | | AxisAlignedBox mFullBoundingBox; |
116 | | Real mBoundingRadius; |
117 | | bool mBoundsDirty; |
118 | | bool mBoundsUpdated; //Set to false by derived classes that need it |
119 | | Camera *mCurrentCamera; |
120 | | |
121 | | bool mDirtyAnimation; //Set to false at start of each _updateRenderQueue |
122 | | |
123 | | /// False if a technique doesn't support skeletal animation |
124 | | bool mTechnSupportsSkeletal; |
125 | | |
126 | | /// Last update camera distance frame number |
127 | | mutable unsigned long mCameraDistLastUpdateFrameNumber; |
128 | | /// Cached distance to last camera for getSquaredViewDepth |
129 | | mutable Real mCachedCameraDist; |
130 | | /// The camera for which the cached distance is valid |
131 | | mutable const Camera *mCachedCamera; |
132 | | |
133 | | /// Tells that the list of entity instances with shared transforms has changed |
134 | | bool mTransformSharingDirty; |
135 | | |
136 | | /// When true remove the memory of the VertexData we've created because no one else will |
137 | | bool mRemoveOwnVertexData; |
138 | | /// When true remove the memory of the IndexData we've created because no one else will |
139 | | bool mRemoveOwnIndexData; |
140 | | |
141 | | virtual void setupVertices( const SubMesh* baseSubMesh ) = 0; |
142 | | virtual void setupIndices( const SubMesh* baseSubMesh ) = 0; |
143 | | virtual void createAllInstancedEntities(void); |
144 | | void deleteAllInstancedEntities(void); |
145 | | virtual void deleteUnusedInstancedEntities(void); |
146 | | /// Creates a new InstancedEntity instance |
147 | | virtual InstancedEntity* generateInstancedEntity(size_t num); |
148 | | |
149 | | /** Takes an array of 3x4 matrices and makes it camera relative. Note the second argument |
150 | | takes number of floats in the array, not number of matrices. Assumes mCachedCamera |
151 | | contains the camera which is about to be rendered to. |
152 | | */ |
153 | | void makeMatrixCameraRelative3x4( Matrix3x4f *mat3x4, size_t count ); |
154 | | |
155 | | /// Returns false on errors that would prevent building this batch from the given submesh |
156 | | virtual bool checkSubMeshCompatibility( const SubMesh* baseSubMesh ); |
157 | | |
158 | | void updateVisibility(void); |
159 | | |
160 | | /** @see _defragmentBatch */ |
161 | | void defragmentBatchNoCull( InstancedEntityVec &usedEntities, CustomParamsVec &usedParams ); |
162 | | |
163 | | /** @see _defragmentBatch |
164 | | This one takes the entity closest to the minimum corner of the bbox, then starts |
165 | | gathering entities closest to this entity. There might be much better algorithms (i.e. |
166 | | involving space partition), but this one is simple and works well enough |
167 | | */ |
168 | | void defragmentBatchDoCull( InstancedEntityVec &usedEntities, CustomParamsVec &usedParams ); |
169 | | |
170 | | public: |
171 | | InstanceBatch( InstanceManager *creator, MeshPtr &meshReference, const MaterialPtr &material, |
172 | | size_t instancesPerBatch, const Mesh::IndexMap *indexToBoneMap, |
173 | | const String &batchName ); |
174 | | virtual ~InstanceBatch(); |
175 | | |
176 | 0 | MeshPtr& _getMeshRef() { return mMeshReference; } |
177 | | |
178 | | /** Raises an exception if trying to change it after being built |
179 | | */ |
180 | | void _setInstancesPerBatch( size_t instancesPerBatch ); |
181 | | |
182 | 0 | const Mesh::IndexMap* _getIndexToBoneMap() const { return mIndexToBoneMap; } |
183 | | |
184 | | /** Returns true if this technique supports skeletal animation |
185 | | |
186 | | A virtual function could have been used, but using a simple variable overridden |
187 | | by the derived class is faster than virtual call overhead. And both are clean |
188 | | ways of implementing it. |
189 | | */ |
190 | 0 | bool _supportsSkeletalAnimation() const { return mTechnSupportsSkeletal; } |
191 | | |
192 | | /** @see InstanceManager::updateDirtyBatches */ |
193 | | void _updateBounds(void); |
194 | | |
195 | | /** Some techniques have a limit on how many instances can be done. |
196 | | Sometimes even depends on the material being used. |
197 | | @par |
198 | | Note this is a helper function, as such it takes a submesh base to compute |
199 | | the parameters, instead of using the object's own. This allows |
200 | | querying for a technique without requiring to actually build it. |
201 | | @param baseSubMesh The base submesh that will be using to build it. |
202 | | @param flags Flags to pass to the InstanceManager. @see InstanceManagerFlags |
203 | | @return The max instances limit |
204 | | */ |
205 | | virtual size_t calculateMaxNumInstances( const SubMesh *baseSubMesh, uint16 flags ) const = 0; |
206 | | |
207 | | /** Constructs all the data needed to use this batch, as well as the |
208 | | InstanceEntities. Placed here because in the constructor virtual |
209 | | tables may not have been yet filled. |
210 | | |
211 | | @note Call this only ONCE. This is done automatically by Ogre::InstanceManager |
212 | | Caller is responsible for freeing buffers in this RenderOperation |
213 | | Buffers inside the RenderOp may be null if the built failed. |
214 | | @param baseSubMesh A sub mesh which the instances will be based upon from |
215 | | @return |
216 | | A render operation which is very useful to pass to other InstanceBatches |
217 | | (see buildFrom()) so that they share the same vertex buffers and indices, |
218 | | when possible |
219 | | */ |
220 | | virtual RenderOperation build( const SubMesh* baseSubMesh ); |
221 | | |
222 | | /** Instancing consumes significantly more GPU memory than regular rendering |
223 | | methods. However, multiple batches can share most, if not all, of the |
224 | | vertex & index buffers to save memory. |
225 | | Derived classes are free to overload this method to manipulate what to |
226 | | reference from Render Op. |
227 | | For example, Hardware based instancing uses it's own vertex buffer for the |
228 | | last source binding, but shares the other sources. |
229 | | @param baseSubMesh A sub mesh which the instances will be based upon from |
230 | | @param renderOperation The RenderOp to reference. |
231 | | |
232 | | @note Caller is responsible for freeing buffers passed as input arguments |
233 | | This function replaces the need to call build() |
234 | | */ |
235 | | virtual void buildFrom( const SubMesh *baseSubMesh, const RenderOperation &renderOperation ); |
236 | | |
237 | 0 | const Ogre::MeshPtr& _getMeshReference(void) const { return mMeshReference; } |
238 | | |
239 | | /** @return true if it can not create more InstancedEntities |
240 | | (Num InstancedEntities == mInstancesPerBatch) |
241 | | */ |
242 | 0 | bool isBatchFull(void) const { return mUnusedEntities.empty(); } |
243 | | |
244 | | /** Returns true if it no instanced entity has been requested or all of them have been removed |
245 | | */ |
246 | 0 | bool isBatchUnused(void) const { return mUnusedEntities.size() == mInstancedEntities.size(); } |
247 | | |
248 | | /** Fills the input vector with the instances that are currently being used or were requested. |
249 | | Used for defragmentation, @see InstanceManager::defragmentBatches |
250 | | */ |
251 | | void getInstancedEntitiesInUse( InstancedEntityVec &outEntities, CustomParamsVec &outParams ); |
252 | | |
253 | | /** @see InstanceManager::defragmentBatches |
254 | | This function takes InstancedEntities and pushes back all entities it can fit here |
255 | | Extra entities in mUnusedEntities are destroyed |
256 | | (so that used + unused = mInstancedEntities.size()) |
257 | | @param optimizeCulling true will call the DoCull version, false the NoCull |
258 | | @param usedEntities Array of InstancedEntities to parent with this batch. Those reparented |
259 | | are removed from this input vector |
260 | | @param usedParams Array of Custom parameters correlated with the InstancedEntities in usedEntities. |
261 | | They follow the fate of the entities in that vector. |
262 | | @remarks: |
263 | | This function assumes caller holds data to mInstancedEntities! Otherwise |
264 | | you can get memory leaks. Don't call this directly if you don't know what you're doing! |
265 | | */ |
266 | | void _defragmentBatch( bool optimizeCulling, InstancedEntityVec &usedEntities, |
267 | | CustomParamsVec &usedParams ); |
268 | | |
269 | | /** @see InstanceManager::_defragmentBatchDiscard |
270 | | Destroys unused entities and clears the mInstancedEntity container which avoids leaving |
271 | | dangling pointers from reparented InstancedEntities |
272 | | Usually called before deleting this pointer. Don't call directly! |
273 | | */ |
274 | | void _defragmentBatchDiscard(void); |
275 | | |
276 | | /** Called by InstancedEntity(s) to tell us we need to update the bounds |
277 | | (we touch the SceneNode so the SceneManager aknowledges such change) |
278 | | */ |
279 | | virtual void _boundsDirty(void); |
280 | | |
281 | | /** Tells this batch to stop updating animations, positions, rotations, and display |
282 | | all it's active instances. Currently only InstanceBatchHW & InstanceBatchHW_VTF support it. |
283 | | This option makes the batch behave pretty much like Static Geometry, but with the GPU RAM |
284 | | memory advantages (less VRAM, less bandwidth) and not LOD support. Very useful for |
285 | | billboards of trees, repeating vegetation, etc. |
286 | | |
287 | | @note This function moves a lot of processing time from the CPU to the GPU. If the GPU |
288 | | is already a bottleneck, you may see a decrease in performance instead! |
289 | | Call this function again (with bStatic=true) if you've made a change to an |
290 | | InstancedEntity and wish this change to take effect. |
291 | | Be sure to call this after you've set all your instances |
292 | | */ |
293 | 0 | virtual void setStaticAndUpdate( bool bStatic ) {} |
294 | | |
295 | | /** Returns true if this batch was set as static. @see setStaticAndUpdate |
296 | | */ |
297 | 0 | virtual bool isStatic() const { return false; } |
298 | | |
299 | | /** Returns a pointer to a new InstancedEntity ready to use |
300 | | Note it's actually preallocated, so no memory allocation happens at |
301 | | this point. |
302 | | |
303 | | @note Returns NULL if all instances are being used |
304 | | */ |
305 | | InstancedEntity* createInstancedEntity(); |
306 | | |
307 | | /** Removes an InstancedEntity from the scene retrieved with |
308 | | getNewInstancedEntity, putting back into a queue |
309 | | |
310 | | @note Throws an exception if the instanced entity wasn't created by this batch |
311 | | Removed instanced entities save little CPU time, but _not_ GPU |
312 | | */ |
313 | | void removeInstancedEntity( InstancedEntity *instancedEntity ); |
314 | | |
315 | | /** Tells whether world bone matrices need to be calculated. |
316 | | This does not include bone matrices which are calculated regardless |
317 | | */ |
318 | 0 | virtual bool useBoneWorldMatrices() const { return true; } |
319 | | |
320 | | /** Tells that the list of entity instances with shared transforms has changed */ |
321 | 0 | void _markTransformSharingDirty() { mTransformSharingDirty = true; } |
322 | | |
323 | | /** @see InstancedEntity::setCustomParam */ |
324 | | void _setCustomParam( InstancedEntity *instancedEntity, unsigned char idx, const Vector4f &newParam ); |
325 | | |
326 | | /** @see InstancedEntity::getCustomParam */ |
327 | | const Vector4f& _getCustomParam( InstancedEntity *instancedEntity, unsigned char idx ); |
328 | | |
329 | | //Renderable overloads |
330 | | /** @copydoc Renderable::getMaterial */ |
331 | 0 | const MaterialPtr& getMaterial(void) const override { return mMaterial; } |
332 | | /** @copydoc Renderable::getRenderOperation */ |
333 | 0 | void getRenderOperation( RenderOperation& op ) override { op = mRenderOperation; } |
334 | | |
335 | | /** @copydoc Renderable::getSquaredViewDepth */ |
336 | | Real getSquaredViewDepth( const Camera* cam ) const override; |
337 | | /** @copydoc Renderable::getLights */ |
338 | | const LightList& getLights( void ) const override; |
339 | | |
340 | | /** @copydoc MovableObject::getMovableType */ |
341 | | const String& getMovableType(void) const override; |
342 | | /** @copydoc MovableObject::_notifyCurrentCamera */ |
343 | | void _notifyCurrentCamera( Camera* cam ) override; |
344 | | /** @copydoc MovableObject::getBoundingBox */ |
345 | | const AxisAlignedBox& getBoundingBox(void) const override; |
346 | | /** @copydoc MovableObject::getBoundingRadius */ |
347 | | Real getBoundingRadius(void) const override; |
348 | | |
349 | | void _updateRenderQueue(RenderQueue* queue) override; |
350 | | void visitRenderables( Renderable::Visitor* visitor, bool debugRenderables = false ) override; |
351 | | |
352 | | // resolve ambiguity of get/setUserAny due to inheriting from Renderable and MovableObject |
353 | | using Renderable::getUserAny; |
354 | | using Renderable::setUserAny; |
355 | | }; |
356 | | } // namespace Ogre |
357 | | |
358 | | #include "OgreHeaderSuffix.h" |
359 | | |
360 | | #endif // __InstanceBatch_H__ |