From 0488eec5698d51193732dbff24bde8f78400f264 Mon Sep 17 00:00:00 2001 From: Tazpn <tazpn@users.sourceforge.net> Date: Sun, 7 Sep 2008 05:26:46 +0000 Subject: [PATCH] niflib: Add InertiaMatrix as first class niflib type. Add qhull to niflib. Add UpdateMassCenterInertia to bhkRigidBody and supporing bhkShape objects. --- include/Inertia.h | 56 ++++++ include/NIF_IO.h | 3 + include/gen/InertiaMatrix.h | 53 ------ include/nif_math.h | 206 ++++++++++++++++++++ include/obj/NiMorphData.h | 2 +- include/obj/bhkBoxShape.h | 10 + include/obj/bhkBvTreeShape.h | 11 ++ include/obj/bhkCapsuleShape.h | 10 + include/obj/bhkConvexShape.h | 11 ++ include/obj/bhkConvexTransformShape.h | 10 + include/obj/bhkConvexVerticesShape.h | 10 + include/obj/bhkListShape.h | 10 + include/obj/bhkMoppBvTreeShape.h | 10 + include/obj/bhkMultiSphereShape.h | 10 + include/obj/bhkNiTriStripsShape.h | 10 + include/obj/bhkPackedNiTriStripsShape.h | 10 + include/obj/bhkRigidBody.h | 17 +- include/obj/bhkShape.h | 12 ++ include/obj/bhkSphereRepShape.h | 10 + include/obj/bhkSphereShape.h | 10 + include/obj/bhkTransformShape.h | 10 + niflib.vcproj | 26 ++- niflib_VC2008.vcproj | 36 +++- src/Inertia.cpp | 238 ++++++++++++++++++++++++ src/NIF_IO.cpp | 17 ++ src/gen/InertiaMatrix.cpp | 37 ---- src/nif_math.cpp | 196 +++++++++++++++++++ src/obj/NiMorphData.cpp | 2 +- src/obj/bhkBoxShape.cpp | 6 + src/obj/bhkBvTreeShape.cpp | 7 + src/obj/bhkCapsuleShape.cpp | 16 ++ src/obj/bhkConvexShape.cpp | 8 + src/obj/bhkConvexTransformShape.cpp | 8 + src/obj/bhkConvexVerticesShape.cpp | 12 +- src/obj/bhkListShape.cpp | 25 +++ src/obj/bhkMoppBvTreeShape.cpp | 10 + src/obj/bhkMultiSphereShape.cpp | 7 + src/obj/bhkNiTriStripsShape.cpp | 21 +++ src/obj/bhkPackedNiTriStripsShape.cpp | 15 +- src/obj/bhkRigidBody.cpp | 118 +++++------- src/obj/bhkShape.cpp | 7 + src/obj/bhkSphereRepShape.cpp | 8 + src/obj/bhkSphereShape.cpp | 8 + src/obj/bhkTransformShape.cpp | 16 ++ 44 files changed, 1160 insertions(+), 175 deletions(-) create mode 100644 include/Inertia.h delete mode 100644 include/gen/InertiaMatrix.h create mode 100644 src/Inertia.cpp delete mode 100644 src/gen/InertiaMatrix.cpp diff --git a/include/Inertia.h b/include/Inertia.h new file mode 100644 index 00000000..a9c38c0b --- /dev/null +++ b/include/Inertia.h @@ -0,0 +1,56 @@ +/* Copyright (c) 2006, NIF File Format Library and Tools +All rights reserved. Please see niflib.h for license. */ + +#ifndef _NIF_INERTIA_H +#define _NIF_INERTIA_H +#pragma once + +//--Includes--// +#include "nif_math.h" +#include <vector> + +namespace Niflib { + +class Inertia { +public: + + /*! Return mass and inertia matrix for a sphere of given radius and + * density. + */ + static void GetMassInertiaSphere(float radius, float density, + bool solid, float& mass, InertiaMatrix &inertia); + + /*! Return mass and inertia matrix for a box of given size and + * density. + */ + static void GetMassInertiaBox(Vector3 size, float density, + bool solid, float& mass, InertiaMatrix &inertia); + /*! Return mass and inertia matrix for a cylinder of given radius, + * height and density. + */ + static void GetMassInertiaCylinder(float radius, float height, + float density, bool solid, + float& mass, InertiaMatrix &inertia); + + /*! Return mass and inertia matrix for a capsule of given radius, + * height and density. + */ + static void GetMassInertiaCapsule(float radius, float height, + float density, bool solid, + float& mass, InertiaMatrix &inertia); + + /*! Return mass and inertia matrix for a capsule of given radius, + * height and density. + */ + static void GetMassCenterInertiaPolyhedron( + const std::vector<Niflib::Vector3>& vertices, + const std::vector<Niflib::Triangle>& triangles, + float density, bool solid, + float& mass, Niflib::Vector3& center, InertiaMatrix &inertia); + +private: + explicit Inertia(); +}; + +} +#endif \ No newline at end of file diff --git a/include/NIF_IO.h b/include/NIF_IO.h index cf557a2c..f6093cec 100644 --- a/include/NIF_IO.h +++ b/include/NIF_IO.h @@ -209,6 +209,9 @@ void NifStream( Char8String & val, istream& in, const NifInfo & info ); void NifStream( Char8String const & val, ostream& out, const NifInfo & info ); ostream & operator<<( ostream & out, Char8String const & val ); +//InertiaMatrix +void NifStream( InertiaMatrix & val, istream& in, const NifInfo & info); +void NifStream( InertiaMatrix const & val, ostream& out, const NifInfo & info); //--Templates--// diff --git a/include/gen/InertiaMatrix.h b/include/gen/InertiaMatrix.h deleted file mode 100644 index e6a2c138..00000000 --- a/include/gen/InertiaMatrix.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright (c) 2006, NIF File Format Library and Tools -All rights reserved. Please see niflib.h for license. */ - -//---THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT---// - -//To change this file, alter the niftools/docsys/gen_niflib.py Python script. - -#ifndef _INERTIAMATRIX_H_ -#define _INERTIAMATRIX_H_ - -#include "../NIF_IO.h" - -namespace Niflib { - - -/*! An inertia matrix. */ -struct InertiaMatrix { - /*! Default Constructor */ - NIFLIB_API InertiaMatrix(); - /*! Default Destructor */ - NIFLIB_API ~InertiaMatrix(); - /*! Copy Constructor */ - NIFLIB_API InertiaMatrix( const InertiaMatrix & src ); - /*! Copy Operator */ - NIFLIB_API InertiaMatrix & operator=( const InertiaMatrix & src ); - /*! Unknown. */ - float m11; - /*! Unknown. */ - float m12; - /*! Unknown. */ - float m13; - /*! Zero */ - float m14; - /*! Unknown. */ - float m21; - /*! Unknown. */ - float m22; - /*! Unknown. */ - float m23; - /*! Zero */ - float m24; - /*! Unknown. */ - float m31; - /*! Unknown. */ - float m32; - /*! Unknown. */ - float m33; - /*! Zero */ - float m34; -}; - -} -#endif diff --git a/include/nif_math.h b/include/nif_math.h index 3dd3bf83..2c389be3 100644 --- a/include/nif_math.h +++ b/include/nif_math.h @@ -30,6 +30,7 @@ struct Float3; struct Matrix33; struct Float4; struct Matrix44; +struct InertiaMatrix; /*! Stores 2D texture coordinates as two floating point variables, u and v. */ struct TexCoord { @@ -231,6 +232,13 @@ struct Vector3 { */ NIFLIB_API bool operator!=( const Vector3 & rh ) const; + /*! The bracket operator makes it possible to use this structure like a C++ array. + * \param[in] n The index into the data array. Should be 0, 1, or 2. + * \return The value at the given array index by reference so it can be read or set via the bracket operator. + */ + NIFLIB_API float & operator[](int n); + NIFLIB_API float operator[](int n) const; + /* Computes the dot product of two vectors; the angle between two vectors. * \param[in] rh The vector to perform the dot product with * \return The angle in radians between this vector and the one given @@ -823,6 +831,18 @@ struct Matrix44 { */ NIFLIB_API Matrix44 & operator+=( const Matrix44 & rh ); + /* Adds this matrix to another. + * \param[in] rh The matrix to be added to this one. + * \return The result of the addition. + */ + NIFLIB_API Matrix44 operator-( const Matrix44 & rh ) const; + + /* Adds this matrix to another and sets the result to itself. + * \param[in] rh The matrix to be added to this one. + * \return This matrix is returned. + */ + NIFLIB_API Matrix44 & operator-=( const Matrix44 & rh ); + /* Sets the values of this matrix to those of the given matrix. * \param[in] rh The matrix to copy values from. * \return This matrix is returned. @@ -1020,6 +1040,190 @@ struct Quaternion { NIFLIB_API Float3 AsEulerYawPitchRoll(); }; + +/*! Stores a 4 by 3 matrix used for tensors. */ +struct InertiaMatrix { + /*! The 4x3 identity matrix constant */ + NIFLIB_API static const InertiaMatrix IDENTITY; + + Float4 rows[3]; /*!< The three rows of Float3 structures which hold three floating point numbers each. */ + + /*! The bracket operator makes it possible to use this structure like a 4x4 C++ array. + * \param[in] n The index into the row array. Should be 0, 1, 2, or 3. + * \return The Float4 structure for the given row index by reference so it can be read or set via the bracket operator. + */ + NIFLIB_API Float4 & operator[](int n) { + return rows[n]; + } + NIFLIB_API Float4 const & operator[](int n) const { + return rows[n]; + } + + /*! Default constructor. Initializes Matrix to Identity. */ + NIFLIB_API InertiaMatrix(); + + /*! Copy constructor. Initializes Matrix to another InertiaMatrix. + * \param[in] m The matrix to initialize this one to. + */ + NIFLIB_API InertiaMatrix( const InertiaMatrix & m ) { memcpy(rows, m.rows, sizeof(Float4) * 4); } + + /*! This constructor can be used to set all values in this matrix during initialization + * \param[in] m11 The value to set at row 1, column 1. + * \param[in] m12 The value to set at row 1, column 2. + * \param[in] m13 The value to set at row 1, column 3. + * \param[in] m14 The value to set at row 1, column 4. + * \param[in] m21 The value to set at row 2, column 1. + * \param[in] m22 The value to set at row 2, column 2. + * \param[in] m23 The value to set at row 2, column 3. + * \param[in] m24 The value to set at row 2, column 4. + * \param[in] m31 The value to set at row 3, column 1. + * \param[in] m32 The value to set at row 3, column 2. + * \param[in] m33 The value to set at row 3, column 3. + * \param[in] m34 The value to set at row 3, column 4. + * \param[in] m41 The value to set at row 4, column 1. + * \param[in] m42 The value to set at row 4, column 2. + * \param[in] m43 The value to set at row 4, column 3. + * \param[in] m44 The value to set at row 4, column 4. + */ + NIFLIB_API InertiaMatrix( + float m11, float m12, float m13, float m14, + float m21, float m22, float m23, float m24, + float m31, float m32, float m33, float m34 + ) { + rows[0][0] = m11; rows[0][1] = m12; rows[0][2] = m13; rows[0][3] = m14; + rows[1][0] = m21; rows[1][1] = m22; rows[1][2] = m23; rows[1][3] = m24; + rows[2][0] = m31; rows[2][1] = m32; rows[2][2] = m33; rows[2][3] = m34; + } + + /*! This constructor allows a 4x4 transform matrix to be initalized from a + * a 3x3 rotation matrix. + * \param[in] rotation The 3x3 rotation matrix. + */ + NIFLIB_API InertiaMatrix( const Matrix33 & rotation ); + + /*! This function can be used to set all values in this matrix at the same time. + * \param[in] m11 The value to set at row 1, column 1. + * \param[in] m12 The value to set at row 1, column 2. + * \param[in] m13 The value to set at row 1, column 3. + * \param[in] m14 The value to set at row 1, column 4. + * \param[in] m21 The value to set at row 2, column 1. + * \param[in] m22 The value to set at row 2, column 2. + * \param[in] m23 The value to set at row 2, column 3. + * \param[in] m24 The value to set at row 2, column 4. + * \param[in] m31 The value to set at row 3, column 1. + * \param[in] m32 The value to set at row 3, column 2. + * \param[in] m33 The value to set at row 3, column 3. + * \param[in] m34 The value to set at row 3, column 4. + */ + NIFLIB_API void Set( + float m11, float m12, float m13, float m14, + float m21, float m22, float m23, float m24, + float m31, float m32, float m33, float m34 + ) { + rows[0][0] = m11; rows[0][1] = m12; rows[0][2] = m13; rows[0][3] = m14; + rows[1][0] = m21; rows[1][1] = m22; rows[1][2] = m23; rows[1][3] = m24; + rows[2][0] = m31; rows[2][1] = m32; rows[2][2] = m33; rows[2][3] = m34; + } + + /* Multiplies this matrix by another. + * \param[in] rh The matrix to multiply this one with. + * \return The result of the multiplication. + */ + NIFLIB_API InertiaMatrix operator*( const InertiaMatrix & rh ) const; + + /* Multiplies this matrix by another and sets the result to itself. + * \param[in] rh The matrix to multiply this one with. + * \return This matrix is returned. + */ + NIFLIB_API InertiaMatrix & operator*=( const InertiaMatrix & rh ); + + /* Multiplies this matrix by a scalar value. + * \param[in] rh The scalar value to multiply each component of this matrix by. + * \return The result of the multiplication. + */ + NIFLIB_API InertiaMatrix operator*( float rh ) const; + + /* Multiplies this matrix by a scalar value and sets the resutl to itself. + * \param[in] rh The scalar value to multiply each component of this matrix by. + * \return This matrix is returned. + */ + NIFLIB_API InertiaMatrix & operator*=( float rh ); + + /* Multiplies this matrix by a vector with x, y, and z components. + * \param[in] rh The vector to multiply this matrix with. + * \return The result of the multiplication. + */ + NIFLIB_API Vector3 operator*( const Vector3 & rh ) const; + + /* Adds this matrix to another. + * \param[in] rh The matrix to be added to this one. + * \return The result of the addition. + */ + NIFLIB_API InertiaMatrix operator+( const InertiaMatrix & rh ) const; + + /* Adds this matrix to another and sets the result to itself. + * \param[in] rh The matrix to be added to this one. + * \return This matrix is returned. + */ + NIFLIB_API InertiaMatrix & operator+=( const InertiaMatrix & rh ); + + /* Sets the values of this matrix to those of the given matrix. + * \param[in] rh The matrix to copy values from. + * \return This matrix is returned. + */ + NIFLIB_API InertiaMatrix & operator=( const InertiaMatrix & rh ); + + /* Allows the contents of the matrix to be printed to an ostream. + * \param[in] lh The ostream to insert the text into. + * \param[in] rh The matrix to insert into the stream. + * \return The given ostream is returned. + */ + NIFLIB_API friend ostream & operator<<( ostream & lh, const InertiaMatrix & rh ); + + /* Compares two 4x4 matricies. They are considered equal if all components are equal. + * \param[in] rh The matrix to compare this one with. + * \return true if the matricies are equal, false otherwise. + */ + NIFLIB_API bool operator==( const InertiaMatrix & rh ) const; + + /* Compares two 4x4 matricies. They are considered inequal if any corresponding + * components are inequal. + * \param[in] rh The matrix to compare this one with. + * \return true if the matricies are inequal, false otherwise. + */ + NIFLIB_API bool operator!=( const InertiaMatrix & rh ) const; + + /*! Calculates the transpose of this matrix. + * \return The transpose of this matrix. + */ + NIFLIB_API InertiaMatrix Transpose() const; + + /*! Calculates the determinant of this matrix. + * \return The determinant of this matrix. + */ + NIFLIB_API float Determinant() const; + + /*! Calculates the inverse of this matrix. + * \return The inverse of this matrix. + */ + NIFLIB_API InertiaMatrix Inverse() const; + + /*! Returns a 3x3 submatrix of this matrix created by skipping the indicated row and column. + * \param[in] skip_r The row to skip. Must be a value between 0 and 3. + * \param[in] skip_c The colum to skip. Must be a value between 0 and 3. + * \return The 3x3 submatrix obtained by skipping the indicated row and column. + */ + NIFLIB_API Matrix33 Submatrix( int skip_r, int skip_c ) const; + + /*! Calculates the adjunct of this matrix created by skipping the indicated row and column. + * \param[in] skip_r The row to skip. Must be a value between 0 and 3. + * \param[in] skip_c The colum to skip. Must be a value between 0 and 3. + * \return The adjunct obtained by skipping the indicated row and column. + */ + NIFLIB_API float Adjoint( int skip_r, int skip_c ) const; +}; + + //--ostream functions for printing with cout--// NIFLIB_API ostream & operator<<( ostream & out, TexCoord const & val ); @@ -1033,6 +1237,8 @@ NIFLIB_API ostream & operator<<( ostream & out, Float4 const & val ); NIFLIB_API ostream & operator<<( ostream & out, Color3 const & val ); NIFLIB_API ostream & operator<<( ostream & out, Color4 const & val ); NIFLIB_API ostream & operator<<( ostream & out, Quaternion const & val ); +NIFLIB_API ostream & operator<<( ostream & out, Matrix44 const & val ); +NIFLIB_API ostream & operator<<( ostream & out, InertiaMatrix const & val ); } #endif diff --git a/include/obj/NiMorphData.h b/include/obj/NiMorphData.h index 426ab11e..4ead91ae 100644 --- a/include/obj/NiMorphData.h +++ b/include/obj/NiMorphData.h @@ -164,7 +164,7 @@ protected: /*! Number of vertices. */ unsigned int numVertices; /*! This byte is always 1 in all official files. */ - bool relativeTargets; + byte relativeTargets; /*! The geometry morphing objects. */ vector<Morph > morphs; public: diff --git a/include/obj/bhkBoxShape.h b/include/obj/bhkBoxShape.h index dc14ea94..c17851aa 100644 --- a/include/obj/bhkBoxShape.h +++ b/include/obj/bhkBoxShape.h @@ -66,6 +66,16 @@ public: */ NIFLIB_API void SetDimensions( const Vector3 & value ); + /*! Helper routine for calculating mass properties. + * \param[in] density Uniform density of object + * \param[in] solid Determines whether the object is assumed to be solid or not + * \param[out] mass Calculated mass of the object + * \param[out] center Center of mass + * \param[out] inertia Mass Inertia Tensor + * \return Return mass, center, and inertia tensor. + */ + NIFLIB_API virtual void CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia); + //--END CUSTOM CODE--// protected: /*! Unknown. */ diff --git a/include/obj/bhkBvTreeShape.h b/include/obj/bhkBvTreeShape.h index 16e32e98..03d8c929 100644 --- a/include/obj/bhkBvTreeShape.h +++ b/include/obj/bhkBvTreeShape.h @@ -52,6 +52,17 @@ public: */ NIFLIB_API virtual const Type & GetType() const; + + /*! Helper routine for calculating mass properties. + * \param[in] density Uniform density of object + * \param[in] solid Determines whether the object is assumed to be solid or not + * \param[out] mass Calculated mass of the object + * \param[out] center Center of mass + * \param[out] inertia Mass Inertia Tensor + * \return Return mass, center, and inertia tensor. + */ + NIFLIB_API virtual void CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia); + //--BEGIN MISC CUSTOM CODE--// //--END CUSTOM CODE--// public: diff --git a/include/obj/bhkCapsuleShape.h b/include/obj/bhkCapsuleShape.h index 2eaf164f..6428b717 100644 --- a/include/obj/bhkCapsuleShape.h +++ b/include/obj/bhkCapsuleShape.h @@ -114,6 +114,16 @@ public: */ NIFLIB_API void SetRadius2( float value ); + /*! Helper routine for calculating mass properties. + * \param[in] density Uniform density of object + * \param[in] solid Determines whether the object is assumed to be solid or not + * \param[out] mass Calculated mass of the object + * \param[out] center Center of mass + * \param[out] inertia Mass Inertia Tensor + * \return Return mass, center, and inertia tensor. + */ + NIFLIB_API virtual void CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia); + //--END CUSTOM CODE--// protected: /*! Unknown. */ diff --git a/include/obj/bhkConvexShape.h b/include/obj/bhkConvexShape.h index 2b7dd380..aec3cdb5 100644 --- a/include/obj/bhkConvexShape.h +++ b/include/obj/bhkConvexShape.h @@ -53,6 +53,17 @@ public: NIFLIB_API virtual const Type & GetType() const; //--BEGIN MISC CUSTOM CODE--// + + /*! Helper routine for calculating mass properties. + * \param[in] density Uniform density of object + * \param[in] solid Determines whether the object is assumed to be solid or not + * \param[out] mass Calculated mass of the object + * \param[out] center Center of mass + * \param[out] inertia Mass Inertia Tensor + * \return Return mass, center, and inertia tensor. + */ + NIFLIB_API virtual void CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia); + //--END CUSTOM CODE--// public: /*! NIFLIB_HIDDEN function. For internal use only. */ diff --git a/include/obj/bhkConvexTransformShape.h b/include/obj/bhkConvexTransformShape.h index 2e835654..9b8864bc 100644 --- a/include/obj/bhkConvexTransformShape.h +++ b/include/obj/bhkConvexTransformShape.h @@ -53,6 +53,16 @@ public: NIFLIB_API virtual const Type & GetType() const; //--BEGIN MISC CUSTOM CODE--// + /*! Helper routine for calculating mass properties. + * \param[in] density Uniform density of object + * \param[in] solid Determines whether the object is assumed to be solid or not + * \param[out] mass Calculated mass of the object + * \param[out] center Center of mass + * \param[out] inertia Mass Inertia Tensor + * \return Return mass, center, and inertia tensor. + */ + NIFLIB_API virtual void CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia); + //--END CUSTOM CODE--// public: /*! NIFLIB_HIDDEN function. For internal use only. */ diff --git a/include/obj/bhkConvexVerticesShape.h b/include/obj/bhkConvexVerticesShape.h index 24b7a1fc..3155f085 100644 --- a/include/obj/bhkConvexVerticesShape.h +++ b/include/obj/bhkConvexVerticesShape.h @@ -111,6 +111,16 @@ public: */ NIFLIB_API void SetNormalsAndDist(const vector<Vector4>& value); + /*! Helper routine for calculating mass properties. + * \param[in] density Uniform density of object + * \param[in] solid Determines whether the object is assumed to be solid or not + * \param[out] mass Calculated mass of the object + * \param[out] center Center of mass + * \param[out] inertia Mass Inertia Tensor + * \return Return mass, center, and inertia tensor. + */ + NIFLIB_API virtual void CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia); + //--END CUSTOM CODE--// protected: /*! diff --git a/include/obj/bhkListShape.h b/include/obj/bhkListShape.h index 605c85ad..7d362570 100644 --- a/include/obj/bhkListShape.h +++ b/include/obj/bhkListShape.h @@ -91,6 +91,16 @@ public: */ NIFLIB_API void SetMaterial( HavokMaterial value ); + /*! Helper routine for calculating mass properties. + * \param[in] density Uniform density of object + * \param[in] solid Determines whether the object is assumed to be solid or not + * \param[out] mass Calculated mass of the object + * \param[out] center Center of mass + * \param[out] inertia Mass Inertia Tensor + * \return Return mass, center, and inertia tensor. + */ + NIFLIB_API virtual void CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia); + //--END CUSTOM CODE--// protected: /*! The number of sub shapes referenced. */ diff --git a/include/obj/bhkMoppBvTreeShape.h b/include/obj/bhkMoppBvTreeShape.h index 7e563487..8ef6c4f7 100644 --- a/include/obj/bhkMoppBvTreeShape.h +++ b/include/obj/bhkMoppBvTreeShape.h @@ -130,6 +130,16 @@ public: */ NIFLIB_API void SetMoppScale( float value ); + /*! Helper routine for calculating mass properties. + * \param[in] density Uniform density of object + * \param[in] solid Determines whether the object is assumed to be solid or not + * \param[out] mass Calculated mass of the object + * \param[out] center Center of mass + * \param[out] inertia Mass Inertia Tensor + * \return Return mass, center, and inertia tensor. + */ + NIFLIB_API virtual void CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia); + //--END CUSTOM CODE--// protected: /*! The shape. */ diff --git a/include/obj/bhkMultiSphereShape.h b/include/obj/bhkMultiSphereShape.h index 61a06437..abdf6758 100644 --- a/include/obj/bhkMultiSphereShape.h +++ b/include/obj/bhkMultiSphereShape.h @@ -70,6 +70,16 @@ public: NIFLIB_API void SetSpheres( const vector<SphereBV> & value ); + /*! Helper routine for calculating mass properties. + * \param[in] density Uniform density of object + * \param[in] solid Determines whether the object is assumed to be solid or not + * \param[out] mass Calculated mass of the object + * \param[out] center Center of mass + * \param[out] inertia Mass Inertia Tensor + * \return Return mass, center, and inertia tensor. + */ + NIFLIB_API virtual void CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia); + //--END CUSTOM CODE--// protected: /*! Unknown. */ diff --git a/include/obj/bhkNiTriStripsShape.h b/include/obj/bhkNiTriStripsShape.h index ba5454aa..f1a5f0b7 100644 --- a/include/obj/bhkNiTriStripsShape.h +++ b/include/obj/bhkNiTriStripsShape.h @@ -131,6 +131,16 @@ public: NIFLIB_API unsigned char GetOblivionFilter( unsigned int index ) const; NIFLIB_API void SetOblivionFilter( unsigned int index, unsigned char filter ); + /*! Helper routine for calculating mass properties. + * \param[in] density Uniform density of object + * \param[in] solid Determines whether the object is assumed to be solid or not + * \param[out] mass Calculated mass of the object + * \param[out] center Center of mass + * \param[out] inertia Mass Inertia Tensor + * \return Return mass, center, and inertia tensor. + */ + NIFLIB_API virtual void CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia); + //--END CUSTOM CODE--// protected: /*! The shape's material. */ diff --git a/include/obj/bhkPackedNiTriStripsShape.h b/include/obj/bhkPackedNiTriStripsShape.h index d534d8dd..b9326232 100644 --- a/include/obj/bhkPackedNiTriStripsShape.h +++ b/include/obj/bhkPackedNiTriStripsShape.h @@ -83,6 +83,16 @@ public: */ NIFLIB_API void SetSubShapes( vector<OblivionSubShape>& value ); + /*! Helper routine for calculating mass properties. + * \param[in] density Uniform density of object + * \param[in] solid Determines whether the object is assumed to be solid or not + * \param[out] mass Calculated mass of the object + * \param[out] center Center of mass + * \param[out] inertia Mass Inertia Tensor + * \return Return mass, center, and inertia tensor. + */ + NIFLIB_API virtual void CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia); + //--END CUSTOM CODE--// protected: /*! Number of subparts. */ diff --git a/include/obj/bhkRigidBody.h b/include/obj/bhkRigidBody.h index 76104f3f..b71f1f0f 100644 --- a/include/obj/bhkRigidBody.h +++ b/include/obj/bhkRigidBody.h @@ -17,7 +17,6 @@ All rights reserved. Please see niflib.h for license. */ // Include structures #include "../gen/QuaternionXYZW.h" -#include "../gen/InertiaMatrix.h" #include "../Ref.h" namespace Niflib { @@ -133,13 +132,13 @@ public: * Gets the current inertia of this rigid body. * \return The inertia of this rigid body. */ - NIFLIB_API array<12,float> GetInertia() const; + NIFLIB_API InertiaMatrix GetInertia() const; /*! * Sets a new inertia for this rigid body. * \param[in] value The new inertia for this rigid body. */ - NIFLIB_API void SetInertia( const array<12,float> & value ); + NIFLIB_API void SetInertia( const InertiaMatrix & value ); /*! * Gets the current center point of this rigid body. @@ -284,13 +283,21 @@ public: // Usually set to 1 for fixed objects, or set to 2 for moving ones. Seems to // always be same as Unknown Byte 1. // \return The current value. - SolverDeactivation GetSolverDeactivation() const; + NIFLIB_API SolverDeactivation GetSolverDeactivation() const; // Usually set to 1 for fixed objects, or set to 2 for moving ones. Seems to // always be same as Unknown Byte 1. // \param[in] value The new value. - void SetSolverDeactivation( const SolverDeactivation & value ); + NIFLIB_API void SetSolverDeactivation( const SolverDeactivation & value ); + // Apply scale factor <scale> on data. + // \param[in] scale Factor to scale by + NIFLIB_API void ApplyScale(float scale); + + // Look at all the objects under this rigid body and update the mass + // center of gravity, and inertia tensor accordingly. If the mass parameter + // is given then the density argument is ignored. + NIFLIB_API void UpdateMassCenterInertia(float density = 1.0f, bool solid = true, float mass = 0.0f); //--END CUSTOM CODE--// protected: diff --git a/include/obj/bhkShape.h b/include/obj/bhkShape.h index d1704f6b..6b858a03 100644 --- a/include/obj/bhkShape.h +++ b/include/obj/bhkShape.h @@ -11,6 +11,7 @@ All rights reserved. Please see niflib.h for license. */ #define _BHKSHAPE_H_ //--BEGIN FILE HEAD CUSTOM CODE--// +#include "../NIF_IO.h" //--END CUSTOM CODE--// #include "bhkSerializable.h" @@ -53,6 +54,17 @@ public: NIFLIB_API virtual const Type & GetType() const; //--BEGIN MISC CUSTOM CODE--// + + /*! Helper routine for calculating mass properties. + * \param[in] density Uniform density of object + * \param[in] solid Determines whether the object is assumed to be solid or not + * \param[out] mass Calculated mass of the object + * \param[out] center Center of mass + * \param[out] inertia Mass Inertia Tensor + * \return Return mass, center, and inertia tensor. + */ + NIFLIB_API virtual void CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia); + //--END CUSTOM CODE--// public: /*! NIFLIB_HIDDEN function. For internal use only. */ diff --git a/include/obj/bhkSphereRepShape.h b/include/obj/bhkSphereRepShape.h index 27cb1b44..fd08bad8 100644 --- a/include/obj/bhkSphereRepShape.h +++ b/include/obj/bhkSphereRepShape.h @@ -81,6 +81,16 @@ public: */ NIFLIB_API void SetRadius( float value ); + /*! Helper routine for calculating mass properties. + * \param[in] density Uniform density of object + * \param[in] solid Determines whether the object is assumed to be solid or not + * \param[out] mass Calculated mass of the object + * \param[out] center Center of mass + * \param[out] inertia Mass Inertia Tensor + * \return Return mass, center, and inertia tensor. + */ + NIFLIB_API virtual void CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia); + //--END CUSTOM CODE--// protected: /*! The shape's material. */ diff --git a/include/obj/bhkSphereShape.h b/include/obj/bhkSphereShape.h index 0b32da66..1145b7ee 100644 --- a/include/obj/bhkSphereShape.h +++ b/include/obj/bhkSphereShape.h @@ -66,6 +66,16 @@ public: */ NIFLIB_API void SetRadius( float value ); + /*! Helper routine for calculating mass properties. + * \param[in] density Uniform density of object + * \param[in] solid Determines whether the object is assumed to be solid or not + * \param[out] mass Calculated mass of the object + * \param[out] center Center of mass + * \param[out] inertia Mass Inertia Tensor + * \return Return mass, center, and inertia tensor. + */ + NIFLIB_API virtual void CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia); + //--END CUSTOM CODE--// public: /*! NIFLIB_HIDDEN function. For internal use only. */ diff --git a/include/obj/bhkTransformShape.h b/include/obj/bhkTransformShape.h index 6cf08300..34d7470d 100644 --- a/include/obj/bhkTransformShape.h +++ b/include/obj/bhkTransformShape.h @@ -94,6 +94,16 @@ public: */ NIFLIB_API virtual void SetTransform( const Matrix44 & value ); + /*! Helper routine for calculating mass properties. + * \param[in] density Uniform density of object + * \param[in] solid Determines whether the object is assumed to be solid or not + * \param[out] mass Calculated mass of the object + * \param[out] center Center of mass + * \param[out] inertia Mass Inertia Tensor + * \return Return mass, center, and inertia tensor. + */ + NIFLIB_API virtual void CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia); + //--END CUSTOM CODE--// protected: diff --git a/niflib.vcproj b/niflib.vcproj index ba817327..33bf04b4 100644 --- a/niflib.vcproj +++ b/niflib.vcproj @@ -597,7 +597,7 @@ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > <File - RelativePath=".\src\ComplexShape.cpp" + RelativePath=".\src\Inertia.cpp" > </File> <File @@ -652,6 +652,10 @@ /> </FileConfiguration> </File> + <File + RelativePath=".\src\nifqhull.cpp" + > + </File> <File RelativePath=".\src\ObjectRegistry.cpp" > @@ -1851,6 +1855,10 @@ RelativePath=".\src\gen\ChannelData.cpp" > </File> + <File + RelativePath=".\src\ComplexShape.cpp" + > + </File> <File RelativePath=".\src\gen\ControllerLink.cpp" > @@ -1883,10 +1891,6 @@ RelativePath=".\src\gen\hkTriangle.cpp" > </File> - <File - RelativePath=".\src\gen\InertiaMatrix.cpp" - > - </File> <File RelativePath=".\src\gen\LimitedHingeDescriptor.cpp" > @@ -2054,6 +2058,10 @@ RelativePath=".\include\FixLink.h" > </File> + <File + RelativePath=".\include\Inertia.h" + > + </File> <File RelativePath=".\include\Key.h" > @@ -2086,6 +2094,10 @@ RelativePath=".\include\niflib.h" > </File> + <File + RelativePath=".\include\nifqhull.h" + > + </File> <File RelativePath=".\include\ObjectRegistry.h" > @@ -2105,6 +2117,10 @@ <Filter Name="obj" > + <File + RelativePath=".\include\obj\ATextureRenderData.h" + > + </File> <File RelativePath=".\include\obj\AvoidNode.h" > diff --git a/niflib_VC2008.vcproj b/niflib_VC2008.vcproj index d31472d6..3146ad08 100644 --- a/niflib_VC2008.vcproj +++ b/niflib_VC2008.vcproj @@ -593,6 +593,10 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > + <File + RelativePath=".\src\Inertia.cpp" + > + </File> <File RelativePath=".\src\kfm.cpp" > @@ -645,6 +649,10 @@ /> </FileConfiguration> </File> + <File + RelativePath=".\src\nifqhull.cpp" + > + </File> <File RelativePath=".\src\ObjectRegistry.cpp" > @@ -1880,10 +1888,6 @@ RelativePath=".\src\gen\hkTriangle.cpp" > </File> - <File - RelativePath=".\src\gen\InertiaMatrix.cpp" - > - </File> <File RelativePath=".\src\gen\LimitedHingeDescriptor.cpp" > @@ -2051,6 +2055,10 @@ RelativePath=".\include\FixLink.h" > </File> + <File + RelativePath=".\include\Inertia.h" + > + </File> <File RelativePath=".\include\Key.h" > @@ -2083,6 +2091,10 @@ RelativePath=".\include\niflib.h" > </File> + <File + RelativePath=".\include\nifqhull.h" + > + </File> <File RelativePath=".\include\ObjectRegistry.h" > @@ -2798,6 +2810,10 @@ RelativePath=".\include\obj\NiPathInterpolator.h" > </File> + <File + RelativePath=".\include\obj\NiPersistentSrcTextureRendererData.h" + > + </File> <File RelativePath=".\include\obj\NiPhysXActorDesc.h" > @@ -3034,6 +3050,14 @@ RelativePath=".\include\obj\NiRotatingParticlesData.h" > </File> + <File + RelativePath=".\include\obj\NiScreenElements.h" + > + </File> + <File + RelativePath=".\include\obj\NiScreenElementsData.h" + > + </File> <File RelativePath=".\include\obj\NiScreenLODData.h" > @@ -3370,6 +3394,10 @@ RelativePath=".\include\gen\physXMaterialRef.h" > </File> + <File + RelativePath=".\include\gen\Polygon.h" + > + </File> <File RelativePath=".\include\gen\QuaternionXYZW.h" > diff --git a/src/Inertia.cpp b/src/Inertia.cpp new file mode 100644 index 00000000..1b103488 --- /dev/null +++ b/src/Inertia.cpp @@ -0,0 +1,238 @@ +/* Copyright (c) 2006, NIF File Format Library and Tools +All rights reserved. Please see niflib.h for license. */ + +#include "../include/Inertia.h" +#include <vector> +#include <algorithm> +#include <functional> +#include <numeric> +#define _USE_MATH_DEFINES +#include <math.h> +using namespace Niflib; + +void Inertia::GetMassInertiaSphere(float radius, float density, bool solid, + float& mass, InertiaMatrix &inertia) +{ + float inertiaScalar; + if (solid) { + mass = density * (4.0f * float(M_PI) * pow(radius, 3.0f)) / 3.0f; + inertiaScalar = (2.0f * mass * pow(radius, 2.0f)) / 5.0f; + } else { + mass = density * 4.0f * float(M_PI) * pow(radius, 2.0f); + inertiaScalar = (2.0f * mass * pow(radius, 2.0f)) / 3.0f; + } + inertia = InertiaMatrix::IDENTITY; + inertia[0][0] = inertia[1][1] = inertia[2][2] = inertiaScalar; +} + + + +void Inertia::GetMassInertiaBox(Vector3 size, float density, bool solid, + float& mass, InertiaMatrix &inertia) +{ + Vector3 tmp; + if (solid) + { + mass = density * (size[0] * size[1] * size[2]); + tmp[0] = mass * pow(size[0], 2.0f) / 12.0f; + tmp[1] = mass * pow(size[1], 2.0f) / 12.0f; + tmp[2] = mass * pow(size[2], 2.0f) / 12.0f; + } + else + { + mass = density * ((size[0]*size[1]*2.0f) + (size[0]*size[2]*2.0f) + (size[1]*size[2]*2.0f)); + tmp[0] = mass * pow(size[0], 2.0f) / 6.0f; + tmp[1] = mass * pow(size[1], 2.0f) / 6.0f; + tmp[2] = mass * pow(size[2], 2.0f) / 6.0f; + //TODO: just guessing here, calculate it + } + inertia = InertiaMatrix::IDENTITY; + inertia[0][0] = tmp[1] + tmp[2]; + inertia[1][1] = tmp[2] + tmp[0]; + inertia[2][2] = tmp[0] + tmp[1]; +} + +void Inertia::GetMassInertiaCylinder(float radius, float height, + float density, bool solid, + float& mass, InertiaMatrix &inertia) +{ + inertia = InertiaMatrix::IDENTITY; + if (solid) + { + mass = density * height * float(M_PI) * pow(radius, 2.0f); + inertia[0][0] = + inertia[1][1] = mass * (3.0f * pow(radius, 3.0f) + pow(height, 2.0f)) / 12.0f; + inertia[2][2] = mass * (pow(radius, 2.0f)) / 2.0f; + } + else + { + mass = density * height * float(M_PI) * pow(radius, 2.0f); + inertia[0][0] = + inertia[1][1] = mass * (6.0f * pow(radius, 3.0f) + pow(height, 2.0f)) / 12.0f; + inertia[2][2] = mass * (pow(radius, 2.0f)); + } +} + +void Inertia::GetMassInertiaCapsule(float radius, float height, + float density, bool solid, + float& mass, InertiaMatrix &inertia) +{ + // cylinder + caps, and caps have volume of a sphere + inertia = InertiaMatrix::IDENTITY; + if (solid) + { + mass = density * (height * float(M_PI) * pow(radius, 2.0f) + (4.0f * float(M_PI) * pow(radius, 3.0f)) / 3.0f); + inertia[0][0] = mass * (3.0f * pow(radius, 3.0f) + pow(height, 2.0f)) / 12.0f; + inertia[1][1] = inertia[0][0]; + inertia[2][2] = mass * (pow(radius, 2.0f)) / 2.0f; + } + else + { + mass = density * (height * 2.0f * float(M_PI) * radius + 2.0f * float(M_PI) * pow(radius, 2.0f)); + inertia[0][0] = mass * (6.0f * pow(radius, 2.0f) + pow(height, 2.0f)) / 12.0f; + inertia[1][1] = inertia[0][0]; + inertia[2][2] = mass * pow(radius, 2.0f); + } +} + +// +// References +// ---------- +// +// Jonathan Blow, Atman J Binstock +// "How to find the inertia tensor (or other mass properties) of a 3D solid body represented by a triangle mesh" +// http://number-none.com/blow/inertia/bb_inertia.doc +// +// David Eberly +// "Polyhedral Mass Properties (Revisited)" +// http://www.geometrictools.com//LibPhysics/RigidBody/Wm4PolyhedralMassProperties.pdf +// +// The function is an implementation of the Blow and Binstock algorithm, +// extended for the case where the polygon is a surface (set parameter +// solid = False). +void Inertia::GetMassCenterInertiaPolyhedron(const vector<Vector3>& vertices, + const vector<Triangle>& triangles, + float density, bool solid, + float& mass, Vector3& center, InertiaMatrix &inertia) +{ + // 120 times the covariance matrix of the canonical tetrahedron + // (0,0,0),(1,0,0),(0,1,0),(0,0,1) + // integrate(integrate(integrate(z*z, x=0..1-y-z), y=0..1-z), z=0..1) = 1/120 + // integrate(integrate(integrate(y*z, x=0..1-y-z), y=0..1-z), z=0..1) = 1/60 + Matrix33 covariance_canonical( 2.0f, 1.0f, 1.0f, + 1.0f, 2.0f, 1.0f, + 1.0f, 1.0f, 2.0f ); + float covariance_correction = 1.0f/120.0f; + + vector<Matrix44> covariances; + vector<float> masses; + vector<Vector3> centers; + + // for each triangle + // construct a tetrahedron from triangle + (0,0,0) + // find its matrix, mass, and center (for density = 1, will be corrected at + // the end of the algorithm) + for (vector<Triangle>::const_iterator itr=triangles.begin(), end=triangles.end(); itr != end; ++itr) + { + // get vertices + const Vector3& vert0 = vertices[ (*itr)[0] ]; + const Vector3& vert1 = vertices[ (*itr)[1] ]; + const Vector3& vert2 = vertices[ (*itr)[2] ]; + + // construct a transform matrix that converts the canonical tetrahedron + // into (0,0,0),vert0,vert1,vert2 + Matrix44 transform_transposed(Matrix33( + vert0[0], vert0[1], vert0[2], + vert1[0], vert1[1], vert1[2], + vert2[0], vert2[1], vert2[2])); + Matrix44 transform = transform_transposed.Transpose(); + + // find the covariance matrix of the transformed tetrahedron/triangle + if (solid) + { + // we shall be needing the determinant more than once, so + // precalculate it + float determinant = transform.Determinant(); + + // C' = det(A) * A * C * A^T + covariances.push_back( transform * covariance_canonical * transform_transposed * determinant ); + // m = det(A) / 6.0 + masses.push_back(determinant / 6.0f); + // find center of gravity of the tetrahedron + centers.push_back( + Vector3(0.25f * (vert0[0] + vert1[0] + vert2[0]), + 0.25f * (vert0[1] + vert1[1] + vert2[1]), + 0.25f * (vert0[2] + vert1[2] + vert2[2])) + ); + } else { + // find center of gravity of the triangle + Vector3 com( (vert0[0] + vert1[0] + vert2[0]) / 3.0f, + (vert0[1] + vert1[1] + vert2[1]) / 3.0f, + (vert0[2] + vert1[2] + vert2[2]) / 3.0f); + centers.push_back( com ); + + // find mass of triangle + // mass is surface, which is half the norm of cross product + // of two edges + float calc_mass = ((vert1 - vert0) ^ (vert2 - vert0)).Magnitude() / 2.0f; + masses.push_back( calc_mass ); + + // find covariance at center of this triangle + // (this is approximate only as it replaces triangle with point mass + // TODO: find better way) + Matrix33 calc_c( com[0]*com[0], com[0]*com[1], com[0]*com[2], + com[1]*com[0], com[1]*com[1], com[1]*com[2], + com[2]*com[0], com[2]*com[1], com[2]*com[2]); + covariances.push_back( Matrix44(calc_c) ); + } + } + // accumulate the results + mass = std::accumulate(masses.begin(), masses.end(), 0.0f); + if (mass < 0.0001f) + { + // dimension is probably badly chosen + //raise ZeroDivisionError("mass is zero (consider calculating inertia with a lower dimension)") + //printf("WARNING: mass is zero"); + mass = 0.0f; + center = Vector3(); + inertia = InertiaMatrix::IDENTITY; + return; + } + + // weighed average of centers with masses + center = Vector3(); + for (size_t i = 0; i<masses.size(); ++i) + center += (centers[i] * (masses[i] / mass) ); + + // add covariances, and correct the values + Matrix44 total_covariance; + if (solid) + { + for (size_t i = 0; i<covariances.size(); ++i) + total_covariance *= covariances[i]; + } + + + // translate covariance to center of gravity: + // C' = C - m * ( x dx^T + dx x^T + dx dx^T ) + // with x the translation vector and dx the center of gravity + + Matrix44 translate_correction( + Matrix33( center[0]*center[0], center[0]*center[1], center[0]*center[2], + center[1]*center[0], center[1]*center[1], center[1]*center[2], + center[2]*center[0], center[2]*center[1], center[2]*center[2] + ) + ); + translate_correction *= mass; + + total_covariance = total_covariance - translate_correction; + + // convert covariance matrix into inertia tensor + float trace = total_covariance[0][0] + total_covariance[1][1] + total_covariance[2][2]; + Matrix44 trace_matrix; + trace_matrix[0][0] = trace_matrix[1][1] = trace_matrix[2][2] = trace; + + // correct for given density + inertia = InertiaMatrix((trace_matrix - total_covariance).GetRotation()) * density; + mass *= density; +} \ No newline at end of file diff --git a/src/NIF_IO.cpp b/src/NIF_IO.cpp index 96ec1b20..91d24d38 100644 --- a/src/NIF_IO.cpp +++ b/src/NIF_IO.cpp @@ -837,5 +837,22 @@ ostream & operator<<( ostream & out, Char8String const & val ) { return out; } +//InertiaMatrix +void NifStream( InertiaMatrix & val, istream& in, const NifInfo & info ) { + for (int c = 0; c < 3; ++c) { + for (int r = 0; r < 4; ++r) { + val[r][c] = ReadFloat( in ); + } + } +} + +void NifStream( InertiaMatrix const & val, ostream& out, const NifInfo & info ) { + for (int c = 0; c < 3; ++c) { + for (int r = 0; r < 4; ++r) { + WriteFloat( val[r][c], out ); + } + } +} + } \ No newline at end of file diff --git a/src/gen/InertiaMatrix.cpp b/src/gen/InertiaMatrix.cpp deleted file mode 100644 index 5fc8a753..00000000 --- a/src/gen/InertiaMatrix.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* Copyright (c) 2006, NIF File Format Library and Tools -All rights reserved. Please see niflib.h for license. */ - -//---THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT---// - -//To change this file, alter the niftools/docsys/gen_niflib.py Python script. - -#include "../../include/gen/InertiaMatrix.h" -using namespace Niflib; - -//Constructor -InertiaMatrix::InertiaMatrix() : m11(0.0f), m12(0.0f), m13(0.0f), m14(0.0f), m21(0.0f), m22(0.0f), m23(0.0f), m24(0.0f), m31(0.0f), m32(0.0f), m33(0.0f), m34(0.0f) {}; - -//Copy Constructor -InertiaMatrix::InertiaMatrix( const InertiaMatrix & src ) { - *this = src; -}; - -//Copy Operator -InertiaMatrix & InertiaMatrix::operator=( const InertiaMatrix & src ) { - this->m11 = src.m11; - this->m12 = src.m12; - this->m13 = src.m13; - this->m14 = src.m14; - this->m21 = src.m21; - this->m22 = src.m22; - this->m23 = src.m23; - this->m24 = src.m24; - this->m31 = src.m31; - this->m32 = src.m32; - this->m33 = src.m33; - this->m34 = src.m34; - return *this; -}; - -//Destructor -InertiaMatrix::~InertiaMatrix() {}; diff --git a/src/nif_math.cpp b/src/nif_math.cpp index 9ee0ca01..d368a2f2 100644 --- a/src/nif_math.cpp +++ b/src/nif_math.cpp @@ -19,6 +19,11 @@ const Matrix33 Matrix33::IDENTITY( 1.0f, 0.0f, 0.0f, const Matrix22 Matrix22::IDENTITY( 1.0f, 0.0f, 0.0f, 1.0f ); +const InertiaMatrix InertiaMatrix::IDENTITY( + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f ); + /* TexCoord Methods * */ @@ -124,6 +129,24 @@ bool Vector3::operator!=( const Vector3 & rh) const { return true; } +float & Vector3::operator[](int n) { + switch (n) { + case 0: return x; break; + case 1: return y; break; + case 2: return z; break; + default: throw std::out_of_range("Index out of range for Vector3"); + }; +} + +float Vector3::operator[](int n) const { + switch (n) { + case 0: return x; break; + case 1: return y; break; + case 2: return z; break; + default: throw std::out_of_range("Index out of range for Vector3"); + }; +} + float Vector3::DotProduct( const Vector3 & rh) const { return x * rh.x + y * rh.y + z * rh.z; } @@ -475,6 +498,19 @@ Matrix44 & Matrix44::operator+=( const Matrix44 & rh ) { return *this; } +Matrix44 Matrix44::operator-( const Matrix44 & rh ) const { + return Matrix44(*this) -= rh; +} + +Matrix44 & Matrix44::operator-=( const Matrix44 & rh ) { + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + (*this)[i][j] -= rh[i][j]; + } + } + return *this; +} + Matrix44 & Matrix44::operator=( const Matrix44 & rh ) { memcpy(rows, rh.rows, sizeof(Float4) * 4); return *this; @@ -623,6 +659,157 @@ Matrix33 Quaternion::AsMatrix() { return m; } + +/* +* InertiaMatrix Methods +*/ + +InertiaMatrix::InertiaMatrix() { + *this = InertiaMatrix::IDENTITY; +} + +InertiaMatrix::InertiaMatrix( const Matrix33 & r ) { + //Set this matrix with rotate and translate information + InertiaMatrix & m = *this; + m[0][0] = r[0][0]; m[0][1] = r[0][1]; m[0][2] = r[0][2]; m[0][3] = 0.0f; + m[1][0] = r[1][0]; m[1][1] = r[1][1]; m[1][2] = r[1][2]; m[1][3] = 0.0f; + m[2][0] = r[2][0]; m[2][1] = r[2][1]; m[2][2] = r[2][2]; m[2][3] = 0.0f; +} + +InertiaMatrix InertiaMatrix::operator*( const InertiaMatrix & rh ) const { + return InertiaMatrix(*this) *= rh; +} + +InertiaMatrix & InertiaMatrix::operator*=( const InertiaMatrix & rh ) { + InertiaMatrix r; + InertiaMatrix & lh = *this; + float t; + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 4; j++) { + t = 0.0f; + for (int k = 0; k < 4; k++) { + t += lh[i][k] * rh[k][j]; + } + r[i][j] = t; + } + } + + *this = r; + return *this; +} + +InertiaMatrix InertiaMatrix::operator*( float rh ) const { + return InertiaMatrix(*this) *= rh; +} + +InertiaMatrix & InertiaMatrix::operator*=( float rh ) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 4; j++) { + (*this)[i][j] *= rh; + } + } + return *this; +} + +Vector3 InertiaMatrix::operator*( const Vector3 & rh ) const { + const InertiaMatrix & t = *this; + Vector3 v; + //Multiply, ignoring w + v.x = rh.x * t[0][0] + rh.y * t[1][0] + rh.z * t[2][0]; + v.y = rh.x * t[0][1] + rh.y * t[1][1] + rh.z * t[2][1]; + v.z = rh.x * t[0][2] + rh.y * t[1][2] + rh.z * t[2][2]; + return v; +} + +InertiaMatrix InertiaMatrix::operator+( const InertiaMatrix & rh ) const { + return InertiaMatrix(*this) += rh; +} + +InertiaMatrix & InertiaMatrix::operator+=( const InertiaMatrix & rh ) { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 4; j++) { + (*this)[i][j] += rh[i][j]; + } + } + return *this; +} + +InertiaMatrix & InertiaMatrix::operator=( const InertiaMatrix & rh ) { + memcpy(rows, rh.rows, sizeof(Float4) * 4); + return *this; +} + +bool InertiaMatrix::operator==( const InertiaMatrix & rh ) const { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 4; j++) { + if ( (*this)[i][j] != rh[i][j] ) + return false; + } + } + return true; +} + +bool InertiaMatrix::operator!=( const InertiaMatrix & rh ) const { + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 4; j++) { + if ( (*this)[i][j] != rh[i][j] ) + return true; + } + } + return false; +} + +InertiaMatrix InertiaMatrix::Transpose() const { + const InertiaMatrix & t = *this; + return InertiaMatrix( t[0][0], t[1][0], t[2][0], t[3][0], + t[0][1], t[1][1], t[2][1], t[3][1], + t[0][2], t[1][2], t[2][2], t[3][2]); +} + +Matrix33 InertiaMatrix::Submatrix( int skip_r, int skip_c ) const { + Matrix33 sub; + int i = 0, j = 0; + for (int r = 0; r < 3; r++) { + if (r == skip_r) + continue; + for (int c = 0; c < 4; c++) { + if (c == skip_c) + continue; + sub[i][j] = (*this)[r][c]; + j++; + } + i++; + j = 0; + } + return sub; +} + +float InertiaMatrix::Adjoint( int skip_r, int skip_c ) const { + Matrix33 sub = Submatrix( skip_r, skip_c ); + return pow(-1.0f, float(skip_r + skip_c)) * sub.Determinant(); +} + +InertiaMatrix InertiaMatrix::Inverse() const { + InertiaMatrix result; + + float det = Determinant(); + for (int r = 0; r < 3; r++) { + for (int c = 0; c < 4; c++) { + result[c][r] = Adjoint(r, c) / det; + } + } + + return result; +} + +float InertiaMatrix::Determinant() const { + const InertiaMatrix & t = *this; + return t[0][0] * Submatrix(0, 0).Determinant() + - t[0][1] * Submatrix(0, 1).Determinant() + + t[0][2] * Submatrix(0, 2).Determinant() + - t[0][3] * Submatrix(0, 3).Determinant(); +} + /* * ostream functions for printing with cout */ @@ -686,4 +873,13 @@ ostream & operator<<( ostream & out, Color4 const & val ) { ostream & operator<<( ostream & out, Quaternion const & val ) { return out << "[" << setw(6) << val.w << ",(" << setw(6) << val.x << "," << setw(6) << val.y << "," << setw(6) << val.z << ")]"; } + +ostream & operator<<( ostream & out, InertiaMatrix const & val ) { + out << endl + << " |" << setw(6) << val[0][0] << "," << setw(6) << val[0][1] << "," << setw(6) << val[0][2] << "," << setw(6) << val[0][3] << " |" << endl + << " |" << setw(6) << val[1][0] << "," << setw(6) << val[1][1] << "," << setw(6) << val[1][2] << "," << setw(6) << val[1][3] << " |" << endl + << " |" << setw(6) << val[2][0] << "," << setw(6) << val[2][1] << "," << setw(6) << val[2][2] << "," << setw(6) << val[2][3] << " |"; + return out; +} + } diff --git a/src/obj/NiMorphData.cpp b/src/obj/NiMorphData.cpp index ef544290..09322294 100644 --- a/src/obj/NiMorphData.cpp +++ b/src/obj/NiMorphData.cpp @@ -20,7 +20,7 @@ using namespace Niflib; //Definition of TYPE constant const Type NiMorphData::TYPE("NiMorphData", &NiObject::TYPE ); -NiMorphData::NiMorphData() : numMorphs((unsigned int)0), numVertices((unsigned int)0), relativeTargets(1) { +NiMorphData::NiMorphData() : numMorphs((unsigned int)0), numVertices((unsigned int)0), relativeTargets((byte)1) { //--BEGIN CONSTRUCTOR CUSTOM CODE--// //--END CUSTOM CODE--// } diff --git a/src/obj/bhkBoxShape.cpp b/src/obj/bhkBoxShape.cpp index ee085848..86eb94a2 100644 --- a/src/obj/bhkBoxShape.cpp +++ b/src/obj/bhkBoxShape.cpp @@ -8,6 +8,7 @@ All rights reserved. Please see niflib.h for license. */ //-----------------------------------NOTICE----------------------------------// //--BEGIN FILE HEAD CUSTOM CODE--// +#include "../../include/Inertia.h" //--END CUSTOM CODE--// #include "../../include/FixLink.h" @@ -121,4 +122,9 @@ void bhkBoxShape::SetDimensions(const Vector3 &value) { minimumSize = min( min(value.x, value.y), value.z ); } +void bhkBoxShape::CalcMassCenterInertia( float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia ) +{ + center = Vector3(0,0,0); + Inertia::GetMassInertiaBox( dimensions * 2.0f, density, solid, mass, inertia ); +} //--END CUSTOM CODE--// diff --git a/src/obj/bhkBvTreeShape.cpp b/src/obj/bhkBvTreeShape.cpp index b0741761..d115e160 100644 --- a/src/obj/bhkBvTreeShape.cpp +++ b/src/obj/bhkBvTreeShape.cpp @@ -86,5 +86,12 @@ std::list<NiObjectRef> bhkBvTreeShape::GetRefs() const { return refs; } +void bhkBvTreeShape::CalcMassCenterInertia( float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia ) +{ + center = Vector3(0,0,0); + mass = 0.0f; + inertia = InertiaMatrix::IDENTITY; +} + //--BEGIN MISC CUSTOM CODE--// //--END CUSTOM CODE--// diff --git a/src/obj/bhkCapsuleShape.cpp b/src/obj/bhkCapsuleShape.cpp index eb27e286..66d6face 100644 --- a/src/obj/bhkCapsuleShape.cpp +++ b/src/obj/bhkCapsuleShape.cpp @@ -8,6 +8,7 @@ All rights reserved. Please see niflib.h for license. */ //-----------------------------------NOTICE----------------------------------// //--BEGIN FILE HEAD CUSTOM CODE--// +#include "../../include/Inertia.h" //--END CUSTOM CODE--// #include "../../include/FixLink.h" @@ -158,4 +159,19 @@ void bhkCapsuleShape::SetRadius2( float value ) { radius2 = value; } +/*! Helper routine for calculating mass properties. +* \param[in] density Uniform density of object +* \param[in] solid Determines whether the object is assumed to be solid or not +* \param[out] mass Calculated mass of the object +* \param[out] center Center of mass +* \param[out] inertia Mass Inertia Tensor +* \return Return mass, center, and inertia tensor. +*/ +void bhkCapsuleShape::CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia) +{ + center = Vector3(); + float height = (secondPoint - firstPoint).Magnitude(); + Inertia::GetMassInertiaCapsule(radius, height, density, solid, mass, inertia); +} + //--END CUSTOM CODE--// diff --git a/src/obj/bhkConvexShape.cpp b/src/obj/bhkConvexShape.cpp index c2e93ef4..b762579b 100644 --- a/src/obj/bhkConvexShape.cpp +++ b/src/obj/bhkConvexShape.cpp @@ -87,4 +87,12 @@ std::list<NiObjectRef> bhkConvexShape::GetRefs() const { } //--BEGIN MISC CUSTOM CODE--// + +void bhkConvexShape::CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia) +{ + center = Vector3(0,0,0); + mass = 0.0f; + inertia = InertiaMatrix::IDENTITY; +} + //--END CUSTOM CODE--// diff --git a/src/obj/bhkConvexTransformShape.cpp b/src/obj/bhkConvexTransformShape.cpp index 2bd655b8..2cfb3476 100644 --- a/src/obj/bhkConvexTransformShape.cpp +++ b/src/obj/bhkConvexTransformShape.cpp @@ -87,4 +87,12 @@ std::list<NiObjectRef> bhkConvexTransformShape::GetRefs() const { } //--BEGIN MISC CUSTOM CODE--// +void bhkConvexTransformShape::CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia) +{ + center = Vector3(0,0,0); + mass = 0.0f; + inertia = InertiaMatrix::IDENTITY; +} + + //--END CUSTOM CODE--// diff --git a/src/obj/bhkConvexVerticesShape.cpp b/src/obj/bhkConvexVerticesShape.cpp index 4b242b17..d1dbcd58 100644 --- a/src/obj/bhkConvexVerticesShape.cpp +++ b/src/obj/bhkConvexVerticesShape.cpp @@ -8,6 +8,8 @@ All rights reserved. Please see niflib.h for license. */ //-----------------------------------NOTICE----------------------------------// //--BEGIN FILE HEAD CUSTOM CODE--// +#include "../../include/nifqhull.h" +#include "../../include/Inertia.h" //--END CUSTOM CODE--// #include "../../include/FixLink.h" @@ -243,5 +245,13 @@ void bhkConvexVerticesShape::SetNormalsAndDist(const vector<Vector4>& value) normals = value; } - +void bhkConvexVerticesShape::CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia) +{ + center = Vector3(0,0,0); + mass = 0.0f; + inertia = InertiaMatrix::IDENTITY; + vector<Vector3> verts = GetVertices(); + vector<Triangle> tris = NifQHull::compute_convex_hull(verts); + Inertia::GetMassCenterInertiaPolyhedron(verts, tris, density, solid, mass, center, inertia); +} //--END CUSTOM CODE--// diff --git a/src/obj/bhkListShape.cpp b/src/obj/bhkListShape.cpp index ce10aeac..b01268fc 100644 --- a/src/obj/bhkListShape.cpp +++ b/src/obj/bhkListShape.cpp @@ -198,4 +198,29 @@ void bhkListShape::SetSubShapes(const vector<Ref<bhkShape > >& shapes) { unknownInts.resize(subShapes.size(), 0); } +void bhkListShape::CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia) +{ + center = Vector3(0,0,0); + mass = 0.0f; + inertia = InertiaMatrix::IDENTITY; + + vector<float> masses; + vector<Vector3> centers; + vector<InertiaMatrix> inertias; + for (vector<bhkShapeRef>::iterator itr = subShapes.begin(); itr != subShapes.end(); ++itr) + { + float m; Vector3 c; InertiaMatrix i; + (*itr)->CalcMassCenterInertia(density, solid, m, c, i); + masses.push_back(m); + centers.push_back(c); + inertias.push_back(i); + mass += m; + } + + // TODO: doubt this inertia calculation is even remotely close + for (size_t i=0; i < masses.size(); ++i) { + center += centers[i] * (masses[i] / mass); + inertia *= inertias[i]; + } +} //--END CUSTOM CODE--// diff --git a/src/obj/bhkMoppBvTreeShape.cpp b/src/obj/bhkMoppBvTreeShape.cpp index 2df51bd5..189b17c7 100644 --- a/src/obj/bhkMoppBvTreeShape.cpp +++ b/src/obj/bhkMoppBvTreeShape.cpp @@ -200,4 +200,14 @@ void bhkMoppBvTreeShape::SetMoppScale( float value ) { scale = value; } +void bhkMoppBvTreeShape::CalcMassCenterInertia( float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia ) +{ + center = Vector3(0,0,0); + mass = 0.0f; + inertia = InertiaMatrix::IDENTITY; + + if (shape != NULL) + shape->CalcMassCenterInertia(density, solid, mass, center, inertia); +} + //--END CUSTOM CODE--// diff --git a/src/obj/bhkMultiSphereShape.cpp b/src/obj/bhkMultiSphereShape.cpp index eb8bea24..da68b33f 100644 --- a/src/obj/bhkMultiSphereShape.cpp +++ b/src/obj/bhkMultiSphereShape.cpp @@ -126,4 +126,11 @@ void bhkMultiSphereShape::SetSpheres( const vector<SphereBV >& value ) { spheres = value; } +void bhkMultiSphereShape::CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia) +{ + // TODO: Calculate this properly + center = Vector3(0,0,0); + mass = 0.0f; + inertia = InertiaMatrix::IDENTITY; +} //--END CUSTOM CODE--// diff --git a/src/obj/bhkNiTriStripsShape.cpp b/src/obj/bhkNiTriStripsShape.cpp index b12d2f21..6e0aa018 100644 --- a/src/obj/bhkNiTriStripsShape.cpp +++ b/src/obj/bhkNiTriStripsShape.cpp @@ -8,6 +8,7 @@ All rights reserved. Please see niflib.h for license. */ //-----------------------------------NOTICE----------------------------------// //--BEGIN FILE HEAD CUSTOM CODE--// +#include "../../include/Inertia.h" //--END CUSTOM CODE--// #include "../../include/FixLink.h" @@ -257,4 +258,24 @@ void bhkNiTriStripsShape::SetOblivionFilter( unsigned int index, unsigned char f dataLayers[index].colFilter = filter; } +void bhkNiTriStripsShape::CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia) +{ + center = Vector3(0,0,0); + mass = 0.0f; + inertia = InertiaMatrix::IDENTITY; + + vector<Vector3> verts; + vector<Triangle> tris; + for ( vector<NiTriStripsDataRef>::iterator itr = stripsData.begin(); itr != stripsData.end(); ++itr ) + { + size_t nv = verts.size(), nt = tris.size(); + vector<Vector3> v = (*itr)->GetVertices(); + vector<Triangle> t = (*itr)->GetTriangles(); + for (size_t i=0; i<nv; ++i) + verts.push_back( v[i] ); + for (size_t i=0; i<nt; ++i) + tris.push_back( Triangle(t[i][0] + nt, t[i][1] + nt, t[i][2] + nt) ); + } + Inertia::GetMassCenterInertiaPolyhedron(verts, tris, density, solid, mass, center, inertia); +} //--END CUSTOM CODE--// diff --git a/src/obj/bhkPackedNiTriStripsShape.cpp b/src/obj/bhkPackedNiTriStripsShape.cpp index 4e488b13..a6791005 100644 --- a/src/obj/bhkPackedNiTriStripsShape.cpp +++ b/src/obj/bhkPackedNiTriStripsShape.cpp @@ -8,6 +8,7 @@ All rights reserved. Please see niflib.h for license. */ //-----------------------------------NOTICE----------------------------------// //--BEGIN FILE HEAD CUSTOM CODE--// +#include "../../include/Inertia.h" //--END CUSTOM CODE--// #include "../../include/FixLink.h" @@ -181,5 +182,17 @@ void bhkPackedNiTriStripsShape::SetSubShapes( vector<OblivionSubShape>& value ) subShapes = value; } - +void bhkPackedNiTriStripsShape::CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia) +{ + center = Vector3(0,0,0); + mass = 0.0f; + inertia = InertiaMatrix::IDENTITY; + + if (data != NULL) + { + vector<Vector3> verts = data->GetVertices(); + vector<Triangle> tris = data->GetTriangles(); + Inertia::GetMassCenterInertiaPolyhedron(verts, tris, density, solid, mass, center, inertia); + } +} //--END CUSTOM CODE--// diff --git a/src/obj/bhkRigidBody.cpp b/src/obj/bhkRigidBody.cpp index de3b84a7..f89c8abb 100644 --- a/src/obj/bhkRigidBody.cpp +++ b/src/obj/bhkRigidBody.cpp @@ -8,6 +8,7 @@ All rights reserved. Please see niflib.h for license. */ //-----------------------------------NOTICE----------------------------------// //--BEGIN FILE HEAD CUSTOM CODE--// +#include "../../include/obj/bhkShape.h" //--END CUSTOM CODE--// #include "../../include/FixLink.h" @@ -15,7 +16,6 @@ All rights reserved. Please see niflib.h for license. */ #include "../../include/NIF_IO.h" #include "../../include/obj/bhkRigidBody.h" #include "../../include/gen/QuaternionXYZW.h" -#include "../../include/gen/InertiaMatrix.h" #include "../../include/obj/bhkConstraint.h" using namespace Niflib; @@ -69,18 +69,7 @@ void bhkRigidBody::Read( istream& in, list<unsigned int> & link_stack, const Nif NifStream( rotation.w, in, info ); NifStream( linearVelocity, in, info ); NifStream( angularVelocity, in, info ); - NifStream( inertia.m11, in, info ); - NifStream( inertia.m12, in, info ); - NifStream( inertia.m13, in, info ); - NifStream( inertia.m14, in, info ); - NifStream( inertia.m21, in, info ); - NifStream( inertia.m22, in, info ); - NifStream( inertia.m23, in, info ); - NifStream( inertia.m24, in, info ); - NifStream( inertia.m31, in, info ); - NifStream( inertia.m32, in, info ); - NifStream( inertia.m33, in, info ); - NifStream( inertia.m34, in, info ); + NifStream( inertia, in, info ); NifStream( center, in, info ); NifStream( mass, in, info ); NifStream( linearDamping, in, info ); @@ -138,18 +127,7 @@ void bhkRigidBody::Write( ostream& out, const map<NiObjectRef,unsigned int> & li NifStream( rotation.w, out, info ); NifStream( linearVelocity, out, info ); NifStream( angularVelocity, out, info ); - NifStream( inertia.m11, out, info ); - NifStream( inertia.m12, out, info ); - NifStream( inertia.m13, out, info ); - NifStream( inertia.m14, out, info ); - NifStream( inertia.m21, out, info ); - NifStream( inertia.m22, out, info ); - NifStream( inertia.m23, out, info ); - NifStream( inertia.m24, out, info ); - NifStream( inertia.m31, out, info ); - NifStream( inertia.m32, out, info ); - NifStream( inertia.m33, out, info ); - NifStream( inertia.m34, out, info ); + NifStream( inertia, out, info ); NifStream( center, out, info ); NifStream( mass, out, info ); NifStream( linearDamping, out, info ); @@ -242,18 +220,7 @@ std::string bhkRigidBody::asString( bool verbose ) const { out << " w: " << rotation.w << endl; out << " Linear Velocity: " << linearVelocity << endl; out << " Angular Velocity: " << angularVelocity << endl; - out << " m11: " << inertia.m11 << endl; - out << " m12: " << inertia.m12 << endl; - out << " m13: " << inertia.m13 << endl; - out << " m14: " << inertia.m14 << endl; - out << " m21: " << inertia.m21 << endl; - out << " m22: " << inertia.m22 << endl; - out << " m23: " << inertia.m23 << endl; - out << " m24: " << inertia.m24 << endl; - out << " m31: " << inertia.m31 << endl; - out << " m32: " << inertia.m32 << endl; - out << " m33: " << inertia.m33 << endl; - out << " m34: " << inertia.m34 << endl; + out << " Inertia: " << inertia << endl; out << " Center: " << center << endl; out << " Mass: " << mass << endl; out << " Linear Damping: " << linearDamping << endl; @@ -355,36 +322,12 @@ void bhkRigidBody::SetAngularVelocity( const Vector4 & value ) { angularVelocity = value; } -array<12,float> bhkRigidBody::GetInertia() const { - array<12, float> result; - result[0] = inertia.m11; - result[1] = inertia.m12; - result[2] = inertia.m13; - result[3] = inertia.m14; - result[4] = inertia.m21; - result[5] = inertia.m22; - result[6] = inertia.m23; - result[7] = inertia.m24; - result[8] = inertia.m31; - result[9] = inertia.m32; - result[10] = inertia.m33; - result[11] = inertia.m34; - return result; -} - -void bhkRigidBody::SetInertia( const array<12,float>& value ) { - inertia.m11 = value[0]; - inertia.m12 = value[1]; - inertia.m13 = value[2]; - inertia.m14 = value[3]; - inertia.m21 = value[4]; - inertia.m22 = value[5]; - inertia.m23 = value[6]; - inertia.m24 = value[7]; - inertia.m31 = value[8]; - inertia.m32 = value[9]; - inertia.m33 = value[10]; - inertia.m34 = value[11]; +InertiaMatrix bhkRigidBody::GetInertia() const { + return inertia; +} + +void bhkRigidBody::SetInertia( const InertiaMatrix& value ) { + inertia = value; } Vector4 bhkRigidBody::GetCenter() const { @@ -491,4 +434,45 @@ void bhkRigidBody::SetSolverDeactivation( const SolverDeactivation & value ) { solverDeactivation = value; } + + +// Apply scale factor <scale> on data. +void bhkRigidBody::ApplyScale(float scale) +{ + // apply scale on transform + translation *= scale; + + // apply scale on center of gravity + center *= scale; + + // apply scale on inertia tensor + inertia *= pow(scale, 2.0f); + + //# apply scale on all blocks down the hierarchy + //ApplyScale(scale) +} + +void bhkRigidBody::UpdateMassCenterInertia(float density, bool solid, float mass) +{ + // Look at all the objects under this rigid body and update the mass + // center of gravity, and inertia tensor accordingly. If the C{mass} parameter + // is given then the C{density} argument is ignored. + + if (mass != 0.0f) + density = 1.0f; + + if (shape != NULL) + { + Vector3 com; + shape->CalcMassCenterInertia(density, solid, this->mass, com, inertia); + center = com; + if (mass != 0.0f) + { + float mass_correction = (this->mass != 0.0f) ? mass / this->mass : 1.0f; + this->mass = mass; + inertia *= mass_correction; + } + } +} + //--END CUSTOM CODE--// diff --git a/src/obj/bhkShape.cpp b/src/obj/bhkShape.cpp index 468065a7..fdfac180 100644 --- a/src/obj/bhkShape.cpp +++ b/src/obj/bhkShape.cpp @@ -87,4 +87,11 @@ std::list<NiObjectRef> bhkShape::GetRefs() const { } //--BEGIN MISC CUSTOM CODE--// + +void bhkShape::CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia) +{ + center = Vector3(0,0,0); + mass = 0.0f; + inertia = InertiaMatrix::IDENTITY; +} //--END CUSTOM CODE--// diff --git a/src/obj/bhkSphereRepShape.cpp b/src/obj/bhkSphereRepShape.cpp index 0e7bc31e..3bc83d8d 100644 --- a/src/obj/bhkSphereRepShape.cpp +++ b/src/obj/bhkSphereRepShape.cpp @@ -8,6 +8,7 @@ All rights reserved. Please see niflib.h for license. */ //-----------------------------------NOTICE----------------------------------// //--BEGIN FILE HEAD CUSTOM CODE--// +#include "../../include/Inertia.h" //--END CUSTOM CODE--// #include "../../include/FixLink.h" @@ -110,5 +111,12 @@ void bhkSphereRepShape::SetRadius( float value ) { radius = value; } +void bhkSphereRepShape::CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia) +{ + center = Vector3(0,0,0); + mass = 0.0f; + inertia = InertiaMatrix::IDENTITY; + Inertia::GetMassInertiaSphere(radius, density, solid, mass, inertia); +} //--END CUSTOM CODE--// diff --git a/src/obj/bhkSphereShape.cpp b/src/obj/bhkSphereShape.cpp index 61a06172..c0c378e1 100644 --- a/src/obj/bhkSphereShape.cpp +++ b/src/obj/bhkSphereShape.cpp @@ -8,6 +8,7 @@ All rights reserved. Please see niflib.h for license. */ //-----------------------------------NOTICE----------------------------------// //--BEGIN FILE HEAD CUSTOM CODE--// +#include "../../include/Inertia.h" //--END CUSTOM CODE--// #include "../../include/FixLink.h" @@ -96,4 +97,11 @@ void bhkSphereShape::SetRadius( float value ) { radius = value; } +void bhkSphereShape::CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia) +{ + center = Vector3(0,0,0); + mass = 0.0f; + inertia = InertiaMatrix::IDENTITY; + Inertia::GetMassInertiaSphere(radius, density, solid, mass, inertia); +} //--END CUSTOM CODE--// diff --git a/src/obj/bhkTransformShape.cpp b/src/obj/bhkTransformShape.cpp index f98afa07..33fba51a 100644 --- a/src/obj/bhkTransformShape.cpp +++ b/src/obj/bhkTransformShape.cpp @@ -156,4 +156,20 @@ void bhkTransformShape::SetTransform(const Matrix44 & value ) { transform = value; } +void bhkTransformShape::CalcMassCenterInertia(float density, bool solid, float &mass, Vector3 ¢er, InertiaMatrix& inertia) +{ + center = transform.GetTranslation(); + mass = 0.0f; + inertia = InertiaMatrix::IDENTITY; + if (shape != NULL) + { + Matrix44 transform_transposed = transform.Transpose(); + shape->CalcMassCenterInertia(density, solid, mass, center, inertia); + center = transform * center; + + Matrix44 tm(inertia.Submatrix(0, 0)); + Matrix44 im = transform_transposed * tm * transform; + inertia = InertiaMatrix(im.GetRotation()); + } +} //--END CUSTOM CODE--// -- GitLab