Coverage Report

Created: 2025-08-25 06:48

/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__