From 63008f4b2341f2fa436eb7bfde30652eb4be3835 Mon Sep 17 00:00:00 2001 From: Tazpn <tazpn@users.sourceforge.net> Date: Sat, 22 Sep 2007 16:13:09 +0000 Subject: [PATCH] Fixes for Bound calculations of objects with a morph attached. --- include/obj/NiGeomMorpherController.h | 5 ++ include/obj/NiGeometryData.h | 6 +++ src/obj/NiGeomMorpherController.cpp | 67 +++++++++++++++++++++++++++ src/obj/NiGeometryData.cpp | 6 +++ src/obj/bhkBoxShape.cpp | 1 + 5 files changed, 85 insertions(+) diff --git a/include/obj/NiGeomMorpherController.h b/include/obj/NiGeomMorpherController.h index 38281196..e2233555 100644 --- a/include/obj/NiGeomMorpherController.h +++ b/include/obj/NiGeomMorpherController.h @@ -94,6 +94,11 @@ public: */ NIFLIB_API void SetData( NiMorphData * n ); + /*! + * Update the Model Bounds + */ + NIFLIB_API void UpdateModelBound(); + //--END CUSTOM CODE--// protected: /*! Unknown. */ diff --git a/include/obj/NiGeometryData.h b/include/obj/NiGeometryData.h index 381eaad6..86c90cd9 100644 --- a/include/obj/NiGeometryData.h +++ b/include/obj/NiGeometryData.h @@ -97,6 +97,12 @@ public: */ NIFLIB_API float GetRadius() const; + /*! + * Assigns the center and radius of the spherical bound of this data. + * \remark GeoMorpher controllers will alter the model bound. + */ + NIFLIB_API void SetBound(Vector3 const & center, float radius); + /*! * Used to retrive the vertices used by this mesh. The size of the vector will be the same as the vertex count retrieved with the IShapeData::GetVertexCount function. * \return A vector cntaining the vertices used by this mesh. diff --git a/src/obj/NiGeomMorpherController.cpp b/src/obj/NiGeomMorpherController.cpp index 32d23f27..236fdab9 100644 --- a/src/obj/NiGeomMorpherController.cpp +++ b/src/obj/NiGeomMorpherController.cpp @@ -9,6 +9,8 @@ All rights reserved. Please see niflib.h for license. */ //--BEGIN FILE HEAD CUSTOM CODE--// #include "../../include/obj/NiKeyBasedInterpolator.h" +#include "../../include/obj/NiGeometry.h" +#include "../../include/obj/NiGeometryData.h" //--END CUSTOM CODE--// #include "../../include/FixLink.h" @@ -248,4 +250,69 @@ void NiGeomMorpherController::SetData( NiMorphData * n ) { data = n; } +// Calculate bounding sphere using minimum-volume axis-align bounding box. Its fast but not a very good fit. +static void CalcAxisAlignedBox(vector<Vector3> const & vertices, Vector3& center, float& radius) +{ + //--Calculate center & radius--// + + //Set lows and highs to first vertex + Vector3 lows = vertices[ 0 ]; + Vector3 highs = vertices[ 0 ]; + + if (radius != 0.0f) // Initialize from previous box + { + lows = Vector3(center.x - radius, center.y - radius, center.z - radius); + highs = Vector3(center.x + radius, center.y + radius, center.z + radius); + } + + //Iterate through the vertices, adjusting the stored values + //if a vertex with lower or higher values is found + for ( unsigned int i = 0; i < vertices.size(); ++i ) { + const Vector3 & v = vertices[ i ]; + + if ( v.x > highs.x ) highs.x = v.x; + else if ( v.x < lows.x ) lows.x = v.x; + + if ( v.y > highs.y ) highs.y = v.y; + else if ( v.y < lows.y ) lows.y = v.y; + + if ( v.z > highs.z ) highs.z = v.z; + else if ( v.z < lows.z ) lows.z = v.z; + } + + //Now we know the extent of the shape, so the center will be the average + //of the lows and highs + center = (highs + lows) / 2.0f; + + //The radius will be the largest distance from the center + Vector3 diff; + float dist2(0.0f), maxdist2(0.0f); + for ( unsigned int i = 0; i < vertices.size(); ++i ) { + const Vector3 & v = vertices[ i ]; + + diff = center - v; + dist2 = diff.x * diff.x + diff.y * diff.y + diff.z * diff.z; + if ( dist2 > maxdist2 ) maxdist2 = dist2; + }; + radius = sqrt(maxdist2); +} + +void NiGeomMorpherController::UpdateModelBound() { + if (NiGeometryRef geom = DynamicCast<NiGeometry>(target)) + { + if (NiGeometryDataRef gdata = geom->GetData()) + { + Vector3 center = gdata->GetCenter(); + float radius = gdata->GetRadius(); + int nmorph = data->GetMorphCount(); + for (int i=0; i<nmorph; i++) + { + CalcAxisAlignedBox(data->GetMorphVerts(i), center, radius); + } + gdata->SetBound(center, radius); + } + } +} + + //--END CUSTOM CODE--// diff --git a/src/obj/NiGeometryData.cpp b/src/obj/NiGeometryData.cpp index b8fde880..c3ab2e57 100644 --- a/src/obj/NiGeometryData.cpp +++ b/src/obj/NiGeometryData.cpp @@ -516,4 +516,10 @@ void NiGeometryData::SetConsistencyFlags( const ConsistencyType & value ) { consistencyFlags = value; } +void NiGeometryData::SetBound(Vector3 const & center, float radius) +{ + this->center = center; + this->radius = radius; +} + //--END CUSTOM CODE--// diff --git a/src/obj/bhkBoxShape.cpp b/src/obj/bhkBoxShape.cpp index ba8f695d..984f55a8 100644 --- a/src/obj/bhkBoxShape.cpp +++ b/src/obj/bhkBoxShape.cpp @@ -103,6 +103,7 @@ Vector3 bhkBoxShape::GetDimensions() const { void bhkBoxShape::SetDimensions(const Vector3 &value) { dimensions = value; + minimumSize = min( min(value.x, value.y), value.z ); } //--END CUSTOM CODE--// -- GitLab