From 35028908871c3677015e164a31691820d601419f Mon Sep 17 00:00:00 2001 From: lunkhound Date: Mon, 18 Nov 2013 12:18:41 -0800 Subject: [PATCH] skeleton bounding boxes: only compute the bone bounding radius if it is needed by an entity (lazy evaluation) --- OgreMain/include/OgreEntity.h | 4 +--- OgreMain/include/OgreMesh.h | 11 ++++++++--- OgreMain/src/OgreEntity.cpp | 14 ++++++++++++++ OgreMain/src/OgreMesh.cpp | 11 +++++------ 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/OgreMain/include/OgreEntity.h b/OgreMain/include/OgreEntity.h index 6162808bcee..628ed26984d 100644 --- a/OgreMain/include/OgreEntity.h +++ b/OgreMain/include/OgreEntity.h @@ -872,9 +872,7 @@ namespace Ogre { Also the resulting bounding box will be expanded by the amount of GetMesh()->getBoneBoundingRadius(). The expansion amount can be changed on the mesh to achieve a better fitting bounding box. */ - void setUpdateBoundingBoxFromSkeleton(bool update) { - mUpdateBoundingBoxFromSkeleton = update; - } + void setUpdateBoundingBoxFromSkeleton(bool update); /** If true, the skeleton of the entity will be used to update the bounding box for culling. Useful if you have skeletal animations that move the bones away from the root. Otherwise, the diff --git a/OgreMain/include/OgreMesh.h b/OgreMain/include/OgreMesh.h index 4dcdc8761c7..007f38056a9 100644 --- a/OgreMain/include/OgreMesh.h +++ b/OgreMain/include/OgreMesh.h @@ -216,7 +216,6 @@ namespace Ogre { void mergeAdjacentTexcoords( unsigned short finalTexCoordSet, unsigned short texCoordSetToDestroy, VertexData *vertexData ); - void computeBoneBoundingRadius(); public: @@ -367,11 +366,17 @@ namespace Ogre { /** Manually set the bone bounding radius. @remarks - This value is computed automatically when the mesh is loaded, however it can - be overriden with this method. + This value is normally computed automatically, however it can be overriden with this method. */ void _setBoneBoundingRadius(Real radius); + /** Compute the bone bounding radius by looking at the vertices, vertex-bone-assignments, and skeleton bind pose. + @remarks + This is automatically called by Entity if necessary. Only does something if the boneBoundingRadius is zero to + begin with. Only works if vertex data is readable (i.e. not WRITE_ONLY). + */ + void _computeBoneBoundingRadius(); + /** Automatically update the bounding radius and bounding box for this Mesh. @remarks Calling this method is required when building manual meshes. However it is recommended to diff --git a/OgreMain/src/OgreEntity.cpp b/OgreMain/src/OgreEntity.cpp index 58524a206e2..cacba521d3b 100644 --- a/OgreMain/src/OgreEntity.cpp +++ b/OgreMain/src/OgreEntity.cpp @@ -171,6 +171,11 @@ namespace Ogre { { mSkeletonInstance = OGRE_NEW SkeletonInstance(mMesh->getSkeleton()); mSkeletonInstance->load(); + // if mUpdateBoundingBoxFromSkeleton was turned on before the mesh was loaded, and mesh hasn't computed the boneBoundingRadius yet, + if ( mUpdateBoundingBoxFromSkeleton && mMesh->getBoneBoundingRadius() == Real(0)) + { + mMesh->_computeBoneBoundingRadius(); + } } // Build main subentity list @@ -505,6 +510,15 @@ namespace Ogre { } } //----------------------------------------------------------------------- + void Entity::setUpdateBoundingBoxFromSkeleton(bool update) + { + mUpdateBoundingBoxFromSkeleton = update; + if (mMesh->isLoaded() && mMesh->getBoneBoundingRadius() == Real(0)) + { + mMesh->_computeBoneBoundingRadius(); + } + } + //----------------------------------------------------------------------- const AxisAlignedBox& Entity::getBoundingBox(void) const { if (mMesh->isLoaded()) diff --git a/OgreMain/src/OgreMesh.cpp b/OgreMain/src/OgreMesh.cpp index dabfc4d5826..daa68ace286 100644 --- a/OgreMain/src/OgreMesh.cpp +++ b/OgreMain/src/OgreMesh.cpp @@ -561,7 +561,6 @@ namespace Ogre { // Take the opportunity to update the compiled bone assignments _updateCompiledBoneAssignments(); - computeBoneBoundingRadius(); } // Animation states for vertex animation @@ -905,7 +904,7 @@ namespace Ogre { return pt.distance( onLine ); } //--------------------------------------------------------------------- - Real _computeBoneBoundingRadius( VertexData* vertexData, + Real _computeBoneBoundingRadiusHelper( VertexData* vertexData, const Mesh::VertexBoneAssignmentList& boneAssignments, const vector::type& bonePositions, const vector< vector::type >::type& boneChildren @@ -966,9 +965,9 @@ namespace Ogre { return maxRadius; } //--------------------------------------------------------------------- - void Mesh::computeBoneBoundingRadius() + void Mesh::_computeBoneBoundingRadius() { - if (mBoneBoundingRadius == Real(0)) + if (mBoneBoundingRadius == Real(0) && ! mSkeleton.isNull()) { Real radius = Real(0); vector::type bonePositions; @@ -996,7 +995,7 @@ namespace Ogre { if (sharedVertexData) { // check shared vertices - radius = _computeBoneBoundingRadius(sharedVertexData, mBoneAssignments, bonePositions, boneChildren); + radius = _computeBoneBoundingRadiusHelper(sharedVertexData, mBoneAssignments, bonePositions, boneChildren); } // check submesh vertices @@ -1008,7 +1007,7 @@ namespace Ogre { SubMesh* submesh = *itor; if (!submesh->useSharedVertices && submesh->vertexData) { - Real r = _computeBoneBoundingRadius(submesh->vertexData, submesh->mBoneAssignments, bonePositions, boneChildren); + Real r = _computeBoneBoundingRadiusHelper(submesh->vertexData, submesh->mBoneAssignments, bonePositions, boneChildren); radius = std::max( radius, r ); } ++itor;