Please see HfFluidDemo.cpp for examples of how to use the height field fluid along with buoyant collision shapes. The implementation is still lacking in my ways: 1) Need to complete more collision algorithms for buoyant collision shapes 2) Support compound buoyant shapes 3) The buoyancy model isn't that great 4) Fluid volume can be lost over time
225 lines
6.2 KiB
C++
225 lines
6.2 KiB
C++
#ifndef __HFFLUID_H
|
|
#define __HFFLUID_H
|
|
|
|
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
|
|
#include "BulletCollision/CollisionShapes/btTriangleCallback.h"
|
|
|
|
class btPersistentManifold;
|
|
class btManifoldResult;
|
|
|
|
// FIX AABB calculation for whole btHfFluid shape
|
|
// Fix flags and fill ratio
|
|
// -> Figure out the constants used in flags and fill ratio code
|
|
// Fix volume removal
|
|
// add buoyant convex vs. convex / concave
|
|
// add buoyant concave support (try bunny model)
|
|
|
|
class btHfFluid : public btCollisionObject
|
|
{
|
|
public:
|
|
btHfFluid (btScalar gridCellWidth, int numNodesWidth, int numNodesLength);
|
|
|
|
~btHfFluid ();
|
|
|
|
void predictMotion(btScalar dt);
|
|
|
|
/* Prep does some initial setup of the height field fluid.
|
|
* You should call this at initialization time.
|
|
*/
|
|
void prep ();
|
|
|
|
static const btHfFluid* upcast(const btCollisionObject* colObj)
|
|
{
|
|
if (colObj->getInternalType()==CO_HF_FLUID)
|
|
return (const btHfFluid*)colObj;
|
|
return 0;
|
|
}
|
|
static btHfFluid* upcast(btCollisionObject* colObj)
|
|
{
|
|
if (colObj->getInternalType()==CO_HF_FLUID)
|
|
return (btHfFluid*)colObj;
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// ::btCollisionObject
|
|
//
|
|
|
|
virtual void getAabb(btVector3& aabbMin,btVector3& aabbMax) const
|
|
{
|
|
aabbMin = m_aabbMin;
|
|
aabbMax = m_aabbMax;
|
|
}
|
|
|
|
int getNumNodesWidth () const { return m_numNodesWidth; }
|
|
int getNumNodesLength () const { return m_numNodesLength; }
|
|
|
|
btScalar getGridCellWidth () const { return m_gridCellWidth; }
|
|
btScalar widthPos (int i) const;
|
|
btScalar lengthPos (int j) const;
|
|
|
|
int arrayIndex (int i, int j) const;
|
|
int arrayIndex (btScalar i, btScalar j) const;
|
|
int arrayIndex (unsigned int i, unsigned int j) const;
|
|
const btScalar* getHeightArray () const;
|
|
const btScalar* getGroundArray () const;
|
|
const btScalar* getEtaArray () const;
|
|
const btScalar* getVelocityUArray () const;
|
|
const btScalar* getVelocityVArray () const;
|
|
const bool* getFlagsArray () const;
|
|
|
|
void setFluidHeight (int x, int y, btScalar height);
|
|
void setFluidHeight (int index, btScalar height);
|
|
|
|
void addFluidHeight (int x, int y, btScalar height);
|
|
void addDisplaced (int i, int j, btScalar r);
|
|
|
|
void getAabbForColumn (int x, int y, btVector3& aabbMin, btVector3& aabbMax);
|
|
|
|
btScalar* getHeightArray ();
|
|
btScalar* getGroundArray ();
|
|
btScalar* getEtaArray ();
|
|
btScalar* getVelocityUArray ();
|
|
btScalar* getVelocityVArray ();
|
|
bool* getFlagsArray ();
|
|
|
|
void foreachGroundTriangle(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax);
|
|
class btHfFluidColumnCallback
|
|
{
|
|
public:
|
|
btHfFluidColumnCallback () {}
|
|
|
|
virtual ~btHfFluidColumnCallback () {}
|
|
|
|
virtual bool processColumn (btHfFluid* fluid, int w, int l)
|
|
{
|
|
return true; // keep going
|
|
}
|
|
};
|
|
|
|
void foreachFluidColumn (btHfFluidColumnCallback* callback, const btVector3& aabbMin, const btVector3& aabbMax);
|
|
|
|
void foreachSurfaceTriangle (btTriangleCallback* callback, const btVector3& aabbMin, const btVector3& aabbMax);
|
|
protected:
|
|
int m_numNodesWidth;
|
|
int m_numNodesLength;
|
|
|
|
btScalar m_gridCellWidth;
|
|
btScalar m_gridWidth;
|
|
btScalar m_gridLength;
|
|
|
|
btScalar m_gridCellWidthInv;
|
|
|
|
btVector3 m_aabbMin;
|
|
btVector3 m_aabbMax;
|
|
|
|
void setGridDimensions (btScalar gridCellWidth,
|
|
int numNodesWidth, int numNodesLength);
|
|
|
|
btScalar bilinearInterpolate (const btScalar* array, btScalar i, btScalar j);
|
|
|
|
btScalar advect (const btScalar* array, btScalar i, btScalar j, btScalar di, btScalar dj, btScalar dt);
|
|
|
|
void advectEta (btScalar dt);
|
|
void updateHeight (btScalar dt);
|
|
|
|
void advectVelocityU (btScalar dt);
|
|
void advectVelocityV (btScalar dt);
|
|
void updateVelocity (btScalar dt);
|
|
|
|
void transferDisplaced (btScalar dt);
|
|
|
|
void setReflectBoundaryLeft ();
|
|
void setReflectBoundaryRight ();
|
|
void setReflectBoundaryTop ();
|
|
void setReflectBoundaryBottom ();
|
|
|
|
void setAbsorbBoundaryLeft (btScalar dt);
|
|
void setAbsorbBoundaryRight (btScalar dt);
|
|
void setAbsorbBoundaryTop (btScalar dt);
|
|
void setAbsorbBoundaryBottom (btScalar dt);
|
|
|
|
void computeFlagsAndFillRatio ();
|
|
btScalar computeHmin (int i, int j);
|
|
btScalar computeHmax (int i, int j);
|
|
btScalar computeEtaMax (int i, int j);
|
|
|
|
void allocateArrays ();
|
|
|
|
void debugTests ();
|
|
|
|
btScalar* m_temp; // temp
|
|
int m_heightIndex;
|
|
btScalar* m_height[2];
|
|
btScalar* m_ground;
|
|
btScalar* m_eta; // height - ground
|
|
btScalar* m_u[2];
|
|
btScalar* m_v[2];
|
|
int m_rIndex;
|
|
btScalar* m_r[2];
|
|
int m_velocityIndex;
|
|
bool* m_flags;
|
|
btScalar* m_fillRatio;
|
|
|
|
// tweakables
|
|
btScalar m_globalVelocityU;
|
|
btScalar m_globalVelocityV;
|
|
btScalar m_gravity;
|
|
btScalar m_volumeDisplacementScale;
|
|
btScalar m_horizontalVelocityScale;
|
|
|
|
btScalar m_epsHeight;
|
|
btScalar m_epsEta;
|
|
public:
|
|
// You can enforce a global velocity at the surface of the fluid
|
|
// default: 0.0 and 0.0
|
|
void setGlobaVelocity (btScalar globalVelocityU, btScalar globalVelocityV);
|
|
void getGlobalVelocity (btScalar& globalVelocityU, btScalar& globalVelocityV) const;
|
|
|
|
// Control force of gravity, should match physics world
|
|
// default: -10.0
|
|
void setGravity (btScalar gravity);
|
|
btScalar getGravity () const;
|
|
|
|
// When a body is submerged into the fluid, the displaced fluid
|
|
// is spread to adjacent cells. You can control the percentage of this
|
|
// by setting this value between 0.0 and 1.0
|
|
// default: 0.5
|
|
void setVolumeDisplacementScale (btScalar volumeDisplacementScale);
|
|
btScalar getVolumeDisplacementScale () const;
|
|
|
|
// The horizontal velocity of the fluid can influence bodies submerged
|
|
// in the fluid. You can control how much influence by setting this
|
|
// between 0.0 and 1.0
|
|
// default: 0.5
|
|
void setHorizontalVelocityScale (btScalar horizontalVelocityScale);
|
|
btScalar getHorizontalVelocityScale () const;
|
|
};
|
|
|
|
class btRigidBody;
|
|
class btIDebugDraw;
|
|
class btHfFluidBuoyantConvexShape;
|
|
|
|
class btHfFluidColumnRigidBodyCallback : public btHfFluid::btHfFluidColumnCallback
|
|
{
|
|
protected:
|
|
btRigidBody* m_rigidBody;
|
|
btHfFluidBuoyantConvexShape* m_buoyantShape;
|
|
btIDebugDraw* m_debugDraw;
|
|
int m_numVoxels;
|
|
btVector3 m_voxelPositionsXformed[32*32*32];
|
|
bool m_voxelSubmerged[32*32*32];
|
|
btVector3 m_aabbMin;
|
|
btVector3 m_aabbMax;
|
|
btScalar m_volume;
|
|
btScalar m_density;
|
|
btScalar m_floatyness;
|
|
public:
|
|
btHfFluidColumnRigidBodyCallback (btRigidBody* rigidBody, btIDebugDraw* debugDraw, btScalar density, btScalar floatyness);
|
|
bool processColumn (btHfFluid* fluid, int w, int l);
|
|
btScalar getVolume () const { return m_volume; }
|
|
};
|
|
|
|
#endif
|
|
|