/usr/include/OGRE/OgreInstanceBatch.h is in libogre-1.9-dev 1.9.0+dfsg1-7+b4.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
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 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 | /*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/
Copyright (c) 2000-2013 Torus Knot Software Ltd
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#ifndef __InstanceBatch_H__
#define __InstanceBatch_H__
#include "OgrePrerequisites.h"
#include "OgreRenderOperation.h"
#include "OgreRenderable.h"
#include "OgreMovableObject.h"
#include "OgreMesh.h"
#include "OgreHeaderPrefix.h"
namespace Ogre
{
/** \addtogroup Core
* @{
*/
/** \addtogroup Scene
* @{
*/
/** InstanceBatch forms part of the new Instancing system
This is an abstract class that must be derived to implement different instancing techniques
(@see InstanceManager::InstancingTechnique)
OGRE wasn't truly thought for instancing. OGRE assumes that either:
a. One MovableObject -> No Renderable
b. One MovableObject -> One Renderable
c. One MovableObject -> Many Renderable.
However, instances work on reverse: Many MovableObject have the same Renderable.
<b>Instancing is already difficult to cull by a CPU</b>, but the main drawback from this assumption
is that it makes it even harder to take advantage from OGRE's culling capabilities
(i.e. @see OctreeSceneManager)
@par
To workaround this problem, InstanceBatch updates on almost every frame,
growing the bounding box to fit all instances that are not being culled individually.
This helps by avoiding a huge bbox that may cover the whole scene, which decreases shadow
quality considerably (as it is seen as large shadow receiver)
Furthermore, if no individual instance is visible, the InstanceBatch switches it's visibility
(@see MovableObject::setVisible) to avoid sending this Renderable to the GPU. This happens because
even when no individual instance is visible, their merged bounding box may cause OGRE to think
the batch is visible (i.e. the camera is looking between object A & B, but A & B aren't visible)
@par
<b>As it happens with instancing in general, all instanced entities from the same batch will share
the same textures and materials</b>
@par
Each InstanceBatch preallocates a fixed amount of mInstancesPerBatch instances once it's been
built (@see build, @see buildFrom).
@see createInstancedEntity and @see removeInstancedEntity on how to retrieve those instances
remove them from scene.
Note that, on GPU side, removing an instance from scene doesn't save GPU cycles on what
respects vertex shaders, but saves a little fillrate and pixel shaders; unless all instances
are removed, which saves GPU.
For more information, @see InstancedEntity
For information on how Ogre manages multiple Instance batches, @see InstanceManager
@remarks
Design discussion webpage
@author
Matias N. Goldberg ("dark_sylinc")
@version
1.0
*/
class _OgreExport InstanceBatch : public Renderable, public MovableObject
{
public:
typedef vector<InstancedEntity*>::type InstancedEntityVec;
typedef vector<Vector4>::type CustomParamsVec;
protected:
RenderOperation mRenderOperation;
size_t mInstancesPerBatch;
InstanceManager *mCreator;
MaterialPtr mMaterial;
MeshPtr mMeshReference;
Mesh::IndexMap const *mIndexToBoneMap;
//InstancedEntities are all allocated at build time and kept as "unused"
//when they're requested, they're removed from there when requested,
//and put back again when they're no longer needed
//Note each InstancedEntity has a unique ID ranging from [0; mInstancesPerBatch)
InstancedEntityVec mInstancedEntities;
InstancedEntityVec mUnusedEntities;
///@see InstanceManager::setNumCustomParams(). Because this may not even be used,
///our implementations keep the params separate from the InstancedEntity to lower
///the memory overhead. They default to Vector4::ZERO
CustomParamsVec mCustomParams;
/// This bbox contains all (visible) instanced entities
AxisAlignedBox mFullBoundingBox;
Real mBoundingRadius;
bool mBoundsDirty;
bool mBoundsUpdated; //Set to false by derived classes that need it
Camera *mCurrentCamera;
unsigned short mMaterialLodIndex;
bool mDirtyAnimation; //Set to false at start of each _updateRenderQueue
/// False if a technique doesn't support skeletal animation
bool mTechnSupportsSkeletal;
/// Cached distance to last camera for getSquaredViewDepth
mutable Real mCachedCameraDist;
/// The camera for which the cached distance is valid
mutable const Camera *mCachedCamera;
/// Tells that the list of entity instances with shared transforms has changed
bool mTransformSharingDirty;
/// When true remove the memory of the VertexData we've created because no one else will
bool mRemoveOwnVertexData;
/// When true remove the memory of the IndexData we've created because no one else will
bool mRemoveOwnIndexData;
virtual void setupVertices( const SubMesh* baseSubMesh ) = 0;
virtual void setupIndices( const SubMesh* baseSubMesh ) = 0;
virtual void createAllInstancedEntities(void);
virtual void deleteAllInstancedEntities(void);
virtual void deleteUnusedInstancedEntities(void);
/// Creates a new InstancedEntity instance
virtual InstancedEntity* generateInstancedEntity(size_t num);
/** Takes an array of 3x4 matrices and makes it camera relative. Note the second argument
takes number of floats in the array, not number of matrices. Assumes mCachedCamera
contains the camera which is about to be rendered to.
*/
void makeMatrixCameraRelative3x4( float *mat3x4, size_t numFloats );
/// Returns false on errors that would prevent building this batch from the given submesh
virtual bool checkSubMeshCompatibility( const SubMesh* baseSubMesh );
void updateVisibility(void);
/** @see _defragmentBatch */
void defragmentBatchNoCull( InstancedEntityVec &usedEntities, CustomParamsVec &usedParams );
/** @see _defragmentBatch
This one takes the entity closest to the minimum corner of the bbox, then starts
gathering entities closest to this entity. There might be much better algorithms (i.e.
involving space partition), but this one is simple and works well enough
*/
void defragmentBatchDoCull( InstancedEntityVec &usedEntities, CustomParamsVec &usedParams );
public:
InstanceBatch( InstanceManager *creator, MeshPtr &meshReference, const MaterialPtr &material,
size_t instancesPerBatch, const Mesh::IndexMap *indexToBoneMap,
const String &batchName );
virtual ~InstanceBatch();
MeshPtr& _getMeshRef() { return mMeshReference; }
/** Raises an exception if trying to change it after being built
*/
void _setInstancesPerBatch( size_t instancesPerBatch );
const Mesh::IndexMap* _getIndexToBoneMap() const { return mIndexToBoneMap; }
/** Returns true if this technique supports skeletal animation
@remarks
A virtual function could have been used, but using a simple variable overridden
by the derived class is faster than virtual call overhead. And both are clean
ways of implementing it.
*/
bool _supportsSkeletalAnimation() const { return mTechnSupportsSkeletal; }
/** @see InstanceManager::updateDirtyBatches */
void _updateBounds(void);
/** Some techniques have a limit on how many instances can be done.
Sometimes even depends on the material being used.
@par
Note this is a helper function, as such it takes a submesh base to compute
the parameters, instead of using the object's own. This allows
querying for a technique without requiering to actually build it.
@param baseSubMesh The base submesh that will be using to build it.
@param flags Flags to pass to the InstanceManager. @see InstanceManagerFlags
@return The max instances limit
*/
virtual size_t calculateMaxNumInstances( const SubMesh *baseSubMesh, uint16 flags ) const = 0;
/** Constructs all the data needed to use this batch, as well as the
InstanceEntities. Placed here because in the constructor virtual
tables may not have been yet filled.
@param baseSubMesh A sub mesh which the instances will be based upon from.
@remarks
Call this only ONCE. This is done automatically by Ogre::InstanceManager
Caller is responsable for freeing buffers in this RenderOperation
Buffers inside the RenderOp may be null if the built failed.
@return
A render operation which is very useful to pass to other InstanceBatches
(@see buildFrom) so that they share the same vertex buffers and indices,
when possible
*/
virtual RenderOperation build( const SubMesh* baseSubMesh );
/** Instancing consumes significantly more GPU memory than regular rendering
methods. However, multiple batches can share most, if not all, of the
vertex & index buffers to save memory.
Derived classes are free to overload this method to manipulate what to
reference from Render Op.
For example, Hardware based instancing uses it's own vertex buffer for the
last source binding, but shares the other sources.
@param renderOperation The RenderOp to reference.
@remarks
Caller is responsable for freeing buffers passed as input arguments
This function replaces the need to call build()
*/
virtual void buildFrom( const SubMesh *baseSubMesh, const RenderOperation &renderOperation );
const Ogre::MeshPtr& _getMeshReference(void) const { return mMeshReference; }
/** @return true if it can not create more InstancedEntities
(Num InstancedEntities == mInstancesPerBatch)
*/
bool isBatchFull(void) const { return mUnusedEntities.empty(); }
/** Returns true if it no instanced entity has been requested or all of them have been removed
*/
bool isBatchUnused(void) const { return mUnusedEntities.size() == mInstancedEntities.size(); }
/** Fills the input vector with the instances that are currently being used or were requested.
Used for defragmentation, @see InstanceManager::defragmentBatches
*/
void getInstancedEntitiesInUse( InstancedEntityVec &outEntities, CustomParamsVec &outParams );
/** @see InstanceManager::defragmentBatches
This function takes InstancedEntities and pushes back all entities it can fit here
Extra entities in mUnusedEntities are destroyed
(so that used + unused = mInstancedEntities.size())
@param optimizeCulling true will call the DoCull version, false the NoCull
@param usedEntities Array of InstancedEntities to parent with this batch. Those reparented
are removed from this input vector
@param usedParams Array of Custom parameters correlated with the InstancedEntities in usedEntities.
They follow the fate of the entities in that vector.
@remarks:
This function assumes caller holds data to mInstancedEntities! Otherwise
you can get memory leaks. Don't call this directly if you don't know what you're doing!
*/
void _defragmentBatch( bool optimizeCulling, InstancedEntityVec &usedEntities,
CustomParamsVec &usedParams );
/** @see InstanceManager::_defragmentBatchDiscard
Destroys unused entities and clears the mInstancedEntity container which avoids leaving
dangling pointers from reparented InstancedEntities
Usually called before deleting this pointer. Don't call directly!
*/
void _defragmentBatchDiscard(void);
/** Called by InstancedEntity(s) to tell us we need to update the bounds
(we touch the SceneNode so the SceneManager aknowledges such change)
*/
virtual void _boundsDirty(void);
/** Tells this batch to stop updating animations, positions, rotations, and display
all it's active instances. Currently only InstanceBatchHW & InstanceBatchHW_VTF support it.
This option makes the batch behave pretty much like Static Geometry, but with the GPU RAM
memory advantages (less VRAM, less bandwidth) and not LOD support. Very useful for
billboards of trees, repeating vegetation, etc.
@remarks
This function moves a lot of processing time from the CPU to the GPU. If the GPU
is already a bottleneck, you may see a decrease in performance instead!
Call this function again (with bStatic=true) if you've made a change to an
InstancedEntity and wish this change to take effect.
Be sure to call this after you've set all your instances
@see InstanceBatchHW::setStaticAndUpdate
*/
virtual void setStaticAndUpdate( bool bStatic ) {}
/** Returns true if this batch was set as static. @see setStaticAndUpdate
*/
virtual bool isStatic() const { return false; }
/** Returns a pointer to a new InstancedEntity ready to use
Note it's actually preallocated, so no memory allocation happens at
this point.
@remarks
Returns NULL if all instances are being used
*/
InstancedEntity* createInstancedEntity();
/** Removes an InstancedEntity from the scene retrieved with
getNewInstancedEntity, putting back into a queue
@remarks
Throws an exception if the instanced entity wasn't created by this batch
Removed instanced entities save little CPU time, but _not_ GPU
*/
void removeInstancedEntity( InstancedEntity *instancedEntity );
/** Tells whether world bone matrices need to be calculated.
This does not include bone matrices which are calculated regardless
*/
virtual bool useBoneWorldMatrices() const { return true; }
/** Tells that the list of entity instances with shared transforms has changed */
void _markTransformSharingDirty() { mTransformSharingDirty = true; }
/** @see InstancedEntity::setCustomParam */
void _setCustomParam( InstancedEntity *instancedEntity, unsigned char idx, const Vector4 &newParam );
/** @see InstancedEntity::getCustomParam */
const Vector4& _getCustomParam( InstancedEntity *instancedEntity, unsigned char idx );
//Renderable overloads
/** @copydoc Renderable::getMaterial. */
const MaterialPtr& getMaterial(void) const { return mMaterial; }
/** @copydoc Renderable::getRenderOperation. */
void getRenderOperation( RenderOperation& op ) { op = mRenderOperation; }
/** @copydoc Renderable::getSquaredViewDepth. */
Real getSquaredViewDepth( const Camera* cam ) const;
/** @copydoc Renderable::getLights. */
const LightList& getLights( void ) const;
/** @copydoc Renderable::getTechnique. */
Technique* getTechnique(void) const;
/** @copydoc MovableObject::getMovableType. */
const String& getMovableType(void) const;
/** @copydoc MovableObject::_notifyCurrentCamera. */
void _notifyCurrentCamera( Camera* cam );
/** @copydoc MovableObject::getBoundingBox. */
const AxisAlignedBox& getBoundingBox(void) const;
/** @copydoc MovableObject::getBoundingRadius. */
Real getBoundingRadius(void) const;
virtual void _updateRenderQueue(RenderQueue* queue);
void visitRenderables( Renderable::Visitor* visitor, bool debugRenderables = false );
// resolve ambiguity of get/setUserAny due to inheriting from Renderable and MovableObject
using Renderable::getUserAny;
using Renderable::setUserAny;
};
} // namespace Ogre
#include "OgreHeaderSuffix.h"
#endif // __InstanceBatch_H__
|