void btFluidHfBuoyantConvexShape::generateShape(btScalar collisionRadius, btScalar volumeEstimationRadius) { m_voxelPositions.resize(0); btVoronoiSimplexSolver simplexSolver; btTransform voxelTransform = btTransform::getIdentity(); btVector3 aabbMin, aabbMax; getAabb( btTransform::getIdentity(), aabbMin, aabbMax ); //AABB of the convex shape //Generate voxels for collision { btSphereShape collisionShape(collisionRadius); const btScalar collisionDiameter = btScalar(2.0) * collisionRadius; btVector3 numVoxels = (aabbMax - aabbMin) / collisionDiameter; for(int i = 0; i < ceil( numVoxels.x() ); i++) { for(int j = 0; j < ceil( numVoxels.y() ); j++) { for(int k = 0; k < ceil( numVoxels.z() ); k++) { btVector3 voxelPosition = aabbMin + btVector3(i * collisionDiameter, j * collisionDiameter, k * collisionDiameter); voxelTransform.setOrigin(voxelPosition); if( intersect(&simplexSolver, btTransform::getIdentity(), voxelTransform, m_convexShape, &collisionShape) ) m_voxelPositions.push_back(voxelPosition); } } } const bool CENTER_VOXELS_AABB_ON_ORIGIN = true; if(CENTER_VOXELS_AABB_ON_ORIGIN) { btVector3 diameter(collisionDiameter, collisionDiameter, collisionDiameter); btVector3 voxelAabbMin(BT_LARGE_FLOAT, BT_LARGE_FLOAT, BT_LARGE_FLOAT); btVector3 voxelAabbMax(-BT_LARGE_FLOAT, -BT_LARGE_FLOAT, -BT_LARGE_FLOAT); for(int i = 0; i < m_voxelPositions.size(); ++i) { voxelAabbMin.setMin(m_voxelPositions[i] - diameter); voxelAabbMax.setMax(m_voxelPositions[i] + diameter); } btVector3 offset = (voxelAabbMax - voxelAabbMin)*btScalar(0.5) - voxelAabbMax; for(int i = 0; i < m_voxelPositions.size(); ++i) m_voxelPositions[i] += offset; } } //Estimate volume with smaller spheres btScalar estimatedVolume; { btSphereShape volumeEstimationShape(volumeEstimationRadius); int numCollidingVoxels = 0; const btScalar estimationDiameter = btScalar(2.0) * volumeEstimationRadius; btVector3 numEstimationVoxels = (aabbMax - aabbMin) / estimationDiameter; for(int i = 0; i < ceil( numEstimationVoxels.x() ); i++) { for(int j = 0; j < ceil( numEstimationVoxels.y() ); j++) { for(int k = 0; k < ceil( numEstimationVoxels.z() ); k++) { btVector3 voxelPosition = aabbMin + btVector3(i * estimationDiameter, j * estimationDiameter, k * estimationDiameter); voxelTransform.setOrigin(voxelPosition); if( intersect(&simplexSolver, btTransform::getIdentity(), voxelTransform, m_convexShape, &volumeEstimationShape) ) ++numCollidingVoxels; } } } //Although the voxels are spherical, it is better to use the volume of a cube //for volume estimation. Since convex shapes are completely solid and the voxels //are generated by moving along a cubic lattice, using the volume of a sphere //would result in gaps. Comparing the volume of a cube with edge length 2(8 m^3) //and the volume of a sphere with diameter 2(~4 m^3), the estimated volume would //be off by about 1/2. btScalar volumePerEstimationVoxel = btPow( estimationDiameter, btScalar(3.0) ); //btScalar volumePerEstimationVoxel = btScalar(4.0/3.0) * SIMD_PI * btPow( volumeEstimationRadius, btScalar(3.0) ); estimatedVolume = static_cast<btScalar>(numCollidingVoxels) * volumePerEstimationVoxel; } m_volumePerVoxel = estimatedVolume / static_cast<btScalar>( getNumVoxels() ); m_totalVolume = estimatedVolume; m_collisionRadius = collisionRadius; }
// Returns the size (in bytes) of the data blob int32_t RtExternalImageInfo::getDataSize() const { return getBytesPerPix()*getNumVoxels(); }