Synchronize changes from branches/GpuClothAMD to trunk

Main improvements are: GPU cloth collision detection against a capsule shape
,OpenCL-OpenGL interoperability (keeping data buffers on GPU), and bug fixes
Thanks to Lee Howes
This commit is contained in:
erwin.coumans
2011-02-27 09:07:07 +00:00
parent ec1bd45f4f
commit d52f58edd8
37 changed files with 3267 additions and 2481 deletions

View File

@@ -435,11 +435,16 @@ public:
m_vertexTriangleCount[vertexIndex] = 0;
}
/** Create numVertices new vertices for cloth clothIdentifier */
void createVertices( int numVertices, int clothIdentifier )
/**
* Create numVertices new vertices for cloth clothIdentifier
* maxVertices allows a buffer zone of extra vertices for alignment or tearing reasons.
*/
void createVertices( int numVertices, int clothIdentifier, int maxVertices = 0 )
{
int previousSize = m_vertexPosition.size();
int newSize = previousSize + numVertices;
if( maxVertices == 0 )
maxVertices = numVertices;
int newSize = previousSize + maxVertices;
// Resize all the arrays that store vertex data
m_clothIdentifier.resize( newSize );
@@ -454,6 +459,8 @@ public:
for( int vertexIndex = previousSize; vertexIndex < newSize; ++vertexIndex )
m_clothIdentifier[vertexIndex] = clothIdentifier;
for( int vertexIndex = (previousSize + numVertices); vertexIndex < newSize; ++vertexIndex )
m_clothIdentifier[vertexIndex] = -1;
}
// Get and set methods in header so they can be inlined
@@ -466,6 +473,11 @@ public:
return m_vertexPosition[vertexIndex];
}
Vectormath::Aos::Point3 getPosition( int vertexIndex ) const
{
return m_vertexPosition[vertexIndex];
}
/**
* Return a reference to the previous position of vertex vertexIndex as stored on the host.
*/
@@ -498,6 +510,11 @@ public:
return m_vertexNormal[vertexIndex];
}
Vectormath::Aos::Vector3 getNormal( int vertexIndex ) const
{
return m_vertexNormal[vertexIndex];
}
/**
* Return a reference to the inverse mass of vertex vertexIndex as stored on the host.
*/

View File

@@ -74,12 +74,46 @@ static Vectormath::Aos::Transform3 toTransform3( const btTransform &transform )
return outTransform;
}
void btCPUSoftBodySolver::optimize( btAlignedObjectArray< btSoftBody * > &softBodies )
void btCPUSoftBodySolver::btAcceleratedSoftBodyInterface::updateBounds( const btVector3 &lowerBound, const btVector3 &upperBound )
{
if( m_softBodySet.size() != softBodies.size() )
float scalarMargin = this->getSoftBody()->getCollisionShape()->getMargin();
btVector3 vectorMargin( scalarMargin, scalarMargin, scalarMargin );
m_softBody->m_bounds[0] = lowerBound - vectorMargin;
m_softBody->m_bounds[1] = upperBound + vectorMargin;
}
void btCPUSoftBodySolver::copyBackToSoftBodies()
{
// Loop over soft bodies, copying all the vertex positions back for each body in turn
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
{
btAcceleratedSoftBodyInterface *softBodyInterface = m_softBodySet[ softBodyIndex ];
btSoftBody *softBody = softBodyInterface->getSoftBody();
int firstVertex = softBodyInterface->getFirstVertex();
int numVertices = softBodyInterface->getNumVertices();
// Copy vertices from solver back into the softbody
for( int vertex = 0; vertex < numVertices; ++vertex )
{
using Vectormath::Aos::Point3;
Point3 vertexPosition( getVertexData().getVertexPositions()[firstVertex + vertex] );
softBody->m_nodes[vertex].m_x.setX( vertexPosition.getX() );
softBody->m_nodes[vertex].m_x.setY( vertexPosition.getY() );
softBody->m_nodes[vertex].m_x.setZ( vertexPosition.getZ() );
softBody->m_nodes[vertex].m_n.setX( vertexPosition.getX() );
softBody->m_nodes[vertex].m_n.setY( vertexPosition.getY() );
softBody->m_nodes[vertex].m_n.setZ( vertexPosition.getZ() );
}
}
} // btCPUSoftBodySolver::copyBackToSoftBodies
void btCPUSoftBodySolver::optimize( btAlignedObjectArray< btSoftBody * > &softBodies , bool forceUpdate )
{
if( forceUpdate || m_softBodySet.size() != softBodies.size() )
{
// Have a change in the soft body set so update, reloading all the data
getVertexData().clear();
@@ -104,6 +138,7 @@ void btCPUSoftBodySolver::optimize( btAlignedObjectArray< btSoftBody * > &softBo
m_perClothLiftFactor.push_back( softBody->m_cfg.kLF );
m_perClothDragFactor.push_back( softBody->m_cfg.kDG );
m_perClothMediumDensity.push_back(softBody->getWorldInfo()->air_density);
m_perClothCollisionObjects.push_back( CollisionObjectIndices(-1, -1) );
// Add space for new vertices and triangles in the default solver for now
// TODO: Include space here for tearing too later
@@ -385,51 +420,72 @@ void btCPUSoftBodySolver::updateConstants( float timeStep )
}
} // btCPUSoftBodySolver::updateConstants
void btCPUSoftBodySolver::updateBounds()
{
using Vectormath::Aos::Point3;
for( int clothIndex = 0; clothIndex < m_softBodySet.size(); ++clothIndex )
{
btAcceleratedSoftBodyInterface *currentCloth = m_softBodySet[clothIndex];
btVector3 startBound(FLT_MAX, FLT_MAX, FLT_MAX);
btVector3 endBound(FLT_MIN, FLT_MIN, FLT_MIN);
const int startVertex = currentCloth->getFirstVertex();
const int numVertices = currentCloth->getNumVertices();
int endVertex = startVertex + numVertices;
for(int vertexIndex = startVertex; vertexIndex < endVertex; ++vertexIndex)
{
btVector3 vertexPosition( m_vertexData.getVertexPositions()[vertexIndex].getX(), m_vertexData.getVertexPositions()[vertexIndex].getY(), m_vertexData.getVertexPositions()[vertexIndex].getZ() );
startBound.setX( btMin( startBound.getX(), vertexPosition.getX() ) );
startBound.setY( btMin( startBound.getY(), vertexPosition.getY() ) );
startBound.setZ( btMin( startBound.getZ(), vertexPosition.getZ() ) );
endBound.setX( btMax( endBound.getX(), vertexPosition.getX() ) );
endBound.setY( btMax( endBound.getY(), vertexPosition.getY() ) );
endBound.setZ( btMax( endBound.getZ(), vertexPosition.getZ() ) );
}
m_softBodySet[clothIndex]->updateBounds( startBound, endBound );
}
}
class btCPUSB_QuickSortCompare
{
public:
bool operator() ( const btCPUCollisionShapeDescription& a, const btCPUCollisionShapeDescription& b )
{
return ( a.softBodyIdentifier < b.softBodyIdentifier );
}
};
/**
* Sort the collision object details array and generate indexing into it for the per-cloth collision object array.
*/
void btCPUSoftBodySolver::prepareCollisionConstraints()
{
// First do a simple radix sort on the collision objects
// First do a simple sort on the collision objects
btAlignedObjectArray<int> numObjectsPerClothPrefixSum;
btAlignedObjectArray<int> numObjectsPerCloth;
numObjectsPerCloth.resize( m_softBodySet.size(), 0 );
numObjectsPerClothPrefixSum.resize( m_softBodySet.size(), 0 );
btAlignedObjectArray< CollisionShapeDescription > m_collisionObjectDetailsCopy(m_collisionObjectDetails);
// Count and prefix sum number of previous cloths
for( int collisionObject = 0; collisionObject < m_collisionObjectDetailsCopy.size(); ++collisionObject )
{
CollisionShapeDescription &shapeDescription( m_collisionObjectDetailsCopy[collisionObject] );
++numObjectsPerClothPrefixSum[shapeDescription.softBodyIdentifier];
}
int sum = 0;
for( int cloth = 0; cloth < m_softBodySet.size(); ++cloth )
{
int currentValue = numObjectsPerClothPrefixSum[cloth];
numObjectsPerClothPrefixSum[cloth] = sum;
sum += currentValue;
}
// Move into the target array
for( int collisionObject = 0; collisionObject < m_collisionObjectDetailsCopy.size(); ++collisionObject )
{
CollisionShapeDescription &shapeDescription( m_collisionObjectDetailsCopy[collisionObject] );
int clothID = shapeDescription.softBodyIdentifier;
int newLocation = numObjectsPerClothPrefixSum[clothID] + numObjectsPerCloth[clothID];
numObjectsPerCloth[shapeDescription.softBodyIdentifier]++;
m_collisionObjectDetails[newLocation] = shapeDescription;
}
for( int collisionObject = 0; collisionObject < m_collisionObjectDetailsCopy.size(); ++collisionObject )
{
CollisionShapeDescription &shapeDescription( m_collisionObjectDetails[collisionObject] );
}
if (!m_perClothCollisionObjects.size())
return;
m_collisionObjectDetails.quickSort( btCPUSB_QuickSortCompare() );
// Generating indexing for perClothCollisionObjects
// First clear the previous values
// First clear the previous values with the "no collision object for cloth" constant
for( int clothIndex = 0; clothIndex < m_perClothCollisionObjects.size(); ++clothIndex )
{
m_perClothCollisionObjects[clothIndex].firstObject = 0;
m_perClothCollisionObjects[clothIndex].endObject = 0;
m_perClothCollisionObjects[clothIndex].firstObject = -1;
m_perClothCollisionObjects[clothIndex].endObject = -1;
}
int currentCloth = 0;
int startIndex = 0;
@@ -445,8 +501,12 @@ void btCPUSoftBodySolver::prepareCollisionConstraints()
currentCloth = nextCloth;
startIndex = collisionObject;
}
}
//m_perClothCollisionObjects
}
// And update last cloth
m_perClothCollisionObjects[currentCloth].firstObject = startIndex;
m_perClothCollisionObjects[currentCloth].endObject = m_collisionObjectDetails.size();
} // prepareCollisionConstraints
@@ -478,83 +538,9 @@ void btCPUSoftBodySolver::solveConstraints( float solverdt )
}
#if 0
prepareCollisionConstraints();
// Solve collision constraints
// Very simple solver that pushes the vertex out of collision imposters for now
// to test integration with the broad phase code.
// May also want to put this into position solver loop every n iterations depending on
// how it behaves
for( int clothIndex = 0; clothIndex < m_softBodySet.size(); ++clothIndex )
{
btAcceleratedSoftBodyInterface *currentCloth = m_softBodySet[clothIndex];
const int startVertex = currentCloth->getFirstVertex();
const int numVertices = currentCloth->getNumVertices();
int endVertex = startVertex + numVertices;
int startObject = m_perClothCollisionObjects[clothIndex].firstObject;
int endObject = m_perClothCollisionObjects[clothIndex].endObject;
for( int collisionObject = startObject; collisionObject < endObject; ++collisionObject )
{
CollisionShapeDescription &shapeDescription( m_collisionObjectDetails[collisionObject] );
if( shapeDescription.collisionShapeType == CAPSULE_SHAPE_PROXYTYPE )
{
using namespace Vectormath::Aos;
float capsuleHalfHeight = shapeDescription.shapeInformation.capsule.halfHeight;
float capsuleRadius = shapeDescription.shapeInformation.capsule.radius;
Transform3 worldTransform = shapeDescription.shapeTransform;
for( int vertexIndex = startVertex; vertexIndex < endVertex; ++vertexIndex )
{
Point3 vertex( m_vertexData.getPosition( vertexIndex ) );
Point3 c1(0.f, -capsuleHalfHeight, 0.f);
Point3 c2(0.f, +capsuleHalfHeight, 0.f);
Point3 worldC1 = worldTransform * c1;
Point3 worldC2 = worldTransform * c2;
Vector3 segment = worldC2 - worldC1;
// compute distance of tangent to vertex along line segment in capsule
float distanceAlongSegment = -( dot( worldC1 - vertex, segment ) / lengthSqr(segment) );
Point3 closestPoint = (worldC1 + segment * distanceAlongSegment);
float distanceFromLine = length(vertex - closestPoint);
float distanceFromC1 = length(worldC1 - vertex);
float distanceFromC2 = length(worldC2 - vertex);
// Final distance from collision, point to push from, direction to push in
// for impulse force
float distance;
Point3 sourcePoint;
Vector3 pushVector;
if( distanceAlongSegment < 0 )
{
distance = distanceFromC1;
sourcePoint = worldC1;
pushVector = normalize(vertex - worldC1);
} else if( distanceAlongSegment > 1.f ) {
distance = distanceFromC1;
sourcePoint = worldC1;
pushVector = normalize(vertex - worldC1);
} else {
distance = distanceFromLine;
sourcePoint = closestPoint;
pushVector = normalize(vertex - closestPoint);
}
// For now just update vertex position by moving to radius distance along the push vector
// Could use this as the basis for simple vector distance constraint for the point later, possibly?
// That way in the main solver loop all shape types could be the same... though when
// we need to apply bi-directionally it becomes more complicated
m_vertexData.getPosition( vertexIndex ) = closestPoint + capsuleRadius * pushVector;
}
}
}
}
#endif
for( int iteration = 0; iteration < m_numberOfVelocityIterations ; ++iteration )
{
@@ -622,6 +608,8 @@ void btCPUSoftBodySolver::solveConstraints( float solverdt )
}
}
}
// Clear forces so that friction is applied correctly
for( int clothIndex = 0; clothIndex < m_softBodySet.size(); ++clothIndex )
{
btAcceleratedSoftBodyInterface *currentCloth = m_softBodySet[clothIndex];
@@ -637,23 +625,201 @@ void btCPUSoftBodySolver::solveConstraints( float solverdt )
float velocityCorrectionCoefficient = m_perClothVelocityCorrectionCoefficient[clothIndex];
float isolverDt = 1.f/solverdt;
if( m_numberOfVelocityIterations > 0 )
for(int vertexIndex = startVertex; vertexIndex < lastVertex; ++vertexIndex)
{
for(int vertexIndex = startVertex; vertexIndex < lastVertex; ++vertexIndex)
{
m_vertexData.getVelocity(vertexIndex) += (m_vertexData.getPosition(vertexIndex) - m_vertexData.getPreviousPosition(vertexIndex)) * velocityCorrectionCoefficient * isolverDt;
m_vertexData.getVelocity(vertexIndex) *= velocityCoefficient;
m_vertexData.getForceAccumulator( vertexIndex ) = Vector3(0.f, 0.f, 0.f);
}
} else {
// If we didn't compute the velocity iteratively then we compute it purely based on the position change
for(int vertexIndex = startVertex; vertexIndex < lastVertex; ++vertexIndex)
{
m_vertexData.getVelocity(vertexIndex) = (m_vertexData.getPosition(vertexIndex) - m_vertexData.getPreviousPosition(vertexIndex)) * velocityCoefficient * isolverDt;
m_vertexData.getForceAccumulator( vertexIndex ) = Vector3(0.f, 0.f, 0.f);
}
m_vertexData.getForceAccumulator( vertexIndex ) = Vector3(0.f, 0.f, 0.f);
}
}
// Solve collision constraints
// Very simple solver that pushes the vertex out of collision imposters for now
// to test integration with the broad phase code.
// May also want to put this into position solver loop every n iterations depending on
// how it behaves
for( int clothIndex = 0; clothIndex < m_softBodySet.size(); ++clothIndex )
{
btAcceleratedSoftBodyInterface *currentCloth = m_softBodySet[clothIndex];
float clothFriction = currentCloth->getSoftBody()->getFriction();
const int startVertex = currentCloth->getFirstVertex();
const int numVertices = currentCloth->getNumVertices();
int endVertex = startVertex + numVertices;
float velocityCoefficient = (1.f - m_perClothDampingFactor[clothIndex]);
float velocityCorrectionCoefficient = m_perClothVelocityCorrectionCoefficient[clothIndex];
float isolverDt = 1.f/solverdt;
int startObject = m_perClothCollisionObjects[clothIndex].firstObject;
int endObject = m_perClothCollisionObjects[clothIndex].endObject;
if( endObject == startObject )
{
// No collisions so just do the force update
for(int vertexIndex = startVertex; vertexIndex < endVertex; ++vertexIndex)
{
m_vertexData.getForceAccumulator( vertexIndex ) = Vector3(0.f, 0.f, 0.f);
}
// Recompute velocity based on updated position inclusive of drift
for(int vertexIndex = startVertex; vertexIndex < endVertex; ++vertexIndex)
{
m_vertexData.getVelocity(vertexIndex) = (m_vertexData.getPosition(vertexIndex) - m_vertexData.getPreviousPosition(vertexIndex)) * velocityCoefficient * isolverDt;
}
} else {
for( int collisionObject = startObject; collisionObject < endObject; ++collisionObject )
{
btCPUCollisionShapeDescription &shapeDescription( m_collisionObjectDetails[collisionObject] );
float colliderFriction = shapeDescription.friction;
if( shapeDescription.collisionShapeType == CAPSULE_SHAPE_PROXYTYPE )
{
using namespace Vectormath::Aos;
float capsuleHalfHeight = shapeDescription.shapeInformation.capsule.halfHeight;
float capsuleRadius = shapeDescription.shapeInformation.capsule.radius;
int capsuleUpAxis = shapeDescription.shapeInformation.capsule.upAxis;
float capsuleMargin = shapeDescription.margin;
Transform3 worldTransform = shapeDescription.shapeTransform;
// As this is a GPU comparison solver just iterate over the vertices
for( int vertexIndex = startVertex; vertexIndex < endVertex; ++vertexIndex )
{
// Clear force for vertex first
m_vertexData.getForceAccumulator( vertexIndex ) = Vector3(0.f, 0.f, 0.f);
Point3 vertex( m_vertexData.getPosition( vertexIndex ) );
// Correctly define the centerline depending on the upAxis
Point3 c1(0.f, 0.f, 0.f);
Point3 c2(0.f, 0.f, 0.f);
if( capsuleUpAxis == 0 ) {
c1.setX(-capsuleHalfHeight);
c2.setX(capsuleHalfHeight);
} else if( capsuleUpAxis == 1 ) {
c1.setY(-capsuleHalfHeight);
c2.setY(capsuleHalfHeight);
} else {
c1.setZ(-capsuleHalfHeight);
c2.setZ(capsuleHalfHeight);
}
Point3 worldC1 = worldTransform * c1;
Point3 worldC2 = worldTransform * c2;
Vector3 segment = worldC2 - worldC1;
// compute distance of tangent to vertex along line segment in capsule
float distanceAlongSegment = -( dot( worldC1 - vertex, segment ) / lengthSqr(segment) );
Point3 closestPoint = (worldC1 + segment * distanceAlongSegment);
float distanceFromLine = length(vertex - closestPoint);
float distanceFromC1 = length(worldC1 - vertex);
float distanceFromC2 = length(worldC2 - vertex);
// Final distance from collision, point to push from, direction to push in
// for impulse force
float distance;
Point3 sourcePoint;
Vector3 normalVector;
if( distanceAlongSegment < 0 )
{
distance = distanceFromC1;
sourcePoint = worldC1;
normalVector = normalize(vertex - worldC1);
} else if( distanceAlongSegment > 1.f ) {
distance = distanceFromC2;
sourcePoint = worldC2;
normalVector = normalize(vertex - worldC2);
} else {
distance = distanceFromLine;
sourcePoint = closestPoint;
normalVector = normalize(vertex - closestPoint);
}
Vector3 colliderLinearVelocity( shapeDescription.linearVelocity );
Vector3 colliderAngularVelocity( shapeDescription.angularVelocity );
Vector3 velocityOfSurfacePoint = colliderLinearVelocity + cross(colliderAngularVelocity, Vector3(vertex) - worldTransform.getTranslation());
float minDistance = capsuleRadius + capsuleMargin;
bool collided = false;
if( distance < minDistance )
{
// Project back to surface along normal
Vectormath::Aos::Point3 sourcePos = m_vertexData.getPosition( vertexIndex );
Vectormath::Aos::Vector3 posChange = (minDistance - distance)*normalVector*0.9;
//if( length(posChange) > 1 )
// std::cerr << "Poschange: " << length(posChange) << "\n";
Vectormath::Aos::Point3 newPos = sourcePos + posChange;
m_vertexData.getPosition( vertexIndex ) = newPos;
//m_vertexData.getPosition( vertexIndex ) = m_vertexData.getPosition( vertexIndex ) + (minDistance - distance)*normalVector*0.9;
// Experiment with moving back along source vector.
// Removes all ability to slide because it projects back along the vector length so it would undo lateral movement.
// TODO: This isn't quite right because we should take the movement of the collider into account as well
/*Vector3 incomingMoveVector( normalize(m_vertexData.getPreviousPosition(vertexIndex) - m_vertexData.getPosition(vertexIndex)) );
Vector3 normalDirectionMoveOut( (minDistance - distance)*normalVector*0.9 );
float distanceOnIncomingVector = dot(normalDirectionMoveOut, incomingMoveVector);
Vector3 vectorCorrection( distanceOnIncomingVector*incomingMoveVector );
m_vertexData.getPosition( vertexIndex ) = m_vertexData.getPosition( vertexIndex ) + vectorCorrection;*/
collided = true;
}
// Update velocity of vertex based on position
m_vertexData.getVelocity(vertexIndex) = (m_vertexData.getPosition(vertexIndex) - m_vertexData.getPreviousPosition(vertexIndex)) * velocityCoefficient * isolverDt;
// If we collided before we are on the surface so have friction
if( collided )
{
// Compute friction
// TODO: Just vertex velocity not enough, really we need the velocity
// relative to closest point on the surface of the collider
Vector3 vertexVelocity( m_vertexData.getVelocity(vertexIndex) );
Vector3 relativeVelocity( vertexVelocity - velocityOfSurfacePoint );
// First compute vectors for plane perpendicular to normal vector
// Cross any vector with normal vector first then cross the normal with it again
Vector3 p1(normalize(cross(normalVector, segment)));
Vector3 p2(normalize(cross(p1, normalVector)));
// Full friction is sum of velocities in each direction of plane.
Vector3 frictionVector(p1*dot(relativeVelocity, p1) + p2*dot(relativeVelocity, p2));
// Real friction is peak friction corrected by friction coefficients.
frictionVector = frictionVector*(colliderFriction*clothFriction);
float approachSpeed = dot( relativeVelocity, normalVector );
// For now just update vertex position by moving to radius distance along the push vector
// Could use this as the basis for simple vector distance constraint for the point later, possibly?
// That way in the main solver loop all shape types could be the same... though when
// we need to apply bi-directionally it becomes more complicated
// Add friction vector to the force accumulator
Vector3 &currentForce( m_vertexData.getForceAccumulator( vertexIndex ) );
// Only apply if the vertex is moving towards the object to reduce jitter error
if( approachSpeed <= 0.0 )
currentForce -= frictionVector;
}
}
}
} // for( int collisionObject = startObject; collisionObject < endObject; ++collisionObject )
} // if( endObject == startObject )
}
} // btCPUSoftBodySolver::solveConstraints
@@ -669,14 +835,37 @@ btCPUSoftBodySolver::btAcceleratedSoftBodyInterface *btCPUSoftBodySolver::findSo
return 0;
}
void btCPUSoftBodySolver::copySoftBodyToVertexBuffer( const btSoftBody * const softBody, btVertexBufferDescriptor *vertexBuffer )
const btCPUSoftBodySolver::btAcceleratedSoftBodyInterface * const btCPUSoftBodySolver::findSoftBodyInterface( const btSoftBody* const softBody ) const
{
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
{
const btAcceleratedSoftBodyInterface *const softBodyInterface = m_softBodySet[softBodyIndex];
if( softBodyInterface->getSoftBody() == softBody )
return softBodyInterface;
}
return 0;
}
int btCPUSoftBodySolver::findSoftBodyIndex( const btSoftBody* const softBody )
{
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
{
btAcceleratedSoftBodyInterface *softBodyInterface = m_softBodySet[softBodyIndex];
if( softBodyInterface->getSoftBody() == softBody )
return softBodyIndex;
}
return 1;
}
void btSoftBodySolverOutputCPUtoCPU::copySoftBodyToVertexBuffer( const btSoftBody * const softBody, btVertexBufferDescriptor *vertexBuffer )
{
// Currently only support CPU output buffers
// TODO: check for DX11 buffers. Take all offsets into the same DX11 buffer
// and use them together on a single kernel call if possible by setting up a
// per-cloth target buffer array for the copy kernel.
btAcceleratedSoftBodyInterface *currentCloth = findSoftBodyInterface( softBody );
const btSoftBodySolver *solver = softBody->getSoftBodySolver();
btAssert( solver->getSolverType() == btSoftBodySolver::CPU_SOLVER );
const btCPUSoftBodySolver *cpuSolver = static_cast< const btCPUSoftBodySolver * >( solver );
const btCPUSoftBodySolver::btAcceleratedSoftBodyInterface * const currentCloth = cpuSolver->findSoftBodyInterface( softBody );
const btSoftBodyVertexData &vertexData( cpuSolver->m_vertexData );
if( vertexBuffer->getBufferType() == btVertexBufferDescriptor::CPU_BUFFER )
{
@@ -693,7 +882,7 @@ void btCPUSoftBodySolver::copySoftBodyToVertexBuffer( const btSoftBody * const s
for( int vertexIndex = firstVertex; vertexIndex < lastVertex; ++vertexIndex )
{
Vectormath::Aos::Point3 position = m_vertexData.getPosition(vertexIndex);
Vectormath::Aos::Point3 position = vertexData.getPosition(vertexIndex);
*(vertexPointer + 0) = position.getX();
*(vertexPointer + 1) = position.getY();
*(vertexPointer + 2) = position.getZ();
@@ -708,40 +897,58 @@ void btCPUSoftBodySolver::copySoftBodyToVertexBuffer( const btSoftBody * const s
for( int vertexIndex = firstVertex; vertexIndex < lastVertex; ++vertexIndex )
{
Vectormath::Aos::Vector3 normal = m_vertexData.getNormal(vertexIndex);
Vectormath::Aos::Vector3 normal = vertexData.getNormal(vertexIndex);
*(normalPointer + 0) = normal.getX();
*(normalPointer + 1) = normal.getY();
*(normalPointer + 2) = normal.getZ();
normalPointer += normalStride;
}
}
} else {
btAssert( 0=="Invalid vertex buffer descriptor used in CPU output." );
}
} // btCPUSoftBodySolver::outputToVertexBuffers
void btCPUSoftBodySolver::addCollisionObjectForSoftBody( int clothIndex, btCollisionObject *collisionObject )
void btCPUSoftBodySolver::processCollision( btSoftBody*, btSoftBody *)
{
btCollisionShape *collisionShape = collisionObject->getCollisionShape();
int shapeType = collisionShape->getShapeType();
if( shapeType == CAPSULE_SHAPE_PROXYTYPE )
{
// Add to the list of expected collision objects
CollisionShapeDescription newCollisionShapeDescription;
newCollisionShapeDescription.softBodyIdentifier = clothIndex;
newCollisionShapeDescription.collisionShapeType = shapeType;
newCollisionShapeDescription.shapeTransform = toTransform3(collisionObject->getWorldTransform());
btCapsuleShape *capsule = static_cast<btCapsuleShape*>( collisionShape );
newCollisionShapeDescription.shapeInformation.capsule.radius = capsule->getRadius();
newCollisionShapeDescription.shapeInformation.capsule.halfHeight = capsule->getHalfHeight();
m_collisionObjectDetails.push_back( newCollisionShapeDescription );
// TODO: In the collision function, sort the above array on the clothIndex and generate the start and end indices
} else {
btAssert("Unsupported collision shape type\n");
}
}
// Add the collision object to the set to deal with for a particular soft body
void btCPUSoftBodySolver::processCollision( btSoftBody *softBody, btCollisionObject* collisionObject )
{
int softBodyIndex = findSoftBodyIndex( softBody );
if( softBodyIndex >= 0 )
{
btCollisionShape *collisionShape = collisionObject->getCollisionShape();
float friction = collisionObject->getFriction();
int shapeType = collisionShape->getShapeType();
if( shapeType == CAPSULE_SHAPE_PROXYTYPE )
{
// Add to the list of expected collision objects
btCPUCollisionShapeDescription newCollisionShapeDescription;
newCollisionShapeDescription.softBodyIdentifier = softBodyIndex;
newCollisionShapeDescription.collisionShapeType = shapeType;
newCollisionShapeDescription.shapeTransform = toTransform3(collisionObject->getWorldTransform());
btCapsuleShape *capsule = static_cast<btCapsuleShape*>( collisionShape );
newCollisionShapeDescription.shapeInformation.capsule.radius = capsule->getRadius();
newCollisionShapeDescription.shapeInformation.capsule.halfHeight = capsule->getHalfHeight();
newCollisionShapeDescription.shapeInformation.capsule.upAxis = capsule->getUpAxis();
newCollisionShapeDescription.margin = capsule->getMargin();
newCollisionShapeDescription.friction = friction;
btRigidBody* body = static_cast< btRigidBody* >( collisionObject );
newCollisionShapeDescription.linearVelocity = toVector3(body->getLinearVelocity());
newCollisionShapeDescription.angularVelocity = toVector3(body->getAngularVelocity());
m_collisionObjectDetails.push_back( newCollisionShapeDescription );
} else {
btAssert("Unsupported collision shape type\n");
}
} else {
btAssert("Unknown soft body");
}
} // btCPUSoftBodySolver::processCollision
void btCPUSoftBodySolver::predictMotion( float timeStep )
{
@@ -760,6 +967,12 @@ void btCPUSoftBodySolver::predictMotion( float timeStep )
// Itegrate motion for all soft bodies dealt with by the solver
integrate( timeStep * getTimeScale() );
// Update bounds
// Will update the bounds for all softBodies being dealt with by the solver and
// set the values in the btSoftBody object
updateBounds();
// End prediction work for solvers
}

View File

@@ -21,7 +21,37 @@ subject to the following restrictions:
#include "BulletSoftBody/btSoftBodySolverVertexBuffer.h"
#include "BulletMultiThreaded/GpuSoftBodySolvers/CPU/btSoftBodySolverData.h"
struct btCPUCollisionShapeDescription
{
int softBodyIdentifier;
int collisionShapeType;
Vectormath::Aos::Transform3 shapeTransform;
union
{
struct Sphere
{
float radius;
} sphere;
struct Capsule
{
float radius;
float halfHeight;
int upAxis;
} capsule;
} shapeInformation;
float margin;
float friction;
Vectormath::Aos::Vector3 linearVelocity;
Vectormath::Aos::Vector3 angularVelocity;
btCPUCollisionShapeDescription()
{
collisionShapeType = 0;
margin = 0;
friction = 0;
}
};
class btCPUSoftBodySolver : public btSoftBodySolver
{
@@ -30,28 +60,22 @@ protected:
* Entry in the collision shape array.
* Specifies the shape type, the transform matrix and the necessary details of the collisionShape.
*/
struct CollisionShapeDescription
{
int softBodyIdentifier;
int collisionShapeType;
Vectormath::Aos::Transform3 shapeTransform;
union
{
struct Sphere
{
float radius;
} sphere;
struct Capsule
{
float radius;
float halfHeight;
} capsule;
} shapeInformation;
CollisionShapeDescription()
// Public because output classes need it. This is a better encapsulation to break in the short term
// Than having the solvers themselves need dependencies on DX, CL etc unnecessarily
public:
struct CollisionObjectIndices
{
CollisionObjectIndices( int f, int e )
{
collisionShapeType = 0;
firstObject = f;
endObject = e;
}
int firstObject;
int endObject;
};
/**
@@ -99,36 +123,41 @@ protected:
m_maxLinks = 0;
m_numLinks = 0;
}
int getNumVertices()
int getNumVertices() const
{
return m_numVertices;
}
int getNumTriangles()
int getNumTriangles() const
{
return m_numTriangles;
}
int getMaxVertices()
int getMaxVertices() const
{
return m_maxVertices;
}
int getMaxTriangles()
int getMaxTriangles() const
{
return m_maxTriangles;
}
int getFirstVertex()
int getFirstVertex() const
{
return m_firstVertex;
}
int getFirstTriangle()
int getFirstTriangle() const
{
return m_firstTriangle;
}
/**
* Update the bounds in the btSoftBody object
*/
void updateBounds( const btVector3 &lowerBound, const btVector3 &upperBound );
// TODO: All of these set functions will have to do checks and
// update the world because restructuring of the arrays will be necessary
// Reasonable use of "friend"?
@@ -177,17 +206,17 @@ protected:
m_firstLink = firstLink;
}
int getMaxLinks()
int getMaxLinks() const
{
return m_maxLinks;
}
int getNumLinks()
int getNumLinks() const
{
return m_numLinks;
}
int getFirstLink()
int getFirstLink() const
{
return m_firstLink;
}
@@ -197,47 +226,20 @@ protected:
return m_softBody;
}
#if 0
void setAcceleration( Vectormath::Aos::Vector3 acceleration )
const btSoftBody* const getSoftBody() const
{
m_currentSolver->setPerClothAcceleration( m_clothIdentifier, acceleration );
return m_softBody;
}
void setWindVelocity( Vectormath::Aos::Vector3 windVelocity )
{
m_currentSolver->setPerClothWindVelocity( m_clothIdentifier, windVelocity );
}
/**
* Set the density of the air in which the cloth is situated.
*/
void setAirDensity( btScalar density )
{
m_currentSolver->setPerClothMediumDensity( m_clothIdentifier, static_cast<float>(density) );
}
/**
* Add a collision object to this soft body.
*/
void addCollisionObject( btCollisionObject *collisionObject )
{
m_currentSolver->addCollisionObjectForSoftBody( m_clothIdentifier, collisionObject );
}
#endif
};
struct CollisionObjectIndices
{
int firstObject;
int endObject;
};
btSoftBodyLinkData m_linkData;
btSoftBodyVertexData m_vertexData;
btSoftBodyTriangleData m_triangleData;
protected:
/** Variable to define whether we need to update solver constants on the next iteration */
bool m_updateSolverConstants;
@@ -281,7 +283,7 @@ protected:
/**
* Collision shapes being passed across to the cloths in this solver.
*/
btAlignedObjectArray< CollisionShapeDescription > m_collisionObjectDetails;
btAlignedObjectArray< btCPUCollisionShapeDescription > m_collisionObjectDetails;
void prepareCollisionConstraints();
@@ -298,7 +300,10 @@ protected:
void applyForces( float solverdt );
void integrate( float solverdt );
void updateConstants( float timeStep );
btAcceleratedSoftBodyInterface *findSoftBodyInterface( const btSoftBody* const softBody );
int findSoftBodyIndex( const btSoftBody* const softBody );
/** Update the bounds of the soft body objects in the solver */
void updateBounds();
public:
@@ -306,6 +311,12 @@ public:
virtual ~btCPUSoftBodySolver();
virtual SolverTypes getSolverType() const
{
return CPU_SOLVER;
}
virtual btSoftBodyLinkData &getLinkData();
@@ -315,16 +326,8 @@ public:
/**
* Add a collision object to be used by the indicated softbody.
*/
virtual void addCollisionObjectForSoftBody( int clothIdentifier, btCollisionObject *collisionObject );
btAcceleratedSoftBodyInterface *findSoftBodyInterface( const btSoftBody* const softBody );
const btAcceleratedSoftBodyInterface * const findSoftBodyInterface( const btSoftBody* const softBody ) const;
@@ -332,15 +335,36 @@ public:
virtual void updateSoftBodies( );
virtual void optimize( btAlignedObjectArray< btSoftBody * > &softBodies );
virtual void optimize( btAlignedObjectArray< btSoftBody * > &softBodies , bool forceUpdate=false);
virtual void copyBackToSoftBodies();
virtual void solveConstraints( float solverdt );
virtual void predictMotion( float solverdt );
virtual void copySoftBodyToVertexBuffer( const btSoftBody *const softBody, btVertexBufferDescriptor *vertexBuffer );
virtual void processCollision( btSoftBody *, btCollisionObject* );
virtual void processCollision( btSoftBody*, btSoftBody *);
};
#endif // #ifndef BT_ACCELERATED_SOFT_BODY_CPU_SOLVER_H
/**
* Class to manage movement of data from a solver to a given target.
* This version is the CPU to CPU generic version.
*/
class btSoftBodySolverOutputCPUtoCPU : public btSoftBodySolverOutput
{
protected:
public:
btSoftBodySolverOutputCPUtoCPU()
{
}
/** Output current computed vertex data to the vertex buffers for all cloths in the solver. */
virtual void copySoftBodyToVertexBuffer( const btSoftBody * const softBody, btVertexBufferDescriptor *vertexBuffer );
};
#endif // #ifndef BT_ACCELERATED_SOFT_BODY_CPU_SOLVER_H

View File

@@ -39,8 +39,11 @@ SET(BulletSoftBodyDX11Solvers_Shaders
Integrate
UpdatePositions
UpdateNodes
ComputeBounds
SolvePositions
SolvePositionsSIMDBatched
SolveCollisionsAndUpdateVelocities
SolveCollisionsAndUpdateVelocitiesSIMDBatched
UpdatePositionsFromVelocities
ApplyForces
PrepareLinks

View File

@@ -68,6 +68,9 @@ protected:
buffer_desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
buffer_desc.ByteWidth = m_CPUBuffer->size() * sizeof(ElementType);
// At a minimum the buffer must exist
if( buffer_desc.ByteWidth == 0 )
buffer_desc.ByteWidth = sizeof(ElementType);
buffer_desc.StructureByteStride = sizeof(ElementType);
hr = m_d3dDevice->CreateBuffer(&buffer_desc, NULL, &m_Buffer);
if( FAILED( hr ) )
@@ -82,6 +85,8 @@ protected:
srvbuffer_desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
srvbuffer_desc.Buffer.ElementWidth = m_CPUBuffer->size();
if( srvbuffer_desc.Buffer.ElementWidth == 0 )
srvbuffer_desc.Buffer.ElementWidth = 1;
hr = m_d3dDevice->CreateShaderResourceView(m_Buffer, &srvbuffer_desc, &m_SRV);
if( FAILED( hr ) )
return (hr==S_OK);
@@ -93,6 +98,8 @@ protected:
srvbuffer_desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
srvbuffer_desc.Buffer.ElementWidth = m_CPUBuffer->size();
if( srvbuffer_desc.Buffer.ElementWidth == 0 )
srvbuffer_desc.Buffer.ElementWidth = 1;
hr = m_d3dDevice->CreateShaderResourceView(m_Buffer, &srvbuffer_desc, &m_SRV);
if( FAILED( hr ) )
return (hr==S_OK);
@@ -104,6 +111,8 @@ protected:
uavbuffer_desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
uavbuffer_desc.Buffer.NumElements = m_CPUBuffer->size();
if( uavbuffer_desc.Buffer.NumElements == 0 )
uavbuffer_desc.Buffer.NumElements = 1;
hr = m_d3dDevice->CreateUnorderedAccessView(m_Buffer, &uavbuffer_desc, &m_UAV);
if( FAILED( hr ) )
return (hr==S_OK);
@@ -173,7 +182,8 @@ public:
*/
bool moveToGPU()
{
if( (m_CPUBuffer->size() != m_gpuSize) )
// Reallocate if GPU size is too small
if( (m_CPUBuffer->size() > m_gpuSize ) )
m_onGPU = false;
if( !m_onGPU && m_CPUBuffer->size() > 0 )
{
@@ -192,16 +202,20 @@ public:
}
}
D3D11_BOX destRegion;
destRegion.left = 0;
destRegion.front = 0;
destRegion.top = 0;
destRegion.bottom = 1;
destRegion.back = 1;
destRegion.right = (m_CPUBuffer->size())*sizeof(ElementType);
m_d3dDeviceContext->UpdateSubresource(m_Buffer, 0, &destRegion, &((*m_CPUBuffer)[0]), 0, 0);
if( m_gpuSize > 0 )
{
D3D11_BOX destRegion;
destRegion.left = 0;
destRegion.front = 0;
destRegion.top = 0;
destRegion.bottom = 1;
destRegion.back = 1;
destRegion.right = (m_CPUBuffer->size())*sizeof(ElementType);
m_d3dDeviceContext->UpdateSubresource(m_Buffer, 0, &destRegion, &((*m_CPUBuffer)[0]), 0, 0);
m_onGPU = true;
}
m_onGPU = true;
}
return true;

View File

@@ -19,6 +19,7 @@ subject to the following restrictions:
#include "btSoftBodySolver_DX11.h"
#include "btSoftBodySolverVertexBuffer_DX11.h"
#include "BulletSoftBody/btSoftBody.h"
#include "BulletCollision/CollisionShapes/btCapsuleShape.h"
#define MSTRINGIFY(A) #A
static char* PrepareLinksHLSLString =
@@ -43,6 +44,10 @@ static char* OutputToVertexArrayHLSLString =
#include "HLSL/OutputToVertexArray.hlsl"
static char* VSolveLinksHLSLString =
#include "HLSL/VSolveLinks.hlsl"
static char* ComputeBoundsHLSLString =
#include "HLSL/ComputeBounds.hlsl"
static char* SolveCollisionsAndUpdateVelocitiesHLSLString =
#include "HLSL/SolveCollisionsAndUpdateVelocities.hlsl"
btSoftBodyLinkDataDX11::btSoftBodyLinkDataDX11( ID3D11Device *d3dDevice, ID3D11DeviceContext *d3dDeviceContext ) :
@@ -545,6 +550,7 @@ void btSoftBodyTriangleDataDX11::generateBatches()
btDX11SoftBodySolver::btDX11SoftBodySolver(ID3D11Device * dx11Device, ID3D11DeviceContext* dx11Context) :
m_dx11Device( dx11Device ),
m_dx11Context( dx11Context ),
dxFunctions( m_dx11Device, m_dx11Context ),
m_linkData(m_dx11Device, m_dx11Context),
m_vertexData(m_dx11Device, m_dx11Context),
m_triangleData(m_dx11Device, m_dx11Context),
@@ -554,7 +560,12 @@ btDX11SoftBodySolver::btDX11SoftBodySolver(ID3D11Device * dx11Device, ID3D11Devi
m_dx11PerClothVelocityCorrectionCoefficient( m_dx11Device, m_dx11Context, &m_perClothVelocityCorrectionCoefficient, true ),
m_dx11PerClothLiftFactor( m_dx11Device, m_dx11Context, &m_perClothLiftFactor, true ),
m_dx11PerClothDragFactor( m_dx11Device, m_dx11Context, &m_perClothDragFactor, true ),
m_dx11PerClothMediumDensity( m_dx11Device, m_dx11Context, &m_perClothMediumDensity, true )
m_dx11PerClothMediumDensity( m_dx11Device, m_dx11Context, &m_perClothMediumDensity, true ),
m_dx11PerClothCollisionObjects( m_dx11Device, m_dx11Context, &m_perClothCollisionObjects, true ),
m_dx11CollisionObjectDetails( m_dx11Device, m_dx11Context, &m_collisionObjectDetails, true ),
m_dx11PerClothMinBounds( m_dx11Device, m_dx11Context, &m_perClothMinBounds, false ),
m_dx11PerClothMaxBounds( m_dx11Device, m_dx11Context, &m_perClothMaxBounds, false ),
m_dx11PerClothFriction( m_dx11Device, m_dx11Context, &m_perClothFriction, false )
{
// Initial we will clearly need to update solver constants
// For now this is global for the cloths linked with this solver - we should probably make this body specific
@@ -565,15 +576,20 @@ btDX11SoftBodySolver::btDX11SoftBodySolver(ID3D11Device * dx11Device, ID3D11Devi
}
btDX11SoftBodySolver::~btDX11SoftBodySolver()
{
releaseKernels();
}
void btDX11SoftBodySolver::releaseKernels()
{
SAFE_RELEASE( prepareLinksKernel.kernel );
SAFE_RELEASE( prepareLinksKernel.constBuffer );
SAFE_RELEASE( integrateKernel.kernel );
SAFE_RELEASE( integrateKernel.constBuffer );
SAFE_RELEASE( integrateKernel.kernel );
SAFE_RELEASE( prepareLinksKernel.constBuffer );
SAFE_RELEASE( prepareLinksKernel.kernel );
SAFE_RELEASE( solvePositionsFromLinksKernel.constBuffer );
SAFE_RELEASE( solvePositionsFromLinksKernel.kernel );
SAFE_RELEASE( vSolveLinksKernel.constBuffer );
SAFE_RELEASE( vSolveLinksKernel.kernel );
SAFE_RELEASE( updatePositionsFromVelocitiesKernel.constBuffer );
SAFE_RELEASE( updatePositionsFromVelocitiesKernel.kernel );
SAFE_RELEASE( updateVelocitiesFromPositionsWithoutVelocitiesKernel.constBuffer );
@@ -586,27 +602,57 @@ btDX11SoftBodySolver::~btDX11SoftBodySolver()
SAFE_RELEASE( normalizeNormalsAndAreasKernel.kernel );
SAFE_RELEASE( updateSoftBodiesKernel.constBuffer );
SAFE_RELEASE( updateSoftBodiesKernel.kernel );
SAFE_RELEASE( outputToVertexArrayWithNormalsKernel.constBuffer );
SAFE_RELEASE( outputToVertexArrayWithNormalsKernel.kernel );
SAFE_RELEASE( outputToVertexArrayWithoutNormalsKernel.constBuffer );
SAFE_RELEASE( outputToVertexArrayWithoutNormalsKernel.kernel );
SAFE_RELEASE( solveCollisionsAndUpdateVelocitiesKernel.kernel );
SAFE_RELEASE( solveCollisionsAndUpdateVelocitiesKernel.constBuffer );
SAFE_RELEASE( computeBoundsKernel.kernel );
SAFE_RELEASE( computeBoundsKernel.constBuffer );
SAFE_RELEASE( vSolveLinksKernel.kernel );
SAFE_RELEASE( vSolveLinksKernel.constBuffer );
SAFE_RELEASE( addVelocityKernel.constBuffer );
SAFE_RELEASE( addVelocityKernel.kernel );
SAFE_RELEASE( applyForcesKernel.constBuffer );
SAFE_RELEASE( applyForcesKernel.kernel );
SAFE_RELEASE( outputToVertexArrayKernel.constBuffer );
SAFE_RELEASE( outputToVertexArrayKernel.kernel );
SAFE_RELEASE( collideCylinderKernel.constBuffer );
SAFE_RELEASE( collideCylinderKernel.kernel );
m_shadersInitialized = false;
}
void btDX11SoftBodySolver::optimize( btAlignedObjectArray< btSoftBody * > &softBodies )
void btDX11SoftBodySolver::copyBackToSoftBodies()
{
if( m_softBodySet.size() != softBodies.size() )
// Move the vertex data back to the host first
m_vertexData.moveFromAccelerator();
// Loop over soft bodies, copying all the vertex positions back for each body in turn
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
{
btAcceleratedSoftBodyInterface *softBodyInterface = m_softBodySet[ softBodyIndex ];
btSoftBody *softBody = softBodyInterface->getSoftBody();
int firstVertex = softBodyInterface->getFirstVertex();
int numVertices = softBodyInterface->getNumVertices();
// Copy vertices from solver back into the softbody
for( int vertex = 0; vertex < numVertices; ++vertex )
{
using Vectormath::Aos::Point3;
Point3 vertexPosition( getVertexData().getVertexPositions()[firstVertex + vertex] );
softBody->m_nodes[vertex].m_x.setX( vertexPosition.getX() );
softBody->m_nodes[vertex].m_x.setY( vertexPosition.getY() );
softBody->m_nodes[vertex].m_x.setZ( vertexPosition.getZ() );
softBody->m_nodes[vertex].m_n.setX( vertexPosition.getX() );
softBody->m_nodes[vertex].m_n.setY( vertexPosition.getY() );
softBody->m_nodes[vertex].m_n.setZ( vertexPosition.getZ() );
}
}
} // btDX11SoftBodySolver::copyBackToSoftBodies
void btDX11SoftBodySolver::optimize( btAlignedObjectArray< btSoftBody * > &softBodies, bool forceUpdate )
{
if( forceUpdate || m_softBodySet.size() != softBodies.size() )
{
// Have a change in the soft body set so update, reloading all the data
getVertexData().clear();
@@ -622,7 +668,7 @@ void btDX11SoftBodySolver::optimize( btAlignedObjectArray< btSoftBody * > &softB
using Vectormath::Aos::Point3;
// Create SoftBody that will store the information within the solver
btDX11AcceleratedSoftBodyInterface *newSoftBody = new btDX11AcceleratedSoftBodyInterface( softBody );
btAcceleratedSoftBodyInterface *newSoftBody = new btAcceleratedSoftBodyInterface( softBody );
m_softBodySet.push_back( newSoftBody );
m_perClothAcceleration.push_back( toVector3(softBody->getWorldInfo()->m_gravity) );
@@ -631,6 +677,11 @@ void btDX11SoftBodySolver::optimize( btAlignedObjectArray< btSoftBody * > &softB
m_perClothLiftFactor.push_back( softBody->m_cfg.kLF );
m_perClothDragFactor.push_back( softBody->m_cfg.kDG );
m_perClothMediumDensity.push_back(softBody->getWorldInfo()->air_density);
// Simple init values. Actually we'll put 0 and -1 into them at the appropriate time
m_perClothMinBounds.push_back( UIntVector3( 0, 0, 0 ) );
m_perClothMaxBounds.push_back( UIntVector3( UINT_MAX, UINT_MAX, UINT_MAX ) );
m_perClothFriction.push_back( softBody->getFriction() );
m_perClothCollisionObjects.push_back( CollisionObjectIndices(-1, -1) );
// Add space for new vertices and triangles in the default solver for now
// TODO: Include space here for tearing too later
@@ -738,7 +789,11 @@ btSoftBodyTriangleData &btDX11SoftBodySolver::getTriangleData()
bool btDX11SoftBodySolver::checkInitialized()
{
return buildShaders();
if( !m_shadersInitialized )
if( buildShaders() )
m_shadersInitialized = true;
return m_shadersInitialized;
}
void btDX11SoftBodySolver::resetNormalsAndAreas( int numVertices )
@@ -892,6 +947,7 @@ void btDX11SoftBodySolver::updateSoftBodies()
normalizeNormalsAndAreas( numVertices );
} // btDX11SoftBodySolver::updateSoftBodies
@@ -1046,6 +1102,80 @@ float btDX11SoftBodySolver::computeTriangleArea(
return area;
} // btDX11SoftBodySolver::computeTriangleArea
void btDX11SoftBodySolver::updateBounds()
{
using Vectormath::Aos::Point3;
// Interpretation structure for float and int
struct FPRep {
unsigned int mantissa : 23;
unsigned int exponent : 8;
unsigned int sign : 1;
};
union FloatAsInt
{
float floatValue;
int intValue;
unsigned int uintValue;
FPRep fpRep;
};
// Update bounds array to min and max int values to allow easy atomics
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
{
m_perClothMinBounds[softBodyIndex] = UIntVector3( UINT_MAX, UINT_MAX, UINT_MAX );
m_perClothMaxBounds[softBodyIndex] = UIntVector3( 0, 0, 0 );
}
m_dx11PerClothMinBounds.moveToGPU();
m_dx11PerClothMaxBounds.moveToGPU();
computeBounds( );
m_dx11PerClothMinBounds.moveFromGPU();
m_dx11PerClothMaxBounds.moveFromGPU();
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
{
UIntVector3 minBoundUInt = m_perClothMinBounds[softBodyIndex];
UIntVector3 maxBoundUInt = m_perClothMaxBounds[softBodyIndex];
// Convert back to float
FloatAsInt fai;
btVector3 minBound;
fai.uintValue = minBoundUInt.x;
fai.uintValue ^= (((fai.uintValue >> 31) - 1) | 0x80000000);
minBound.setX( fai.floatValue );
fai.uintValue = minBoundUInt.y;
fai.uintValue ^= (((fai.uintValue >> 31) - 1) | 0x80000000);
minBound.setY( fai.floatValue );
fai.uintValue = minBoundUInt.z;
fai.uintValue ^= (((fai.uintValue >> 31) - 1) | 0x80000000);
minBound.setZ( fai.floatValue );
btVector3 maxBound;
fai.uintValue = maxBoundUInt.x;
fai.uintValue ^= (((fai.uintValue >> 31) - 1) | 0x80000000);
maxBound.setX( fai.floatValue );
fai.uintValue = maxBoundUInt.y;
fai.uintValue ^= (((fai.uintValue >> 31) - 1) | 0x80000000);
maxBound.setY( fai.floatValue );
fai.uintValue = maxBoundUInt.z;
fai.uintValue ^= (((fai.uintValue >> 31) - 1) | 0x80000000);
maxBound.setZ( fai.floatValue );
// And finally assign to the soft body
m_softBodySet[softBodyIndex]->updateBounds( minBound, maxBound );
}
}
void btDX11SoftBodySolver::updateConstants( float timeStep )
{
using namespace Vectormath::Aos;
@@ -1074,6 +1204,59 @@ void btDX11SoftBodySolver::updateConstants( float timeStep )
}
} // btDX11SoftBodySolver::updateConstants
/**
* Sort the collision object details array and generate indexing into it for the per-cloth collision object array.
*/
void btDX11SoftBodySolver::prepareCollisionConstraints()
{
// First do a simple sort on the collision objects
btAlignedObjectArray<int> numObjectsPerClothPrefixSum;
btAlignedObjectArray<int> numObjectsPerCloth;
numObjectsPerCloth.resize( m_softBodySet.size(), 0 );
numObjectsPerClothPrefixSum.resize( m_softBodySet.size(), 0 );
class QuickSortCompare
{
public:
bool operator() ( const CollisionShapeDescription& a, const CollisionShapeDescription& b )
{
return ( a.softBodyIdentifier < b.softBodyIdentifier );
}
};
QuickSortCompare comparator;
m_collisionObjectDetails.quickSort( comparator );
// Generating indexing for perClothCollisionObjects
// First clear the previous values with the "no collision object for cloth" constant
for( int clothIndex = 0; clothIndex < m_perClothCollisionObjects.size(); ++clothIndex )
{
m_perClothCollisionObjects[clothIndex].firstObject = -1;
m_perClothCollisionObjects[clothIndex].endObject = -1;
}
int currentCloth = 0;
int startIndex = 0;
for( int collisionObject = 0; collisionObject < m_collisionObjectDetails.size(); ++collisionObject )
{
int nextCloth = m_collisionObjectDetails[collisionObject].softBodyIdentifier;
if( nextCloth != currentCloth )
{
// Changed cloth in the array
// Set the end index and the range is what we need for currentCloth
m_perClothCollisionObjects[currentCloth].firstObject = startIndex;
m_perClothCollisionObjects[currentCloth].endObject = collisionObject;
currentCloth = nextCloth;
startIndex = collisionObject;
}
}
// And update last cloth
m_perClothCollisionObjects[currentCloth].firstObject = startIndex;
m_perClothCollisionObjects[currentCloth].endObject = m_collisionObjectDetails.size();
} // btDX11SoftBodySolver::prepareCollisionConstraints
void btDX11SoftBodySolver::solveConstraints( float solverdt )
@@ -1115,6 +1298,9 @@ void btDX11SoftBodySolver::solveConstraints( float solverdt )
}
}
prepareCollisionConstraints();
// Compute new positions from velocity
// Also update the previous position so that our position computation is now based on the new position from the velocity solution
// rather than based directly on the original positions
@@ -1139,7 +1325,8 @@ void btDX11SoftBodySolver::solveConstraints( float solverdt )
} // for( int iteration = 0; iteration < m_numberOfPositionIterations ; ++iteration )
updateVelocitiesFromPositionsWithoutVelocities( 1.f/solverdt );
// At this point assume that the force array is blank - we will overwrite it
solveCollisionsAndUpdateVelocities( 1.f/solverdt );
} // btDX11SoftBodySolver::solveConstraints
@@ -1435,6 +1622,114 @@ void btDX11SoftBodySolver::updateVelocitiesFromPositionsWithoutVelocities( float
} // btDX11SoftBodySolver::updateVelocitiesFromPositionsWithoutVelocities
void btDX11SoftBodySolver::computeBounds( )
{
ComputeBoundsCB constBuffer;
m_vertexData.moveToAccelerator();
// Set the first link of the batch
// and the batch size
constBuffer.numNodes = m_vertexData.getNumVertices();
constBuffer.numSoftBodies = m_softBodySet.size();
D3D11_MAPPED_SUBRESOURCE MappedResource = {0};
m_dx11Context->Map( computeBoundsKernel.constBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource );
memcpy( MappedResource.pData, &constBuffer, sizeof(ComputeBoundsCB) );
m_dx11Context->Unmap( computeBoundsKernel.constBuffer, 0 );
m_dx11Context->CSSetConstantBuffers( 0, 1, &computeBoundsKernel.constBuffer );
// Set resources and dispatch
m_dx11Context->CSSetShaderResources( 0, 1, &(m_vertexData.m_dx11ClothIdentifier.getSRV()) );
m_dx11Context->CSSetShaderResources( 1, 1, &(m_vertexData.m_dx11VertexPosition.getSRV()) );
m_dx11Context->CSSetUnorderedAccessViews( 0, 1, &(m_dx11PerClothMinBounds.getUAV()), NULL );
m_dx11Context->CSSetUnorderedAccessViews( 1, 1, &(m_dx11PerClothMaxBounds.getUAV()), NULL );
// Execute the kernel
m_dx11Context->CSSetShader( computeBoundsKernel.kernel, NULL, 0 );
int numBlocks = (constBuffer.numNodes + (128-1)) / 128;
m_dx11Context->Dispatch(numBlocks , 1, 1 );
{
// Tidy up
ID3D11ShaderResourceView* pViewNULL = NULL;
m_dx11Context->CSSetShaderResources( 0, 1, &pViewNULL );
m_dx11Context->CSSetShaderResources( 1, 1, &pViewNULL );
ID3D11UnorderedAccessView* pUAViewNULL = NULL;
m_dx11Context->CSSetUnorderedAccessViews( 0, 1, &pUAViewNULL, NULL );
m_dx11Context->CSSetUnorderedAccessViews( 1, 1, &pUAViewNULL, NULL );
ID3D11Buffer *pBufferNull = NULL;
m_dx11Context->CSSetConstantBuffers( 0, 1, &pBufferNull );
}
}
void btDX11SoftBodySolver::solveCollisionsAndUpdateVelocities( float isolverdt )
{
// Copy kernel parameters to GPU
m_vertexData.moveToAccelerator();
m_dx11PerClothFriction.moveToGPU();
m_dx11PerClothDampingFactor.moveToGPU();
m_dx11PerClothCollisionObjects.moveToGPU();
m_dx11CollisionObjectDetails.moveToGPU();
SolveCollisionsAndUpdateVelocitiesCB constBuffer;
// Set the first link of the batch
// and the batch size
constBuffer.numNodes = m_vertexData.getNumVertices();
constBuffer.isolverdt = isolverdt;
D3D11_MAPPED_SUBRESOURCE MappedResource = {0};
m_dx11Context->Map( solveCollisionsAndUpdateVelocitiesKernel.constBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource );
memcpy( MappedResource.pData, &constBuffer, sizeof(SolveCollisionsAndUpdateVelocitiesCB) );
m_dx11Context->Unmap( solveCollisionsAndUpdateVelocitiesKernel.constBuffer, 0 );
m_dx11Context->CSSetConstantBuffers( 0, 1, &solveCollisionsAndUpdateVelocitiesKernel.constBuffer );
// Set resources and dispatch
m_dx11Context->CSSetShaderResources( 0, 1, &(m_vertexData.m_dx11ClothIdentifier.getSRV()) );
m_dx11Context->CSSetShaderResources( 1, 1, &(m_vertexData.m_dx11VertexPreviousPosition.getSRV()) );
m_dx11Context->CSSetShaderResources( 2, 1, &(m_dx11PerClothFriction.getSRV()) );
m_dx11Context->CSSetShaderResources( 3, 1, &(m_dx11PerClothDampingFactor.getSRV()) );
m_dx11Context->CSSetShaderResources( 4, 1, &(m_dx11PerClothCollisionObjects.getSRV()) );
m_dx11Context->CSSetShaderResources( 5, 1, &(m_dx11CollisionObjectDetails.getSRV()) );
m_dx11Context->CSSetUnorderedAccessViews( 0, 1, &(m_vertexData.m_dx11VertexForceAccumulator.getUAV()), NULL );
m_dx11Context->CSSetUnorderedAccessViews( 1, 1, &(m_vertexData.m_dx11VertexVelocity.getUAV()), NULL );
m_dx11Context->CSSetUnorderedAccessViews( 2, 1, &(m_vertexData.m_dx11VertexPosition.getUAV()), NULL );
// Execute the kernel
m_dx11Context->CSSetShader( solveCollisionsAndUpdateVelocitiesKernel.kernel, NULL, 0 );
int numBlocks = (constBuffer.numNodes + (128-1)) / 128;
m_dx11Context->Dispatch(numBlocks , 1, 1 );
{
// Tidy up
ID3D11ShaderResourceView* pViewNULL = NULL;
m_dx11Context->CSSetShaderResources( 0, 1, &pViewNULL );
m_dx11Context->CSSetShaderResources( 1, 1, &pViewNULL );
m_dx11Context->CSSetShaderResources( 2, 1, &pViewNULL );
m_dx11Context->CSSetShaderResources( 3, 1, &pViewNULL );
m_dx11Context->CSSetShaderResources( 4, 1, &pViewNULL );
m_dx11Context->CSSetShaderResources( 5, 1, &pViewNULL );
ID3D11UnorderedAccessView* pUAViewNULL = NULL;
m_dx11Context->CSSetUnorderedAccessViews( 0, 1, &pUAViewNULL, NULL );
m_dx11Context->CSSetUnorderedAccessViews( 1, 1, &pUAViewNULL, NULL );
m_dx11Context->CSSetUnorderedAccessViews( 2, 1, &pUAViewNULL, NULL );
ID3D11Buffer *pBufferNull = NULL;
m_dx11Context->CSSetConstantBuffers( 0, 1, &pBufferNull );
}
} // btDX11SoftBodySolver::solveCollisionsAndUpdateVelocities
// End kernel dispatches
/////////////////////////////////////
@@ -1451,23 +1746,51 @@ void btDX11SoftBodySolver::updateVelocitiesFromPositionsWithoutVelocities( float
btDX11AcceleratedSoftBodyInterface *btDX11SoftBodySolver::findSoftBodyInterface( const btSoftBody* const softBody )
btDX11SoftBodySolver::btAcceleratedSoftBodyInterface *btDX11SoftBodySolver::findSoftBodyInterface( const btSoftBody* const softBody )
{
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
{
btDX11AcceleratedSoftBodyInterface *softBodyInterface = m_softBodySet[softBodyIndex];
btAcceleratedSoftBodyInterface *softBodyInterface = m_softBodySet[softBodyIndex];
if( softBodyInterface->getSoftBody() == softBody )
return softBodyInterface;
}
return 0;
}
void btDX11SoftBodySolver::copySoftBodyToVertexBuffer( const btSoftBody * const softBody, btVertexBufferDescriptor *vertexBuffer )
const btDX11SoftBodySolver::btAcceleratedSoftBodyInterface * const btDX11SoftBodySolver::findSoftBodyInterface( const btSoftBody* const softBody ) const
{
checkInitialized();
btDX11AcceleratedSoftBodyInterface *currentCloth = findSoftBodyInterface( softBody );
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
{
btAcceleratedSoftBodyInterface *softBodyInterface = m_softBodySet[softBodyIndex];
if( softBodyInterface->getSoftBody() == softBody )
return softBodyInterface;
}
return 0;
}
int btDX11SoftBodySolver::findSoftBodyIndex( const btSoftBody* const softBody )
{
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
{
btAcceleratedSoftBodyInterface *softBodyInterface = m_softBodySet[softBodyIndex];
if( softBodyInterface->getSoftBody() == softBody )
return softBodyIndex;
}
return 1;
}
void btSoftBodySolverOutputDXtoCPU::copySoftBodyToVertexBuffer( const btSoftBody * const softBody, btVertexBufferDescriptor *vertexBuffer )
{
btSoftBodySolver *solver = softBody->getSoftBodySolver();
btAssert( solver->getSolverType() == btSoftBodySolver::DX_SOLVER || solver->getSolverType() == btSoftBodySolver::DX_SIMD_SOLVER );
btDX11SoftBodySolver *dxSolver = static_cast< btDX11SoftBodySolver * >( solver );
btDX11SoftBodySolver::btAcceleratedSoftBodyInterface * currentCloth = dxSolver->findSoftBodyInterface( softBody );
btSoftBodyVertexDataDX11 &vertexData( dxSolver->m_vertexData );
const int firstVertex = currentCloth->getFirstVertex();
const int lastVertex = firstVertex + currentCloth->getNumVertices();
@@ -1475,8 +1798,8 @@ void btDX11SoftBodySolver::copySoftBodyToVertexBuffer( const btSoftBody * const
if( vertexBuffer->getBufferType() == btVertexBufferDescriptor::CPU_BUFFER )
{
// If we're doing a CPU-buffer copy must copy the data back to the host first
m_vertexData.m_dx11VertexPosition.copyFromGPU();
m_vertexData.m_dx11VertexNormal.copyFromGPU();
vertexData.m_dx11VertexPosition.copyFromGPU();
vertexData.m_dx11VertexNormal.copyFromGPU();
const int firstVertex = currentCloth->getFirstVertex();
const int lastVertex = firstVertex + currentCloth->getNumVertices();
@@ -1491,7 +1814,7 @@ void btDX11SoftBodySolver::copySoftBodyToVertexBuffer( const btSoftBody * const
for( int vertexIndex = firstVertex; vertexIndex < lastVertex; ++vertexIndex )
{
Vectormath::Aos::Point3 position = m_vertexData.getPosition(vertexIndex);
Vectormath::Aos::Point3 position = vertexData.getPosition(vertexIndex);
*(vertexPointer + 0) = position.getX();
*(vertexPointer + 1) = position.getY();
*(vertexPointer + 2) = position.getZ();
@@ -1506,13 +1829,82 @@ void btDX11SoftBodySolver::copySoftBodyToVertexBuffer( const btSoftBody * const
for( int vertexIndex = firstVertex; vertexIndex < lastVertex; ++vertexIndex )
{
Vectormath::Aos::Vector3 normal = m_vertexData.getNormal(vertexIndex);
Vectormath::Aos::Vector3 normal = vertexData.getNormal(vertexIndex);
*(normalPointer + 0) = normal.getX();
*(normalPointer + 1) = normal.getY();
*(normalPointer + 2) = normal.getZ();
normalPointer += normalStride;
}
}
}
} // btDX11SoftBodySolver::outputToVertexBuffers
bool btSoftBodySolverOutputDXtoDX::checkInitialized()
{
if( !m_shadersInitialized )
if( buildShaders() )
m_shadersInitialized = true;
return m_shadersInitialized;
}
void btSoftBodySolverOutputDXtoDX::releaseKernels()
{
SAFE_RELEASE( outputToVertexArrayWithNormalsKernel.constBuffer );
SAFE_RELEASE( outputToVertexArrayWithNormalsKernel.kernel );
SAFE_RELEASE( outputToVertexArrayWithoutNormalsKernel.constBuffer );
SAFE_RELEASE( outputToVertexArrayWithoutNormalsKernel.kernel );
m_shadersInitialized = false;
}
bool btSoftBodySolverOutputDXtoDX::buildShaders()
{
// Ensure current kernels are released first
releaseKernels();
bool returnVal = true;
if( m_shadersInitialized )
return true;
outputToVertexArrayWithNormalsKernel = dxFunctions.compileComputeShaderFromString( OutputToVertexArrayHLSLString, "OutputToVertexArrayWithNormalsKernel", sizeof(OutputToVertexArrayCB) );
if( !outputToVertexArrayWithNormalsKernel.constBuffer)
returnVal = false;
outputToVertexArrayWithoutNormalsKernel = dxFunctions.compileComputeShaderFromString( OutputToVertexArrayHLSLString, "OutputToVertexArrayWithoutNormalsKernel", sizeof(OutputToVertexArrayCB) );
if( !outputToVertexArrayWithoutNormalsKernel.constBuffer )
returnVal = false;
if( returnVal )
m_shadersInitialized = true;
return returnVal;
}
void btSoftBodySolverOutputDXtoDX::copySoftBodyToVertexBuffer( const btSoftBody * const softBody, btVertexBufferDescriptor *vertexBuffer )
{
btSoftBodySolver *solver = softBody->getSoftBodySolver();
btAssert( solver->getSolverType() == btSoftBodySolver::DX_SOLVER || solver->getSolverType() == btSoftBodySolver::DX_SIMD_SOLVER );
btDX11SoftBodySolver *dxSolver = static_cast< btDX11SoftBodySolver * >( solver );
checkInitialized();
btDX11SoftBodySolver::btAcceleratedSoftBodyInterface * currentCloth = dxSolver->findSoftBodyInterface( softBody );
btSoftBodyVertexDataDX11 &vertexData( dxSolver->m_vertexData );
const int firstVertex = currentCloth->getFirstVertex();
const int lastVertex = firstVertex + currentCloth->getNumVertices();
if( vertexBuffer->getBufferType() == btVertexBufferDescriptor::CPU_BUFFER )
{
btSoftBodySolverOutputDXtoDX::copySoftBodyToVertexBuffer( softBody, vertexBuffer );
} else if( vertexBuffer->getBufferType() == btVertexBufferDescriptor::DX11_BUFFER )
{
// Do a DX11 copy shader DX to DX copy
@@ -1539,86 +1931,43 @@ void btDX11SoftBodySolver::copySoftBodyToVertexBuffer( const btSoftBody * const
// TODO: factor this out. Number of nodes is static and sdt might be, too, we can update this just once on setup
D3D11_MAPPED_SUBRESOURCE MappedResource = {0};
m_dx11Context->Map( outputToVertexArrayConstBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource );
dxFunctions.m_dx11Context->Map( outputToVertexArrayConstBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedResource );
memcpy( MappedResource.pData, &constBuffer, sizeof(OutputToVertexArrayCB) );
m_dx11Context->Unmap( outputToVertexArrayConstBuffer, 0 );
m_dx11Context->CSSetConstantBuffers( 0, 1, &outputToVertexArrayConstBuffer );
dxFunctions.m_dx11Context->Unmap( outputToVertexArrayConstBuffer, 0 );
dxFunctions.m_dx11Context->CSSetConstantBuffers( 0, 1, &outputToVertexArrayConstBuffer );
// Set resources and dispatch
m_dx11Context->CSSetShaderResources( 0, 1, &(m_vertexData.m_dx11VertexPosition.getSRV()) );
m_dx11Context->CSSetShaderResources( 1, 1, &(m_vertexData.m_dx11VertexNormal.getSRV()) );
dxFunctions.m_dx11Context->CSSetShaderResources( 0, 1, &(vertexData.m_dx11VertexPosition.getSRV()) );
dxFunctions.m_dx11Context->CSSetShaderResources( 1, 1, &(vertexData.m_dx11VertexNormal.getSRV()) );
ID3D11UnorderedAccessView* dx11UAV = dx11VertexBuffer->getDX11UAV();
m_dx11Context->CSSetUnorderedAccessViews( 0, 1, &(dx11UAV), NULL );
dxFunctions.m_dx11Context->CSSetUnorderedAccessViews( 0, 1, &(dx11UAV), NULL );
// Execute the kernel
m_dx11Context->CSSetShader( outputToVertexArrayShader, NULL, 0 );
dxFunctions.m_dx11Context->CSSetShader( outputToVertexArrayShader, NULL, 0 );
int numBlocks = (constBuffer.numNodes + (128-1)) / 128;
m_dx11Context->Dispatch(numBlocks, 1, 1 );
dxFunctions.m_dx11Context->Dispatch(numBlocks, 1, 1 );
{
// Tidy up
ID3D11ShaderResourceView* pViewNULL = NULL;
m_dx11Context->CSSetShaderResources( 0, 1, &pViewNULL );
m_dx11Context->CSSetShaderResources( 1, 1, &pViewNULL );
dxFunctions.m_dx11Context->CSSetShaderResources( 0, 1, &pViewNULL );
dxFunctions.m_dx11Context->CSSetShaderResources( 1, 1, &pViewNULL );
ID3D11UnorderedAccessView* pUAViewNULL = NULL;
m_dx11Context->CSSetUnorderedAccessViews( 0, 1, &pUAViewNULL, NULL );
dxFunctions.m_dx11Context->CSSetUnorderedAccessViews( 0, 1, &pUAViewNULL, NULL );
ID3D11Buffer *pBufferNull = NULL;
m_dx11Context->CSSetConstantBuffers( 0, 1, &pBufferNull );
dxFunctions.m_dx11Context->CSSetConstantBuffers( 0, 1, &pBufferNull );
}
}
if( vertexBuffer->getBufferType() == btVertexBufferDescriptor::CPU_BUFFER )
{
const int firstVertex = currentCloth->getFirstVertex();
const int lastVertex = firstVertex + currentCloth->getNumVertices();
const btCPUVertexBufferDescriptor *cpuVertexBuffer = static_cast< btCPUVertexBufferDescriptor* >(vertexBuffer);
float *basePointer = cpuVertexBuffer->getBasePointer();
if( vertexBuffer->hasVertexPositions() )
{
const int vertexOffset = cpuVertexBuffer->getVertexOffset();
const int vertexStride = cpuVertexBuffer->getVertexStride();
float *vertexPointer = basePointer + vertexOffset;
for( int vertexIndex = firstVertex; vertexIndex < lastVertex; ++vertexIndex )
{
Vectormath::Aos::Point3 position = m_vertexData.getPosition(vertexIndex);
*(vertexPointer + 0) = position.getX();
*(vertexPointer + 1) = position.getY();
*(vertexPointer + 2) = position.getZ();
vertexPointer += vertexStride;
}
}
if( vertexBuffer->hasNormals() )
{
const int normalOffset = cpuVertexBuffer->getNormalOffset();
const int normalStride = cpuVertexBuffer->getNormalStride();
float *normalPointer = basePointer + normalOffset;
for( int vertexIndex = firstVertex; vertexIndex < lastVertex; ++vertexIndex )
{
Vectormath::Aos::Vector3 normal = m_vertexData.getNormal(vertexIndex);
*(normalPointer + 0) = normal.getX();
*(normalPointer + 1) = normal.getY();
*(normalPointer + 2) = normal.getZ();
normalPointer += normalStride;
}
}
}
} // btDX11SoftBodySolver::outputToVertexBuffers
btDX11SoftBodySolver::KernelDesc btDX11SoftBodySolver::compileComputeShaderFromString( const char* shaderString, const char* shaderName, int constBufferSize )
DXFunctions::KernelDesc DXFunctions::compileComputeShaderFromString( const char* shaderString, const char* shaderName, int constBufferSize, D3D10_SHADER_MACRO *compileMacros )
{
const char *cs5String = "cs_5_0";
@@ -1626,12 +1975,12 @@ btDX11SoftBodySolver::KernelDesc btDX11SoftBodySolver::compileComputeShaderFromS
ID3DBlob* pErrorBlob = NULL;
ID3DBlob* pBlob = NULL;
ID3D11ComputeShader* kernelPointer = 0;
hr = D3DX11CompileFromMemory(
shaderString,
strlen(shaderString),
shaderName, // file name
NULL,
shaderName,
compileMacros,
NULL,
shaderName,
cs5String,
@@ -1647,13 +1996,14 @@ btDX11SoftBodySolver::KernelDesc btDX11SoftBodySolver::compileComputeShaderFromS
{
if( pErrorBlob ) {
btAssert( "Compilation of compute shader failed\n" );
//OutputDebugStringA( (char*)pErrorBlob->GetBufferPointer() );
char *debugString = (char*)pErrorBlob->GetBufferPointer();
OutputDebugStringA( debugString );
}
SAFE_RELEASE( pErrorBlob );
SAFE_RELEASE( pBlob );
btDX11SoftBodySolver::KernelDesc descriptor;
DXFunctions::KernelDesc descriptor;
descriptor.kernel = 0;
descriptor.constBuffer = 0;
return descriptor;
@@ -1663,7 +2013,7 @@ btDX11SoftBodySolver::KernelDesc btDX11SoftBodySolver::compileComputeShaderFromS
hr = m_dx11Device->CreateComputeShader( pBlob->GetBufferPointer(), pBlob->GetBufferSize(), NULL, &kernelPointer );
if( FAILED( hr ) )
{
btDX11SoftBodySolver::KernelDesc descriptor;
DXFunctions::KernelDesc descriptor;
descriptor.kernel = 0;
descriptor.constBuffer = 0;
return descriptor;
@@ -1692,60 +2042,65 @@ btDX11SoftBodySolver::KernelDesc btDX11SoftBodySolver::compileComputeShaderFromS
SAFE_RELEASE( pErrorBlob );
SAFE_RELEASE( pBlob );
btDX11SoftBodySolver::KernelDesc descriptor;
DXFunctions::KernelDesc descriptor;
descriptor.kernel = kernelPointer;
descriptor.constBuffer = constBuffer;
return descriptor;
} // compileComputeShader
bool btDX11SoftBodySolver::buildShaders()
{
// Ensure current kernels are released first
releaseKernels();
bool returnVal = true;
if( m_shadersInitialized )
return true;
prepareLinksKernel = compileComputeShaderFromString( PrepareLinksHLSLString, "PrepareLinksKernel", sizeof(PrepareLinksCB) );
prepareLinksKernel = dxFunctions.compileComputeShaderFromString( PrepareLinksHLSLString, "PrepareLinksKernel", sizeof(PrepareLinksCB) );
if( !prepareLinksKernel.constBuffer )
returnVal = false;
updatePositionsFromVelocitiesKernel = compileComputeShaderFromString( UpdatePositionsFromVelocitiesHLSLString, "UpdatePositionsFromVelocitiesKernel", sizeof(UpdatePositionsFromVelocitiesCB) );
updatePositionsFromVelocitiesKernel = dxFunctions.compileComputeShaderFromString( UpdatePositionsFromVelocitiesHLSLString, "UpdatePositionsFromVelocitiesKernel", sizeof(UpdatePositionsFromVelocitiesCB) );
if( !updatePositionsFromVelocitiesKernel.constBuffer )
returnVal = false;
solvePositionsFromLinksKernel = compileComputeShaderFromString( SolvePositionsHLSLString, "SolvePositionsFromLinksKernel", sizeof(SolvePositionsFromLinksKernelCB) );
solvePositionsFromLinksKernel = dxFunctions.compileComputeShaderFromString( SolvePositionsHLSLString, "SolvePositionsFromLinksKernel", sizeof(SolvePositionsFromLinksKernelCB) );
if( !updatePositionsFromVelocitiesKernel.constBuffer )
returnVal = false;
vSolveLinksKernel = compileComputeShaderFromString( VSolveLinksHLSLString, "VSolveLinksKernel", sizeof(VSolveLinksCB) );
vSolveLinksKernel = dxFunctions.compileComputeShaderFromString( VSolveLinksHLSLString, "VSolveLinksKernel", sizeof(VSolveLinksCB) );
if( !vSolveLinksKernel.constBuffer )
returnVal = false;
updateVelocitiesFromPositionsWithVelocitiesKernel = compileComputeShaderFromString( UpdateNodesHLSLString, "updateVelocitiesFromPositionsWithVelocitiesKernel", sizeof(UpdateVelocitiesFromPositionsWithVelocitiesCB) );
updateVelocitiesFromPositionsWithVelocitiesKernel = dxFunctions.compileComputeShaderFromString( UpdateNodesHLSLString, "updateVelocitiesFromPositionsWithVelocitiesKernel", sizeof(UpdateVelocitiesFromPositionsWithVelocitiesCB) );
if( !updateVelocitiesFromPositionsWithVelocitiesKernel.constBuffer )
returnVal = false;
updateVelocitiesFromPositionsWithoutVelocitiesKernel = compileComputeShaderFromString( UpdatePositionsHLSLString, "updateVelocitiesFromPositionsWithoutVelocitiesKernel", sizeof(UpdateVelocitiesFromPositionsWithoutVelocitiesCB) );
updateVelocitiesFromPositionsWithoutVelocitiesKernel = dxFunctions.compileComputeShaderFromString( UpdatePositionsHLSLString, "updateVelocitiesFromPositionsWithoutVelocitiesKernel", sizeof(UpdateVelocitiesFromPositionsWithoutVelocitiesCB) );
if( !updateVelocitiesFromPositionsWithoutVelocitiesKernel.constBuffer )
returnVal = false;
integrateKernel = compileComputeShaderFromString( IntegrateHLSLString, "IntegrateKernel", sizeof(IntegrateCB) );
integrateKernel = dxFunctions.compileComputeShaderFromString( IntegrateHLSLString, "IntegrateKernel", sizeof(IntegrateCB) );
if( !integrateKernel.constBuffer )
returnVal = false;
applyForcesKernel = compileComputeShaderFromString( ApplyForcesHLSLString, "ApplyForcesKernel", sizeof(ApplyForcesCB) );
applyForcesKernel = dxFunctions.compileComputeShaderFromString( ApplyForcesHLSLString, "ApplyForcesKernel", sizeof(ApplyForcesCB) );
if( !applyForcesKernel.constBuffer )
returnVal = false;
solveCollisionsAndUpdateVelocitiesKernel = dxFunctions.compileComputeShaderFromString( SolveCollisionsAndUpdateVelocitiesHLSLString, "SolveCollisionsAndUpdateVelocitiesKernel", sizeof(SolveCollisionsAndUpdateVelocitiesCB) );
if( !solveCollisionsAndUpdateVelocitiesKernel.constBuffer )
returnVal = false;
// TODO: Rename to UpdateSoftBodies
resetNormalsAndAreasKernel = compileComputeShaderFromString( UpdateNormalsHLSLString, "ResetNormalsAndAreasKernel", sizeof(UpdateSoftBodiesCB) );
resetNormalsAndAreasKernel = dxFunctions.compileComputeShaderFromString( UpdateNormalsHLSLString, "ResetNormalsAndAreasKernel", sizeof(UpdateSoftBodiesCB) );
if( !resetNormalsAndAreasKernel.constBuffer )
returnVal = false;
normalizeNormalsAndAreasKernel = compileComputeShaderFromString( UpdateNormalsHLSLString, "NormalizeNormalsAndAreasKernel", sizeof(UpdateSoftBodiesCB) );
normalizeNormalsAndAreasKernel = dxFunctions.compileComputeShaderFromString( UpdateNormalsHLSLString, "NormalizeNormalsAndAreasKernel", sizeof(UpdateSoftBodiesCB) );
if( !normalizeNormalsAndAreasKernel.constBuffer )
returnVal = false;
updateSoftBodiesKernel = compileComputeShaderFromString( UpdateNormalsHLSLString, "UpdateSoftBodiesKernel", sizeof(UpdateSoftBodiesCB) );
updateSoftBodiesKernel = dxFunctions.compileComputeShaderFromString( UpdateNormalsHLSLString, "UpdateSoftBodiesKernel", sizeof(UpdateSoftBodiesCB) );
if( !updateSoftBodiesKernel.constBuffer )
returnVal = false;
outputToVertexArrayWithNormalsKernel = compileComputeShaderFromString( OutputToVertexArrayHLSLString, "OutputToVertexArrayWithNormalsKernel", sizeof(OutputToVertexArrayCB) );
if( !outputToVertexArrayWithNormalsKernel.constBuffer )
returnVal = false;
outputToVertexArrayWithoutNormalsKernel = compileComputeShaderFromString( OutputToVertexArrayHLSLString, "OutputToVertexArrayWithoutNormalsKernel", sizeof(OutputToVertexArrayCB) );
if( !outputToVertexArrayWithoutNormalsKernel.constBuffer )
computeBoundsKernel = dxFunctions.compileComputeShaderFromString( ComputeBoundsHLSLString, "ComputeBoundsKernel", sizeof(ComputeBoundsCB) );
if( !computeBoundsKernel.constBuffer )
returnVal = false;
@@ -1757,8 +2112,76 @@ bool btDX11SoftBodySolver::buildShaders()
}
static Vectormath::Aos::Transform3 toTransform3( const btTransform &transform )
{
Vectormath::Aos::Transform3 outTransform;
outTransform.setCol(0, toVector3(transform.getBasis().getColumn(0)));
outTransform.setCol(1, toVector3(transform.getBasis().getColumn(1)));
outTransform.setCol(2, toVector3(transform.getBasis().getColumn(2)));
outTransform.setCol(3, toVector3(transform.getOrigin()));
return outTransform;
}
void btDX11SoftBodySolver::btAcceleratedSoftBodyInterface::updateBounds( const btVector3 &lowerBound, const btVector3 &upperBound )
{
float scalarMargin = this->getSoftBody()->getCollisionShape()->getMargin();
btVector3 vectorMargin( scalarMargin, scalarMargin, scalarMargin );
m_softBody->m_bounds[0] = lowerBound - vectorMargin;
m_softBody->m_bounds[1] = upperBound + vectorMargin;
}
void btDX11SoftBodySolver::processCollision( btSoftBody*, btSoftBody* )
{
}
// Add the collision object to the set to deal with for a particular soft body
void btDX11SoftBodySolver::processCollision( btSoftBody *softBody, btCollisionObject* collisionObject )
{
int softBodyIndex = findSoftBodyIndex( softBody );
if( softBodyIndex >= 0 )
{
btCollisionShape *collisionShape = collisionObject->getCollisionShape();
float friction = collisionObject->getFriction();
int shapeType = collisionShape->getShapeType();
if( shapeType == CAPSULE_SHAPE_PROXYTYPE )
{
// Add to the list of expected collision objects
CollisionShapeDescription newCollisionShapeDescription;
newCollisionShapeDescription.softBodyIdentifier = softBodyIndex;
newCollisionShapeDescription.collisionShapeType = shapeType;
// TODO: May need to transpose this matrix either here or in HLSL
newCollisionShapeDescription.shapeTransform = toTransform3(collisionObject->getWorldTransform());
btCapsuleShape *capsule = static_cast<btCapsuleShape*>( collisionShape );
newCollisionShapeDescription.radius = capsule->getRadius();
newCollisionShapeDescription.halfHeight = capsule->getHalfHeight();
newCollisionShapeDescription.margin = capsule->getMargin();
newCollisionShapeDescription.friction = friction;
btRigidBody* body = static_cast< btRigidBody* >( collisionObject );
newCollisionShapeDescription.linearVelocity = toVector3(body->getLinearVelocity());
newCollisionShapeDescription.angularVelocity = toVector3(body->getAngularVelocity());
m_collisionObjectDetails.push_back( newCollisionShapeDescription );
} else {
btAssert("Unsupported collision shape type\n");
}
} else {
btAssert("Unknown soft body");
}
} // btDX11SoftBodySolver::processCollision
void btDX11SoftBodySolver::predictMotion( float timeStep )
{
// Clear the collision shape array for the next frame
// Ensure that the DX11 ones are moved off the device so they will be updated correctly
m_dx11CollisionObjectDetails.changedOnCPU();
m_dx11PerClothCollisionObjects.changedOnCPU();
m_collisionObjectDetails.clear();
// Fill the force arrays with current acceleration data etc
m_perClothWindVelocity.resize( m_softBodySet.size() );
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
@@ -1774,6 +2197,12 @@ void btDX11SoftBodySolver::predictMotion( float timeStep )
// Itegrate motion for all soft bodies dealt with by the solver
integrate( timeStep * getTimeScale() );
// Update bounds
// Will update the bounds for all softBodies being dealt with by the solver and
// set the values in the btSoftBody object
updateBounds();
// End prediction work for solvers
}

View File

@@ -26,184 +26,20 @@ subject to the following restrictions:
/**
* SoftBody class to maintain information about a soft body instance
* within a solver.
* This data addresses the main solver arrays.
*/
class btDX11AcceleratedSoftBodyInterface
class DXFunctions
{
protected:
/** Current number of vertices that are part of this cloth */
int m_numVertices;
/** Maximum number of vertices allocated to be part of this cloth */
int m_maxVertices;
/** Current number of triangles that are part of this cloth */
int m_numTriangles;
/** Maximum number of triangles allocated to be part of this cloth */
int m_maxTriangles;
/** Index of first vertex in the world allocated to this cloth */
int m_firstVertex;
/** Index of first triangle in the world allocated to this cloth */
int m_firstTriangle;
/** Index of first link in the world allocated to this cloth */
int m_firstLink;
/** Maximum number of links allocated to this cloth */
int m_maxLinks;
/** Current number of links allocated to this cloth */
int m_numLinks;
/** The actual soft body this data represents */
btSoftBody *m_softBody;
public:
btDX11AcceleratedSoftBodyInterface( btSoftBody *softBody ) :
m_softBody( softBody )
{
m_numVertices = 0;
m_maxVertices = 0;
m_numTriangles = 0;
m_maxTriangles = 0;
m_firstVertex = 0;
m_firstTriangle = 0;
m_firstLink = 0;
m_maxLinks = 0;
m_numLinks = 0;
}
int getNumVertices()
{
return m_numVertices;
}
int getNumTriangles()
{
return m_numTriangles;
}
int getMaxVertices()
{
return m_maxVertices;
}
int getMaxTriangles()
{
return m_maxTriangles;
}
int getFirstVertex()
{
return m_firstVertex;
}
int getFirstTriangle()
{
return m_firstTriangle;
}
// TODO: All of these set functions will have to do checks and
// update the world because restructuring of the arrays will be necessary
// Reasonable use of "friend"?
void setNumVertices( int numVertices )
{
m_numVertices = numVertices;
}
void setNumTriangles( int numTriangles )
ID3D11Device * m_dx11Device;
ID3D11DeviceContext* m_dx11Context;
DXFunctions( ID3D11Device *dx11Device, ID3D11DeviceContext* dx11Context) :
m_dx11Device( dx11Device ),
m_dx11Context( dx11Context )
{
m_numTriangles = numTriangles;
}
void setMaxVertices( int maxVertices )
{
m_maxVertices = maxVertices;
}
void setMaxTriangles( int maxTriangles )
{
m_maxTriangles = maxTriangles;
}
void setFirstVertex( int firstVertex )
{
m_firstVertex = firstVertex;
}
void setFirstTriangle( int firstTriangle )
{
m_firstTriangle = firstTriangle;
}
void setMaxLinks( int maxLinks )
{
m_maxLinks = maxLinks;
}
void setNumLinks( int numLinks )
{
m_numLinks = numLinks;
}
void setFirstLink( int firstLink )
{
m_firstLink = firstLink;
}
int getMaxLinks()
{
return m_maxLinks;
}
int getNumLinks()
{
return m_numLinks;
}
int getFirstLink()
{
return m_firstLink;
}
btSoftBody* getSoftBody()
{
return m_softBody;
}
#if 0
void setAcceleration( Vectormath::Aos::Vector3 acceleration )
{
m_currentSolver->setPerClothAcceleration( m_clothIdentifier, acceleration );
}
void setWindVelocity( Vectormath::Aos::Vector3 windVelocity )
{
m_currentSolver->setPerClothWindVelocity( m_clothIdentifier, windVelocity );
}
/**
* Set the density of the air in which the cloth is situated.
*/
void setAirDensity( btScalar density )
{
m_currentSolver->setPerClothMediumDensity( m_clothIdentifier, static_cast<float>(density) );
}
/**
* Add a collision object to this soft body.
*/
void addCollisionObject( btCollisionObject *collisionObject )
{
m_currentSolver->addCollisionObjectForSoftBody( m_clothIdentifier, collisionObject );
}
#endif
};
class btDX11SoftBodySolver : public btSoftBodySolver
{
public:
class KernelDesc
{
protected:
@@ -226,6 +62,238 @@ public:
}
};
/**
* Compile a compute shader kernel from a string and return the appropriate KernelDesc object.
*/
KernelDesc compileComputeShaderFromString( const char* shaderString, const char* shaderName, int constBufferSize, D3D10_SHADER_MACRO *compileMacros = 0 );
};
class btDX11SoftBodySolver : public btSoftBodySolver
{
protected:
/**
* Entry in the collision shape array.
* Specifies the shape type, the transform matrix and the necessary details of the collisionShape.
*/
struct CollisionShapeDescription
{
Vectormath::Aos::Transform3 shapeTransform;
Vectormath::Aos::Vector3 linearVelocity;
Vectormath::Aos::Vector3 angularVelocity;
int softBodyIdentifier;
int collisionShapeType;
// Both needed for capsule
float radius;
float halfHeight;
float margin;
float friction;
CollisionShapeDescription()
{
collisionShapeType = 0;
margin = 0;
friction = 0;
}
};
struct UIntVector3
{
UIntVector3()
{
x = 0;
y = 0;
z = 0;
_padding = 0;
}
UIntVector3( unsigned int x_, unsigned int y_, unsigned int z_ )
{
x = x_;
y = y_;
z = z_;
_padding = 0;
}
unsigned int x;
unsigned int y;
unsigned int z;
unsigned int _padding;
};
public:
/**
* SoftBody class to maintain information about a soft body instance
* within a solver.
* This data addresses the main solver arrays.
*/
class btAcceleratedSoftBodyInterface
{
protected:
/** Current number of vertices that are part of this cloth */
int m_numVertices;
/** Maximum number of vertices allocated to be part of this cloth */
int m_maxVertices;
/** Current number of triangles that are part of this cloth */
int m_numTriangles;
/** Maximum number of triangles allocated to be part of this cloth */
int m_maxTriangles;
/** Index of first vertex in the world allocated to this cloth */
int m_firstVertex;
/** Index of first triangle in the world allocated to this cloth */
int m_firstTriangle;
/** Index of first link in the world allocated to this cloth */
int m_firstLink;
/** Maximum number of links allocated to this cloth */
int m_maxLinks;
/** Current number of links allocated to this cloth */
int m_numLinks;
/** The actual soft body this data represents */
btSoftBody *m_softBody;
public:
btAcceleratedSoftBodyInterface( btSoftBody *softBody ) :
m_softBody( softBody )
{
m_numVertices = 0;
m_maxVertices = 0;
m_numTriangles = 0;
m_maxTriangles = 0;
m_firstVertex = 0;
m_firstTriangle = 0;
m_firstLink = 0;
m_maxLinks = 0;
m_numLinks = 0;
}
int getNumVertices() const
{
return m_numVertices;
}
int getNumTriangles() const
{
return m_numTriangles;
}
int getMaxVertices() const
{
return m_maxVertices;
}
int getMaxTriangles() const
{
return m_maxTriangles;
}
int getFirstVertex() const
{
return m_firstVertex;
}
int getFirstTriangle() const
{
return m_firstTriangle;
}
/**
* Update the bounds in the btSoftBody object
*/
void updateBounds( const btVector3 &lowerBound, const btVector3 &upperBound );
// TODO: All of these set functions will have to do checks and
// update the world because restructuring of the arrays will be necessary
// Reasonable use of "friend"?
void setNumVertices( int numVertices )
{
m_numVertices = numVertices;
}
void setNumTriangles( int numTriangles )
{
m_numTriangles = numTriangles;
}
void setMaxVertices( int maxVertices )
{
m_maxVertices = maxVertices;
}
void setMaxTriangles( int maxTriangles )
{
m_maxTriangles = maxTriangles;
}
void setFirstVertex( int firstVertex )
{
m_firstVertex = firstVertex;
}
void setFirstTriangle( int firstTriangle )
{
m_firstTriangle = firstTriangle;
}
void setMaxLinks( int maxLinks )
{
m_maxLinks = maxLinks;
}
void setNumLinks( int numLinks )
{
m_numLinks = numLinks;
}
void setFirstLink( int firstLink )
{
m_firstLink = firstLink;
}
int getMaxLinks()
{
return m_maxLinks;
}
int getNumLinks()
{
return m_numLinks;
}
int getFirstLink()
{
return m_firstLink;
}
btSoftBody* getSoftBody()
{
return m_softBody;
}
};
struct CollisionObjectIndices
{
CollisionObjectIndices( int f, int e )
{
firstObject = f;
endObject = e;
}
int firstObject;
int endObject;
};
struct PrepareLinksCB
{
@@ -284,20 +352,6 @@ public:
};
struct OutputToVertexArrayCB
{
int startNode;
int numNodes;
int positionOffset;
int positionStride;
int normalOffset;
int normalStride;
int padding1;
int padding2;
};
struct ApplyForcesCB
{
unsigned int numNodes;
@@ -326,17 +380,38 @@ public:
int padding;
};
struct ComputeBoundsCB
{
int numNodes;
int numSoftBodies;
int padding1;
int padding2;
};
private:
struct SolveCollisionsAndUpdateVelocitiesCB
{
unsigned int numNodes;
float isolverdt;
int padding0;
int padding1;
};
protected:
ID3D11Device * m_dx11Device;
ID3D11DeviceContext* m_dx11Context;
DXFunctions dxFunctions;
public:
/** Link data for all cloths. Note that this will be sorted batch-wise for efficient computation and m_linkAddresses will maintain the addressing. */
btSoftBodyLinkDataDX11 m_linkData;
btSoftBodyVertexDataDX11 m_vertexData;
btSoftBodyTriangleDataDX11 m_triangleData;
protected:
/** Variable to define whether we need to update solver constants on the next iteration */
bool m_updateSolverConstants;
@@ -346,7 +421,7 @@ private:
* Cloths owned by this solver.
* Only our cloths are in this array.
*/
btAlignedObjectArray< btDX11AcceleratedSoftBodyInterface * > m_softBodySet;
btAlignedObjectArray< btAcceleratedSoftBodyInterface * > m_softBodySet;
/** Acceleration value to be applied to all non-static vertices in the solver.
* Index n is cloth n, array sized by number of cloths in the world not the solver.
@@ -380,24 +455,59 @@ private:
btAlignedObjectArray< float > m_perClothMediumDensity;
btDX11Buffer<float> m_dx11PerClothMediumDensity;
KernelDesc prepareLinksKernel;
KernelDesc solvePositionsFromLinksKernel;
KernelDesc vSolveLinksKernel;
KernelDesc integrateKernel;
KernelDesc addVelocityKernel;
KernelDesc updatePositionsFromVelocitiesKernel;
KernelDesc updateVelocitiesFromPositionsWithoutVelocitiesKernel;
KernelDesc updateVelocitiesFromPositionsWithVelocitiesKernel;
KernelDesc resetNormalsAndAreasKernel;
KernelDesc normalizeNormalsAndAreasKernel;
KernelDesc updateSoftBodiesKernel;
KernelDesc outputToVertexArrayWithNormalsKernel;
KernelDesc outputToVertexArrayWithoutNormalsKernel;
/**
* Collision shape details: pair of index of first collision shape for the cloth and number of collision objects.
*/
btAlignedObjectArray< CollisionObjectIndices > m_perClothCollisionObjects;
btDX11Buffer<CollisionObjectIndices> m_dx11PerClothCollisionObjects;
KernelDesc outputToVertexArrayKernel;
KernelDesc applyForcesKernel;
KernelDesc collideSphereKernel;
KernelDesc collideCylinderKernel;
/**
* Collision shapes being passed across to the cloths in this solver.
*/
btAlignedObjectArray< CollisionShapeDescription > m_collisionObjectDetails;
btDX11Buffer< CollisionShapeDescription > m_dx11CollisionObjectDetails;
/**
* Minimum bounds for each cloth.
* Updated by GPU and returned for use by broad phase.
* These are int vectors as a reminder that they store the int representation of a float, not a float.
* Bit 31 is inverted - is floats are stored with int-sortable values.
*/
btAlignedObjectArray< UIntVector3 > m_perClothMinBounds;
btDX11Buffer< UIntVector3 > m_dx11PerClothMinBounds;
/**
* Maximum bounds for each cloth.
* Updated by GPU and returned for use by broad phase.
* These are int vectors as a reminder that they store the int representation of a float, not a float.
* Bit 31 is inverted - is floats are stored with int-sortable values.
*/
btAlignedObjectArray< UIntVector3 > m_perClothMaxBounds;
btDX11Buffer< UIntVector3 > m_dx11PerClothMaxBounds;
/**
* Friction coefficient for each cloth
*/
btAlignedObjectArray< float > m_perClothFriction;
btDX11Buffer< float > m_dx11PerClothFriction;
DXFunctions::KernelDesc prepareLinksKernel;
DXFunctions::KernelDesc solvePositionsFromLinksKernel;
DXFunctions::KernelDesc vSolveLinksKernel;
DXFunctions::KernelDesc integrateKernel;
DXFunctions::KernelDesc addVelocityKernel;
DXFunctions::KernelDesc updatePositionsFromVelocitiesKernel;
DXFunctions::KernelDesc updateVelocitiesFromPositionsWithoutVelocitiesKernel;
DXFunctions::KernelDesc updateVelocitiesFromPositionsWithVelocitiesKernel;
DXFunctions::KernelDesc solveCollisionsAndUpdateVelocitiesKernel;
DXFunctions::KernelDesc resetNormalsAndAreasKernel;
DXFunctions::KernelDesc normalizeNormalsAndAreasKernel;
DXFunctions::KernelDesc computeBoundsKernel;
DXFunctions::KernelDesc updateSoftBodiesKernel;
DXFunctions::KernelDesc applyForcesKernel;
/**
@@ -410,12 +520,7 @@ private:
const Vectormath::Aos::Point3 &vertex2 );
/**
* Compile a compute shader kernel from a string and return the appropriate KernelDesc object.
*/
KernelDesc compileComputeShaderFromString( const char* shaderString, const char* shaderName, int constBufferSize );
bool buildShaders();
virtual bool buildShaders();
void resetNormalsAndAreas( int numVertices );
@@ -423,19 +528,20 @@ private:
void executeUpdateSoftBodies( int firstTriangle, int numTriangles );
void prepareCollisionConstraints();
Vectormath::Aos::Vector3 ProjectOnAxis( const Vectormath::Aos::Vector3 &v, const Vectormath::Aos::Vector3 &a );
void ApplyClampedForce( float solverdt, const Vectormath::Aos::Vector3 &force, const Vectormath::Aos::Vector3 &vertexVelocity, float inverseMass, Vectormath::Aos::Vector3 &vertexForce );
virtual void applyForces( float solverdt );
void updateConstants( float timeStep );
btDX11AcceleratedSoftBodyInterface *findSoftBodyInterface( const btSoftBody* const softBody );
virtual void updateConstants( float timeStep );
int findSoftBodyIndex( const btSoftBody* const softBody );
//////////////////////////////////////
// Kernel dispatches
void prepareLinks();
virtual void prepareLinks();
void updatePositionsFromVelocities( float solverdt );
void solveLinksForPosition( int startLink, int numLinks, float kst, float ti );
@@ -443,14 +549,27 @@ private:
void updateVelocitiesFromPositionsWithVelocities( float isolverdt );
void updateVelocitiesFromPositionsWithoutVelocities( float isolverdt );
void computeBounds( );
void solveCollisionsAndUpdateVelocities( float isolverdt );
// End kernel dispatches
/////////////////////////////////////
void updateBounds();
void releaseKernels();
public:
btDX11SoftBodySolver(ID3D11Device * dx11Device, ID3D11DeviceContext* dx11Context);
virtual ~btDX11SoftBodySolver();
virtual SolverTypes getSolverType() const
{
return DX_SOLVER;
}
virtual btSoftBodyLinkData &getLinkData();
@@ -461,19 +580,94 @@ public:
btAcceleratedSoftBodyInterface *findSoftBodyInterface( const btSoftBody* const softBody );
const btAcceleratedSoftBodyInterface * const findSoftBodyInterface( const btSoftBody* const softBody ) const;
virtual bool checkInitialized();
virtual void updateSoftBodies( );
virtual void optimize( btAlignedObjectArray< btSoftBody * > &softBodies );
virtual void optimize( btAlignedObjectArray< btSoftBody * > &softBodies , bool forceUpdate=false);
virtual void copyBackToSoftBodies();
virtual void solveConstraints( float solverdt );
virtual void predictMotion( float solverdt );
virtual void copySoftBodyToVertexBuffer( const btSoftBody *const softBody, btVertexBufferDescriptor *vertexBuffer );
virtual void processCollision( btSoftBody *, btCollisionObject* );
virtual void processCollision( btSoftBody*, btSoftBody* );
};
/**
* Class to manage movement of data from a solver to a given target.
* This version is the DX to CPU version.
*/
class btSoftBodySolverOutputDXtoCPU : public btSoftBodySolverOutput
{
protected:
public:
btSoftBodySolverOutputDXtoCPU()
{
}
/** Output current computed vertex data to the vertex buffers for all cloths in the solver. */
virtual void copySoftBodyToVertexBuffer( const btSoftBody * const softBody, btVertexBufferDescriptor *vertexBuffer );
};
/**
* Class to manage movement of data from a solver to a given target.
* This version is the DX to DX version and subclasses DX to CPU so that it works for that too.
*/
class btSoftBodySolverOutputDXtoDX : public btSoftBodySolverOutputDXtoCPU
{
protected:
struct OutputToVertexArrayCB
{
int startNode;
int numNodes;
int positionOffset;
int positionStride;
int normalOffset;
int normalStride;
int padding1;
int padding2;
};
DXFunctions dxFunctions;
DXFunctions::KernelDesc outputToVertexArrayWithNormalsKernel;
DXFunctions::KernelDesc outputToVertexArrayWithoutNormalsKernel;
bool m_shadersInitialized;
bool checkInitialized();
bool buildShaders();
void releaseKernels();
public:
btSoftBodySolverOutputDXtoDX(ID3D11Device *dx11Device, ID3D11DeviceContext* dx11Context) :
dxFunctions( dx11Device, dx11Context )
{
m_shadersInitialized = false;
}
~btSoftBodySolverOutputDXtoDX()
{
releaseKernels();
}
/** Output current computed vertex data to the vertex buffers for all cloths in the solver. */
virtual void copySoftBodyToVertexBuffer( const btSoftBody * const softBody, btVertexBufferDescriptor *vertexBuffer );
};
#endif // #ifndef BT_ACCELERATED_SOFT_BODY_DX11_SOLVER_H

View File

@@ -14,7 +14,7 @@ subject to the following restrictions:
*/
#include "vectormath/vmInclude.h"
#include "BulletSoftBody/btSoftBodySolvers.h"
#include "btSoftBodySolver_DX11.h"
#include "btSoftBodySolverVertexBuffer_DX11.h"
#include "btSoftBodySolverLinkData_DX11SIMDAware.h"
#include "btSoftBodySolverVertexData_DX11.h"
@@ -24,176 +24,9 @@ subject to the following restrictions:
#ifndef BT_SOFT_BODY_DX11_SOLVER_SIMDAWARE_H
#define BT_SOFT_BODY_DX11_SOLVER_SIMDAWARE_H
class btDX11SIMDAwareSoftBodySolver : public btSoftBodySolver
class btDX11SIMDAwareSoftBodySolver : public btDX11SoftBodySolver
{
public:
/**
* SoftBody class to maintain information about a soft body instance
* within a solver.
* This data addresses the main solver arrays.
*/
class btAcceleratedSoftBodyInterface
{
protected:
/** Current number of vertices that are part of this cloth */
int m_numVertices;
/** Maximum number of vertices allocated to be part of this cloth */
int m_maxVertices;
/** Current number of triangles that are part of this cloth */
int m_numTriangles;
/** Maximum number of triangles allocated to be part of this cloth */
int m_maxTriangles;
/** Index of first vertex in the world allocated to this cloth */
int m_firstVertex;
/** Index of first triangle in the world allocated to this cloth */
int m_firstTriangle;
/** Index of first link in the world allocated to this cloth */
int m_firstLink;
/** Maximum number of links allocated to this cloth */
int m_maxLinks;
/** Current number of links allocated to this cloth */
int m_numLinks;
/** The actual soft body this data represents */
btSoftBody *m_softBody;
public:
btAcceleratedSoftBodyInterface( btSoftBody *softBody ) :
m_softBody( softBody )
{
m_numVertices = 0;
m_maxVertices = 0;
m_numTriangles = 0;
m_maxTriangles = 0;
m_firstVertex = 0;
m_firstTriangle = 0;
m_firstLink = 0;
m_maxLinks = 0;
m_numLinks = 0;
}
int getNumVertices()
{
return m_numVertices;
}
int getNumTriangles()
{
return m_numTriangles;
}
int getMaxVertices()
{
return m_maxVertices;
}
int getMaxTriangles()
{
return m_maxTriangles;
}
int getFirstVertex()
{
return m_firstVertex;
}
int getFirstTriangle()
{
return m_firstTriangle;
}
void setNumVertices( int numVertices )
{
m_numVertices = numVertices;
}
void setNumTriangles( int numTriangles )
{
m_numTriangles = numTriangles;
}
void setMaxVertices( int maxVertices )
{
m_maxVertices = maxVertices;
}
void setMaxTriangles( int maxTriangles )
{
m_maxTriangles = maxTriangles;
}
void setFirstVertex( int firstVertex )
{
m_firstVertex = firstVertex;
}
void setFirstTriangle( int firstTriangle )
{
m_firstTriangle = firstTriangle;
}
void setMaxLinks( int maxLinks )
{
m_maxLinks = maxLinks;
}
void setNumLinks( int numLinks )
{
m_numLinks = numLinks;
}
void setFirstLink( int firstLink )
{
m_firstLink = firstLink;
}
int getMaxLinks()
{
return m_maxLinks;
}
int getNumLinks()
{
return m_numLinks;
}
int getFirstLink()
{
return m_firstLink;
}
btSoftBody* getSoftBody()
{
return m_softBody;
}
};
class KernelDesc
{
protected:
public:
ID3D11ComputeShader* kernel;
ID3D11Buffer* constBuffer;
KernelDesc()
{
kernel = 0;
constBuffer = 0;
}
virtual ~KernelDesc()
{
// TODO: this should probably destroy its kernel but we need to be careful
// in case KernelDescs are copied
}
};
protected:
struct SolvePositionsFromLinksKernelCB
{
int startWave;
@@ -202,230 +35,46 @@ public:
float ti;
};
struct IntegrateCB
{
int numNodes;
float solverdt;
int padding1;
int padding2;
};
struct UpdatePositionsFromVelocitiesCB
{
int numNodes;
float solverSDT;
int padding1;
int padding2;
};
struct UpdateVelocitiesFromPositionsWithoutVelocitiesCB
{
int numNodes;
float isolverdt;
int padding1;
int padding2;
};
struct UpdateVelocitiesFromPositionsWithVelocitiesCB
{
int numNodes;
float isolverdt;
int padding1;
int padding2;
};
struct UpdateSoftBodiesCB
{
int numNodes;
int startFace;
int numFaces;
float epsilon;
};
struct OutputToVertexArrayCB
{
int startNode;
int numNodes;
int positionOffset;
int positionStride;
int normalOffset;
int normalStride;
int padding1;
int padding2;
};
struct ApplyForcesCB
{
unsigned int numNodes;
float solverdt;
float epsilon;
int padding3;
};
struct AddVelocityCB
{
int startNode;
int lastNode;
float velocityX;
float velocityY;
float velocityZ;
int padding1;
int padding2;
int padding3;
};
private:
ID3D11Device * m_dx11Device;
ID3D11DeviceContext* m_dx11Context;
/** Link data for all cloths. Note that this will be sorted batch-wise for efficient computation and m_linkAddresses will maintain the addressing. */
btSoftBodyLinkDataDX11SIMDAware m_linkData;
btSoftBodyVertexDataDX11 m_vertexData;
btSoftBodyTriangleDataDX11 m_triangleData;
/** Variable to define whether we need to update solver constants on the next iteration */
bool m_updateSolverConstants;
bool m_shadersInitialized;
/**
* Cloths owned by this solver.
* Only our cloths are in this array.
*/
btAlignedObjectArray< btAcceleratedSoftBodyInterface * > m_softBodySet;
virtual bool buildShaders();
/** Acceleration value to be applied to all non-static vertices in the solver.
* Index n is cloth n, array sized by number of cloths in the world not the solver.
*/
btAlignedObjectArray< Vectormath::Aos::Vector3 > m_perClothAcceleration;
btDX11Buffer<Vectormath::Aos::Vector3> m_dx11PerClothAcceleration;
/** Wind velocity to be applied normal to all non-static vertices in the solver.
* Index n is cloth n, array sized by number of cloths in the world not the solver.
*/
btAlignedObjectArray< Vectormath::Aos::Vector3 > m_perClothWindVelocity;
btDX11Buffer<Vectormath::Aos::Vector3> m_dx11PerClothWindVelocity;
/** Velocity damping factor */
btAlignedObjectArray< float > m_perClothDampingFactor;
btDX11Buffer<float> m_dx11PerClothDampingFactor;
/** Velocity correction coefficient */
btAlignedObjectArray< float > m_perClothVelocityCorrectionCoefficient;
btDX11Buffer<float> m_dx11PerClothVelocityCorrectionCoefficient;
/** Lift parameter for wind effect on cloth. */
btAlignedObjectArray< float > m_perClothLiftFactor;
btDX11Buffer<float> m_dx11PerClothLiftFactor;
/** Drag parameter for wind effect on cloth. */
btAlignedObjectArray< float > m_perClothDragFactor;
btDX11Buffer<float> m_dx11PerClothDragFactor;
/** Density of the medium in which each cloth sits */
btAlignedObjectArray< float > m_perClothMediumDensity;
btDX11Buffer<float> m_dx11PerClothMediumDensity;
KernelDesc solvePositionsFromLinksKernel;
KernelDesc integrateKernel;
KernelDesc addVelocityKernel;
KernelDesc updatePositionsFromVelocitiesKernel;
KernelDesc updateVelocitiesFromPositionsWithoutVelocitiesKernel;
KernelDesc updateVelocitiesFromPositionsWithVelocitiesKernel;
KernelDesc resetNormalsAndAreasKernel;
KernelDesc normalizeNormalsAndAreasKernel;
KernelDesc updateSoftBodiesKernel;
KernelDesc outputToVertexArrayWithNormalsKernel;
KernelDesc outputToVertexArrayWithoutNormalsKernel;
KernelDesc outputToVertexArrayKernel;
KernelDesc applyForcesKernel;
KernelDesc collideSphereKernel;
KernelDesc collideCylinderKernel;
/**
* Integrate motion on the solver.
*/
virtual void integrate( float solverdt );
float computeTriangleArea(
const Vectormath::Aos::Point3 &vertex0,
const Vectormath::Aos::Point3 &vertex1,
const Vectormath::Aos::Point3 &vertex2 );
/**
* Compile a compute shader kernel from a string and return the appropriate KernelDesc object.
*/
KernelDesc compileComputeShaderFromString( const char* shaderString, const char* shaderName, int constBufferSize, D3D10_SHADER_MACRO *compileMacros = 0 );
bool buildShaders();
void resetNormalsAndAreas( int numVertices );
void normalizeNormalsAndAreas( int numVertices );
void executeUpdateSoftBodies( int firstTriangle, int numTriangles );
Vectormath::Aos::Vector3 ProjectOnAxis( const Vectormath::Aos::Vector3 &v, const Vectormath::Aos::Vector3 &a );
void ApplyClampedForce( float solverdt, const Vectormath::Aos::Vector3 &force, const Vectormath::Aos::Vector3 &vertexVelocity, float inverseMass, Vectormath::Aos::Vector3 &vertexForce );
virtual void applyForces( float solverdt );
void updateConstants( float timeStep );
btAcceleratedSoftBodyInterface *findSoftBodyInterface( const btSoftBody* const softBody );
//////////////////////////////////////
// Kernel dispatches
void prepareLinks();
void updatePositionsFromVelocities( float solverdt );
void solveLinksForPosition( int startLink, int numLinks, float kst, float ti );
void solveLinksForVelocity( int startLink, int numLinks, float kst );
void updateVelocitiesFromPositionsWithVelocities( float isolverdt );
void updateVelocitiesFromPositionsWithoutVelocities( float isolverdt );
void solveLinksForPosition( int startLink, int numLinks, float kst, float ti );
// End kernel dispatches
/////////////////////////////////////
void releaseKernels();
public:
btDX11SIMDAwareSoftBodySolver(ID3D11Device * dx11Device, ID3D11DeviceContext* dx11Context);
virtual ~btDX11SIMDAwareSoftBodySolver();
virtual btSoftBodyLinkData &getLinkData();
virtual btSoftBodyVertexData &getVertexData();
virtual btSoftBodyTriangleData &getTriangleData();
virtual bool checkInitialized();
virtual void updateSoftBodies( );
virtual void optimize( btAlignedObjectArray< btSoftBody * > &softBodies );
virtual void solveConstraints( float solverdt );
virtual void predictMotion( float solverdt );
virtual void copySoftBodyToVertexBuffer( const btSoftBody *const softBody, btVertexBufferDescriptor *vertexBuffer );
virtual SolverTypes getSolverType() const
{
return DX_SIMD_SOLVER;
}
};
#endif // #ifndef BT_SOFT_BODY_DX11_SOLVER_SIMDAWARE_H

View File

@@ -11,15 +11,21 @@ ADD_DEFINITIONS(-DCL_PLATFORM_AMD)
SET(BulletSoftBodyOpenCLSolvers_SRCS
../btSoftBodySolver_OpenCL.cpp
../btSoftBodySolver_OpenCLSIMDAware.cpp
../btSoftBodySolverOutputCLtoGL.cpp
)
SET(BulletSoftBodyOpenCLSolvers_HDRS
../btSoftBodySolver_OpenCL.h
../btSoftBodySolver_OpenCLSIMDAware.h
../../CPU/btSoftBodySolverData.h
../btSoftBodySolverVertexData_OpenCL.h
../btSoftBodySolverTriangleData_OpenCL.h
../btSoftBodySolverLinkData_OpenCL.h
../btSoftBodySolverLinkData_OpenCLSIMDAware.h
../btSoftBodySolverBuffer_OpenCL.h
../btSoftBodySolverVertexBuffer_OpenGL.h
../btSoftBodySolverOutputCLtoGL.h
)
# OpenCL and HLSL Shaders.

View File

@@ -5,8 +5,11 @@ INCLUDE_DIRECTORIES(
)
SET(BulletSoftBodyOpenCLSolvers_SRCS
../btSoftBodySolver_OpenCL.cpp
../btSoftBodySolver_OpenCLSIMDAware.cpp
../btSoftBodySolverOutputCLtoGL.cpp
)
SET(BulletSoftBodyOpenCLSolvers_HDRS
@@ -15,7 +18,10 @@ SET(BulletSoftBodyOpenCLSolvers_HDRS
../btSoftBodySolverVertexData_OpenCL.h
../btSoftBodySolverTriangleData_OpenCL.h
../btSoftBodySolverLinkData_OpenCL.h
../btSoftBodySolverLinkData_OpenCLSIMDAware.h
../btSoftBodySolverBuffer_OpenCL.h
../btSoftBodySolverVertexBuffer_OpenGL.h
../btSoftBodySolverOutputCLtoGL.h
)
# OpenCL and HLSL Shaders.

View File

@@ -65,6 +65,9 @@ public:
cl_mem_flags flags= m_readOnlyOnGPU ? CL_MEM_READ_ONLY : CL_MEM_READ_WRITE;
size_t size = m_CPUBuffer->size() * sizeof(ElementType);
// At a minimum the buffer must exist
if( size == 0 )
size = sizeof(ElementType);
m_buffer = clCreateBuffer(m_clContext, flags, size, 0, &err);
if( err != CL_SUCCESS )
{
@@ -81,6 +84,7 @@ public:
btOpenCLBuffer( cl_command_queue commandQue,cl_context ctx, btAlignedObjectArray< ElementType >* CPUBuffer, bool readOnly)
:m_cqCommandQue(commandQue),
m_clContext(ctx),
m_buffer(0),
m_CPUBuffer(CPUBuffer),
m_gpuSize(0),
m_onGPU(false),
@@ -91,6 +95,7 @@ public:
~btOpenCLBuffer()
{
clReleaseMemObject(m_buffer);
}
@@ -105,6 +110,16 @@ public:
m_onGPU = false;
}
if( !m_allocated && m_CPUBuffer->size() == 0 )
{
// If it isn't on the GPU and yet there is no data on the CPU side this may cause a problem with some kernels.
// We should create *something* on the device side
if (!createBuffer()) {
return false;
}
m_allocated = true;
}
if( !m_onGPU && m_CPUBuffer->size() > 0 )
{
if (!m_allocated || (m_CPUBuffer->size() != m_gpuSize)) {

View File

@@ -20,10 +20,26 @@ subject to the following restrictions:
#include "btSoftBodySolver_OpenCL.h"
#include "BulletSoftBody/btSoftBodySolverVertexBuffer.h"
#include "BulletSoftBody/btSoftBody.h"
#include "BulletCollision/CollisionShapes/btCapsuleShape.h"
#include "LinearMath/btQuickprof.h"
#ifdef USE_MINICL
#include "MiniCL/cl.h"
#else //USE_MINICL
#ifdef __APPLE__
#include <OpenCL/OpenCL.h>
#else
#include <CL/cl.h>
#endif //__APPLE__
#endif//USE_MINICL
#define BT_DEFAULT_WORKGROUPSIZE 128
#define RELEASE_CL_KERNEL(kernelName) {if( kernelName ){ clReleaseKernel( kernelName ); kernelName = 0; }}
//CL_VERSION_1_1 seems broken on NVidia SDK so just disable it
#if (0)//CL_VERSION_1_1 == 1)
@@ -49,6 +65,10 @@ static char* UpdateNormalsCLString =
#include "OpenCLC/UpdateNormals.cl"
static char* VSolveLinksCLString =
#include "OpenCLC/VSolveLinks.cl"
static char* ComputeBoundsCLString =
#include "OpenCLC/ComputeBounds.cl"
static char* SolveCollisionsAndUpdateVelocitiesCLString =
#include "OpenCLC/SolveCollisionsAndUpdateVelocities.cl"
#else
////OpenCL 1.0 kernels don't use float3
#define MSTRINGIFY(A) #A
@@ -72,6 +92,10 @@ static char* UpdateNormalsCLString =
#include "OpenCLC10/UpdateNormals.cl"
static char* VSolveLinksCLString =
#include "OpenCLC10/VSolveLinks.cl"
static char* ComputeBoundsCLString =
#include "OpenCLC10/ComputeBounds.cl"
static char* SolveCollisionsAndUpdateVelocitiesCLString =
#include "OpenCLC10/SolveCollisionsAndUpdateVelocities.cl"
#endif //CL_VERSION_1_1
@@ -583,6 +607,7 @@ btOpenCLSoftBodySolver::btOpenCLSoftBodySolver(cl_command_queue queue, cl_contex
m_linkData(queue, ctx),
m_vertexData(queue, ctx),
m_triangleData(queue, ctx),
clFunctions(queue, ctx),
m_clPerClothAcceleration(queue, ctx, &m_perClothAcceleration, true ),
m_clPerClothWindVelocity(queue, ctx, &m_perClothWindVelocity, true ),
m_clPerClothDampingFactor(queue,ctx, &m_perClothDampingFactor, true ),
@@ -590,6 +615,11 @@ btOpenCLSoftBodySolver::btOpenCLSoftBodySolver(cl_command_queue queue, cl_contex
m_clPerClothLiftFactor(queue, ctx,&m_perClothLiftFactor, true ),
m_clPerClothDragFactor(queue, ctx,&m_perClothDragFactor, true ),
m_clPerClothMediumDensity(queue, ctx,&m_perClothMediumDensity, true ),
m_clPerClothCollisionObjects( queue, ctx, &m_perClothCollisionObjects, true ),
m_clCollisionObjectDetails( queue, ctx, &m_collisionObjectDetails, true ),
m_clPerClothMinBounds( queue, ctx, &m_perClothMinBounds, false ),
m_clPerClothMaxBounds( queue, ctx, &m_perClothMaxBounds, false ),
m_clPerClothFriction( queue, ctx, &m_perClothFriction, false ),
m_cqCommandQue( queue ),
m_cxMainContext(ctx),
m_defaultWorkGroupSize(BT_DEFAULT_WORKGROUPSIZE)
@@ -600,15 +630,85 @@ btOpenCLSoftBodySolver::btOpenCLSoftBodySolver(cl_command_queue queue, cl_contex
m_updateSolverConstants = true;
m_shadersInitialized = false;
prepareLinksKernel = 0;
solvePositionsFromLinksKernel = 0;
updateConstantsKernel = 0;
integrateKernel = 0;
addVelocityKernel = 0;
updatePositionsFromVelocitiesKernel = 0;
updateVelocitiesFromPositionsWithoutVelocitiesKernel = 0;
updateVelocitiesFromPositionsWithVelocitiesKernel = 0;
vSolveLinksKernel = 0;
solveCollisionsAndUpdateVelocitiesKernel = 0;
resetNormalsAndAreasKernel = 0;
resetNormalsAndAreasKernel = 0;
normalizeNormalsAndAreasKernel = 0;
computeBoundsKernel = 0;
outputToVertexArrayKernel = 0;
applyForcesKernel = 0;
}
btOpenCLSoftBodySolver::~btOpenCLSoftBodySolver()
{
releaseKernels();
}
void btOpenCLSoftBodySolver::optimize( btAlignedObjectArray< btSoftBody * > &softBodies )
void btOpenCLSoftBodySolver::releaseKernels()
{
if( m_softBodySet.size() != softBodies.size() )
RELEASE_CL_KERNEL( prepareLinksKernel );
RELEASE_CL_KERNEL( solvePositionsFromLinksKernel );
RELEASE_CL_KERNEL( updateConstantsKernel );
RELEASE_CL_KERNEL( integrateKernel );
RELEASE_CL_KERNEL( addVelocityKernel );
RELEASE_CL_KERNEL( updatePositionsFromVelocitiesKernel );
RELEASE_CL_KERNEL( updateVelocitiesFromPositionsWithoutVelocitiesKernel );
RELEASE_CL_KERNEL( updateVelocitiesFromPositionsWithVelocitiesKernel );
RELEASE_CL_KERNEL( vSolveLinksKernel );
RELEASE_CL_KERNEL( solveCollisionsAndUpdateVelocitiesKernel );
RELEASE_CL_KERNEL( resetNormalsAndAreasKernel );
RELEASE_CL_KERNEL( normalizeNormalsAndAreasKernel );
RELEASE_CL_KERNEL( computeBoundsKernel );
RELEASE_CL_KERNEL( outputToVertexArrayKernel );
RELEASE_CL_KERNEL( applyForcesKernel );
m_shadersInitialized = false;
}
void btOpenCLSoftBodySolver::copyBackToSoftBodies()
{
// Move the vertex data back to the host first
m_vertexData.moveFromAccelerator();
// Loop over soft bodies, copying all the vertex positions back for each body in turn
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
{
btOpenCLAcceleratedSoftBodyInterface *softBodyInterface = m_softBodySet[ softBodyIndex ];
btSoftBody *softBody = softBodyInterface->getSoftBody();
int firstVertex = softBodyInterface->getFirstVertex();
int numVertices = softBodyInterface->getNumVertices();
// Copy vertices from solver back into the softbody
for( int vertex = 0; vertex < numVertices; ++vertex )
{
using Vectormath::Aos::Point3;
Point3 vertexPosition( getVertexData().getVertexPositions()[firstVertex + vertex] );
softBody->m_nodes[vertex].m_x.setX( vertexPosition.getX() );
softBody->m_nodes[vertex].m_x.setY( vertexPosition.getY() );
softBody->m_nodes[vertex].m_x.setZ( vertexPosition.getZ() );
softBody->m_nodes[vertex].m_n.setX( vertexPosition.getX() );
softBody->m_nodes[vertex].m_n.setY( vertexPosition.getY() );
softBody->m_nodes[vertex].m_n.setZ( vertexPosition.getZ() );
}
}
} // btOpenCLSoftBodySolver::copyBackToSoftBodies
void btOpenCLSoftBodySolver::optimize( btAlignedObjectArray< btSoftBody * > &softBodies, bool forceUpdate )
{
if( forceUpdate || m_softBodySet.size() != softBodies.size() )
{
// Have a change in the soft body set so update, reloading all the data
getVertexData().clear();
@@ -633,6 +733,11 @@ void btOpenCLSoftBodySolver::optimize( btAlignedObjectArray< btSoftBody * > &sof
m_perClothLiftFactor.push_back( softBody->m_cfg.kLF );
m_perClothDragFactor.push_back( softBody->m_cfg.kDG );
m_perClothMediumDensity.push_back(softBody->getWorldInfo()->air_density);
// Simple init values. Actually we'll put 0 and -1 into them at the appropriate time
m_perClothMinBounds.push_back( UIntVector3(UINT_MAX, UINT_MAX, UINT_MAX) );
m_perClothMaxBounds.push_back( UIntVector3(0, 0, 0) );
m_perClothFriction.push_back( softBody->getFriction() );
m_perClothCollisionObjects.push_back( CollisionObjectIndices(-1, -1) );
// Add space for new vertices and triangles in the default solver for now
// TODO: Include space here for tearing too later
@@ -738,12 +843,6 @@ btSoftBodyTriangleData &btOpenCLSoftBodySolver::getTriangleData()
return m_triangleData;
}
bool btOpenCLSoftBodySolver::checkInitialized()
{
return buildShaders();
}
void btOpenCLSoftBodySolver::resetNormalsAndAreas( int numVertices )
{
cl_int ciErrNum;
@@ -751,11 +850,15 @@ void btOpenCLSoftBodySolver::resetNormalsAndAreas( int numVertices )
ciErrNum = clSetKernelArg(resetNormalsAndAreasKernel, 1, sizeof(cl_mem), (void*)&m_vertexData.m_clVertexNormal.m_buffer);//oclCHECKERROR(ciErrNum, CL_SUCCESS);
ciErrNum = clSetKernelArg(resetNormalsAndAreasKernel, 2, sizeof(cl_mem), (void*)&m_vertexData.m_clVertexArea.m_buffer); //oclCHECKERROR(ciErrNum, CL_SUCCESS);
size_t numWorkItems = m_defaultWorkGroupSize*((numVertices + (m_defaultWorkGroupSize-1)) / m_defaultWorkGroupSize);
ciErrNum = clEnqueueNDRangeKernel(m_cqCommandQue, resetNormalsAndAreasKernel, 1, NULL, &numWorkItems, &m_defaultWorkGroupSize, 0,0,0 );
if( ciErrNum != CL_SUCCESS )
if (numWorkItems)
{
btAssert( 0 && "enqueueNDRangeKernel(resetNormalsAndAreasKernel)" );
ciErrNum = clEnqueueNDRangeKernel(m_cqCommandQue, resetNormalsAndAreasKernel, 1, NULL, &numWorkItems, &m_defaultWorkGroupSize, 0,0,0 );
if( ciErrNum != CL_SUCCESS )
{
btAssert( 0 && "enqueueNDRangeKernel(resetNormalsAndAreasKernel)" );
}
}
}
@@ -770,10 +873,13 @@ void btOpenCLSoftBodySolver::normalizeNormalsAndAreas( int numVertices )
ciErrNum = clSetKernelArg(normalizeNormalsAndAreasKernel, 2, sizeof(cl_mem), &m_vertexData.m_clVertexNormal.m_buffer);
ciErrNum = clSetKernelArg(normalizeNormalsAndAreasKernel, 3, sizeof(cl_mem), &m_vertexData.m_clVertexArea.m_buffer);
size_t numWorkItems = m_defaultWorkGroupSize*((numVertices + (m_defaultWorkGroupSize-1)) / m_defaultWorkGroupSize);
ciErrNum = clEnqueueNDRangeKernel(m_cqCommandQue, normalizeNormalsAndAreasKernel, 1, NULL, &numWorkItems, &m_defaultWorkGroupSize, 0,0,0);
if( ciErrNum != CL_SUCCESS )
if (numWorkItems)
{
btAssert( 0 && "enqueueNDRangeKernel(normalizeNormalsAndAreasKernel)");
ciErrNum = clEnqueueNDRangeKernel(m_cqCommandQue, normalizeNormalsAndAreasKernel, 1, NULL, &numWorkItems, &m_defaultWorkGroupSize, 0,0,0);
if( ciErrNum != CL_SUCCESS )
{
btAssert( 0 && "enqueueNDRangeKernel(normalizeNormalsAndAreasKernel)");
}
}
}
@@ -875,10 +981,13 @@ void btOpenCLSoftBodySolver::applyForces( float solverdt )
ciErrNum = clSetKernelArg(applyForcesKernel,12, sizeof(cl_mem), &m_vertexData.m_clVertexForceAccumulator.m_buffer);
ciErrNum = clSetKernelArg(applyForcesKernel,13, sizeof(cl_mem), &m_vertexData.m_clVertexVelocity.m_buffer);
size_t numWorkItems = m_defaultWorkGroupSize*((m_vertexData.getNumVertices() + (m_defaultWorkGroupSize-1)) / m_defaultWorkGroupSize);
ciErrNum = clEnqueueNDRangeKernel(m_cqCommandQue,applyForcesKernel, 1, NULL, &numWorkItems, &m_defaultWorkGroupSize, 0,0,0);
if( ciErrNum != CL_SUCCESS )
if (numWorkItems)
{
btAssert( 0 && "enqueueNDRangeKernel(applyForcesKernel)");
ciErrNum = clEnqueueNDRangeKernel(m_cqCommandQue,applyForcesKernel, 1, NULL, &numWorkItems, &m_defaultWorkGroupSize, 0,0,0);
if( ciErrNum != CL_SUCCESS )
{
btAssert( 0 && "enqueueNDRangeKernel(applyForcesKernel)");
}
}
}
@@ -904,10 +1013,13 @@ void btOpenCLSoftBodySolver::integrate( float solverdt )
ciErrNum = clSetKernelArg(integrateKernel, 6, sizeof(cl_mem), &m_vertexData.m_clVertexForceAccumulator.m_buffer);
size_t numWorkItems = m_defaultWorkGroupSize*((m_vertexData.getNumVertices() + (m_defaultWorkGroupSize-1)) / m_defaultWorkGroupSize);
ciErrNum = clEnqueueNDRangeKernel(m_cqCommandQue,integrateKernel, 1, NULL, &numWorkItems, &m_defaultWorkGroupSize,0,0,0);
if( ciErrNum != CL_SUCCESS )
if (numWorkItems)
{
btAssert( 0 && "enqueueNDRangeKernel(integrateKernel)");
ciErrNum = clEnqueueNDRangeKernel(m_cqCommandQue,integrateKernel, 1, NULL, &numWorkItems, &m_defaultWorkGroupSize,0,0,0);
if( ciErrNum != CL_SUCCESS )
{
btAssert( 0 && "enqueueNDRangeKernel(integrateKernel)");
}
}
}
@@ -924,6 +1036,102 @@ float btOpenCLSoftBodySolver::computeTriangleArea(
return area;
}
void btOpenCLSoftBodySolver::updateBounds()
{
//#define USE_GPU_BOUNDS_COMPUTATION
#ifdef USE_GPU_BOUNDS_COMPUTATION
using Vectormath::Aos::Point3;
// Interpretation structure for float and int
struct FPRep {
unsigned int mantissa : 23;
unsigned int exponent : 8;
unsigned int sign : 1;
};
union FloatAsInt
{
float floatValue;
int intValue;
unsigned int uintValue;
FPRep fpRep;
};
// Update bounds array to min and max int values to allow easy atomics
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
{
m_perClothMinBounds[softBodyIndex] = UIntVector3( UINT_MAX, UINT_MAX, UINT_MAX );
m_perClothMaxBounds[softBodyIndex] = UIntVector3( 0, 0, 0 );
}
m_vertexData.moveToAccelerator();
m_clPerClothMinBounds.moveToGPU();
m_clPerClothMaxBounds.moveToGPU();
computeBounds( );
m_clPerClothMinBounds.moveFromGPU();
m_clPerClothMaxBounds.moveFromGPU();
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
{
UIntVector3 minBoundUInt = m_perClothMinBounds[softBodyIndex];
UIntVector3 maxBoundUInt = m_perClothMaxBounds[softBodyIndex];
/*UIntVector3 minBoundUInt;
minBoundUInt.x = m_perClothMinBounds[softBodyIndex*4];
minBoundUInt.y = m_perClothMinBounds[softBodyIndex*4+1];
minBoundUInt.z = m_perClothMinBounds[softBodyIndex*4+2];
UIntVector3 maxBoundUInt;
maxBoundUInt.x = m_perClothMaxBounds[softBodyIndex*4];
maxBoundUInt.y = m_perClothMaxBounds[softBodyIndex*4+1];
maxBoundUInt.z = m_perClothMaxBounds[softBodyIndex*4+2];*/
// Convert back to float
FloatAsInt fai;
btVector3 minBound;
fai.uintValue = minBoundUInt.x;
fai.uintValue ^= (((fai.uintValue >> 31) - 1) | 0x80000000);
minBound.setX( fai.floatValue );
fai.uintValue = minBoundUInt.y;
fai.uintValue ^= (((fai.uintValue >> 31) - 1) | 0x80000000);
minBound.setY( fai.floatValue );
fai.uintValue = minBoundUInt.z;
fai.uintValue ^= (((fai.uintValue >> 31) - 1) | 0x80000000);
minBound.setZ( fai.floatValue );
btVector3 maxBound;
fai.uintValue = maxBoundUInt.x;
fai.uintValue ^= (((fai.uintValue >> 31) - 1) | 0x80000000);
maxBound.setX( fai.floatValue );
fai.uintValue = maxBoundUInt.y;
fai.uintValue ^= (((fai.uintValue >> 31) - 1) | 0x80000000);
maxBound.setY( fai.floatValue );
fai.uintValue = maxBoundUInt.z;
fai.uintValue ^= (((fai.uintValue >> 31) - 1) | 0x80000000);
maxBound.setZ( fai.floatValue );
// And finally assign to the soft body
m_softBodySet[softBodyIndex]->updateBounds( minBound, maxBound );
}
#else
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
{
btVector3 minBound(-1e30,-1e30,-1e30), maxBound(1e30,1e30,1e30);
m_softBodySet[softBodyIndex]->updateBounds( minBound, maxBound );
}
#endif//USE_GPU_BOUNDS_COMPUTATION
} // btOpenCLSoftBodySolver::updateBounds
void btOpenCLSoftBodySolver::updateConstants( float timeStep )
{
@@ -954,6 +1162,66 @@ void btOpenCLSoftBodySolver::updateConstants( float timeStep )
}
class QuickSortCompare
{
public:
bool operator() ( const CollisionShapeDescription& a, const CollisionShapeDescription& b )
{
return ( a.softBodyIdentifier < b.softBodyIdentifier );
}
};
/**
* Sort the collision object details array and generate indexing into it for the per-cloth collision object array.
*/
void btOpenCLSoftBodySolver::prepareCollisionConstraints()
{
// First do a simple sort on the collision objects
btAlignedObjectArray<int> numObjectsPerClothPrefixSum;
btAlignedObjectArray<int> numObjectsPerCloth;
numObjectsPerCloth.resize( m_softBodySet.size(), 0 );
numObjectsPerClothPrefixSum.resize( m_softBodySet.size(), 0 );
m_collisionObjectDetails.quickSort( QuickSortCompare() );
if (!m_perClothCollisionObjects.size())
return;
// Generating indexing for perClothCollisionObjects
// First clear the previous values with the "no collision object for cloth" constant
for( int clothIndex = 0; clothIndex < m_perClothCollisionObjects.size(); ++clothIndex )
{
m_perClothCollisionObjects[clothIndex].firstObject = -1;
m_perClothCollisionObjects[clothIndex].endObject = -1;
}
int currentCloth = 0;
int startIndex = 0;
for( int collisionObject = 0; collisionObject < m_collisionObjectDetails.size(); ++collisionObject )
{
int nextCloth = m_collisionObjectDetails[collisionObject].softBodyIdentifier;
if( nextCloth != currentCloth )
{
// Changed cloth in the array
// Set the end index and the range is what we need for currentCloth
m_perClothCollisionObjects[currentCloth].firstObject = startIndex;
m_perClothCollisionObjects[currentCloth].endObject = collisionObject;
currentCloth = nextCloth;
startIndex = collisionObject;
}
}
// And update last cloth
m_perClothCollisionObjects[currentCloth].firstObject = startIndex;
m_perClothCollisionObjects[currentCloth].endObject = m_collisionObjectDetails.size();
} // btOpenCLSoftBodySolver::prepareCollisionConstraints
void btOpenCLSoftBodySolver::solveConstraints( float solverdt )
{
@@ -993,6 +1261,9 @@ void btOpenCLSoftBodySolver::solveConstraints( float solverdt )
}
}
prepareCollisionConstraints();
// Compute new positions from velocity
// Also update the previous position so that our position computation is now based on the new position from the velocity solution
// rather than based directly on the original positions
@@ -1016,8 +1287,9 @@ void btOpenCLSoftBodySolver::solveConstraints( float solverdt )
} // for( int iteration = 0; iteration < m_numberOfPositionIterations ; ++iteration )
updateVelocitiesFromPositionsWithoutVelocities( 1.f/solverdt );
// At this point assume that the force array is blank - we will overwrite it
solveCollisionsAndUpdateVelocities( 1.f/solverdt );
}
@@ -1158,19 +1430,88 @@ void btOpenCLSoftBodySolver::updateVelocitiesFromPositionsWithoutVelocities( flo
} // updateVelocitiesFromPositionsWithoutVelocities
void btOpenCLSoftBodySolver::computeBounds( )
{
m_vertexData.moveToAccelerator();
cl_int ciErrNum;
int numVerts = m_vertexData.getNumVertices();
int numSoftBodies = m_softBodySet.size();
ciErrNum = clSetKernelArg(computeBoundsKernel, 0, sizeof(int), &numVerts);
ciErrNum = clSetKernelArg(computeBoundsKernel, 1, sizeof(int), &numSoftBodies);
ciErrNum = clSetKernelArg(computeBoundsKernel, 2, sizeof(cl_mem),&m_vertexData.m_clClothIdentifier.m_buffer);
ciErrNum = clSetKernelArg(computeBoundsKernel, 3, sizeof(cl_mem),&m_vertexData.m_clVertexPosition.m_buffer);
ciErrNum = clSetKernelArg(computeBoundsKernel, 4, sizeof(cl_mem),&m_clPerClothMinBounds.m_buffer);
ciErrNum = clSetKernelArg(computeBoundsKernel, 5, sizeof(cl_mem),&m_clPerClothMaxBounds.m_buffer);
ciErrNum = clSetKernelArg(computeBoundsKernel, 6, sizeof(cl_uint4)*256,0);
ciErrNum = clSetKernelArg(computeBoundsKernel, 7, sizeof(cl_uint4)*256,0);
size_t numWorkItems = m_defaultWorkGroupSize*((m_vertexData.getNumVertices() + (m_defaultWorkGroupSize-1)) / m_defaultWorkGroupSize);
if (numWorkItems)
{
ciErrNum = clEnqueueNDRangeKernel(m_cqCommandQue,computeBoundsKernel, 1, NULL, &numWorkItems, &m_defaultWorkGroupSize,0,0,0);
if( ciErrNum != CL_SUCCESS )
{
btAssert( 0 && "enqueueNDRangeKernel(computeBoundsKernel)");
}
}
clFinish(m_cqCommandQue);
} // btOpenCLSoftBodySolver::computeBounds
void btOpenCLSoftBodySolver::solveCollisionsAndUpdateVelocities( float isolverdt )
{
// Copy kernel parameters to GPU
m_vertexData.moveToAccelerator();
m_clPerClothFriction.moveToGPU();
m_clPerClothDampingFactor.moveToGPU();
m_clPerClothCollisionObjects.moveToGPU();
m_clCollisionObjectDetails.moveToGPU();
cl_int ciErrNum;
int numVerts = m_vertexData.getNumVertices();
ciErrNum = clSetKernelArg(solveCollisionsAndUpdateVelocitiesKernel, 0, sizeof(int), &numVerts);
ciErrNum = clSetKernelArg(solveCollisionsAndUpdateVelocitiesKernel, 1, sizeof(int), &isolverdt);
ciErrNum = clSetKernelArg(solveCollisionsAndUpdateVelocitiesKernel, 2, sizeof(cl_mem),&m_vertexData.m_clClothIdentifier.m_buffer);
ciErrNum = clSetKernelArg(solveCollisionsAndUpdateVelocitiesKernel, 3, sizeof(cl_mem),&m_vertexData.m_clVertexPreviousPosition.m_buffer);
ciErrNum = clSetKernelArg(solveCollisionsAndUpdateVelocitiesKernel, 4, sizeof(cl_mem),&m_clPerClothFriction.m_buffer);
ciErrNum = clSetKernelArg(solveCollisionsAndUpdateVelocitiesKernel, 5, sizeof(cl_mem),&m_clPerClothDampingFactor.m_buffer);
ciErrNum = clSetKernelArg(solveCollisionsAndUpdateVelocitiesKernel, 6, sizeof(cl_mem),&m_clPerClothCollisionObjects.m_buffer);
ciErrNum = clSetKernelArg(solveCollisionsAndUpdateVelocitiesKernel, 7, sizeof(cl_mem),&m_clCollisionObjectDetails.m_buffer);
ciErrNum = clSetKernelArg(solveCollisionsAndUpdateVelocitiesKernel, 8, sizeof(cl_mem),&m_vertexData.m_clVertexForceAccumulator.m_buffer);
ciErrNum = clSetKernelArg(solveCollisionsAndUpdateVelocitiesKernel, 9, sizeof(cl_mem),&m_vertexData.m_clVertexVelocity.m_buffer);
ciErrNum = clSetKernelArg(solveCollisionsAndUpdateVelocitiesKernel, 10, sizeof(cl_mem),&m_vertexData.m_clVertexPosition.m_buffer);
size_t numWorkItems = m_defaultWorkGroupSize*((m_vertexData.getNumVertices() + (m_defaultWorkGroupSize-1)) / m_defaultWorkGroupSize);
if (numWorkItems)
{
ciErrNum = clEnqueueNDRangeKernel(m_cqCommandQue,solveCollisionsAndUpdateVelocitiesKernel, 1, NULL, &numWorkItems, &m_defaultWorkGroupSize,0,0,0);
if( ciErrNum != CL_SUCCESS )
{
btAssert( 0 && "enqueueNDRangeKernel(updateVelocitiesFromPositionsWithoutVelocitiesKernel)");
}
}
} // btOpenCLSoftBodySolver::updateVelocitiesFromPositionsWithoutVelocities
// End kernel dispatches
/////////////////////////////////////
void btOpenCLSoftBodySolver::copySoftBodyToVertexBuffer( const btSoftBody * const softBody, btVertexBufferDescriptor *vertexBuffer )
void btSoftBodySolverOutputCLtoCPU::copySoftBodyToVertexBuffer( const btSoftBody * const softBody, btVertexBufferDescriptor *vertexBuffer )
{
// Currently only support CPU output buffers
// TODO: check for DX11 buffers. Take all offsets into the same DX11 buffer
// and use them together on a single kernel call if possible by setting up a
// per-cloth target buffer array for the copy kernel.
btSoftBodySolver *solver = softBody->getSoftBodySolver();
btAssert( solver->getSolverType() == btSoftBodySolver::CL_SOLVER || solver->getSolverType() == btSoftBodySolver::CL_SIMD_SOLVER );
btOpenCLSoftBodySolver *dxSolver = static_cast< btOpenCLSoftBodySolver * >( solver );
btOpenCLAcceleratedSoftBodyInterface *currentCloth = findSoftBodyInterface( softBody );
btOpenCLAcceleratedSoftBodyInterface* currentCloth = dxSolver->findSoftBodyInterface( softBody );
btSoftBodyVertexDataOpenCL &vertexData( dxSolver->m_vertexData );
const int firstVertex = currentCloth->getFirstVertex();
const int lastVertex = firstVertex + currentCloth->getNumVertices();
@@ -1180,8 +1521,8 @@ void btOpenCLSoftBodySolver::copySoftBodyToVertexBuffer( const btSoftBody * cons
const btCPUVertexBufferDescriptor *cpuVertexBuffer = static_cast< btCPUVertexBufferDescriptor* >(vertexBuffer);
float *basePointer = cpuVertexBuffer->getBasePointer();
m_vertexData.m_clVertexPosition.copyFromGPU();
m_vertexData.m_clVertexNormal.copyFromGPU();
vertexData.m_clVertexPosition.copyFromGPU();
vertexData.m_clVertexNormal.copyFromGPU();
if( vertexBuffer->hasVertexPositions() )
{
@@ -1191,7 +1532,7 @@ void btOpenCLSoftBodySolver::copySoftBodyToVertexBuffer( const btSoftBody * cons
for( int vertexIndex = firstVertex; vertexIndex < lastVertex; ++vertexIndex )
{
Vectormath::Aos::Point3 position = m_vertexData.getPosition(vertexIndex);
Vectormath::Aos::Point3 position = vertexData.getPosition(vertexIndex);
*(vertexPointer + 0) = position.getX();
*(vertexPointer + 1) = position.getY();
*(vertexPointer + 2) = position.getZ();
@@ -1206,7 +1547,7 @@ void btOpenCLSoftBodySolver::copySoftBodyToVertexBuffer( const btSoftBody * cons
for( int vertexIndex = firstVertex; vertexIndex < lastVertex; ++vertexIndex )
{
Vectormath::Aos::Vector3 normal = m_vertexData.getNormal(vertexIndex);
Vectormath::Aos::Vector3 normal = vertexData.getNormal(vertexIndex);
*(normalPointer + 0) = normal.getX();
*(normalPointer + 1) = normal.getY();
*(normalPointer + 2) = normal.getZ();
@@ -1215,10 +1556,11 @@ void btOpenCLSoftBodySolver::copySoftBodyToVertexBuffer( const btSoftBody * cons
}
}
} // btCPUSoftBodySolver::outputToVertexBuffers
} // btSoftBodySolverOutputCLtoCPU::outputToVertexBuffers
cl_kernel btOpenCLSoftBodySolver::compileCLKernelFromString( const char* kernelSource, const char* kernelName )
cl_kernel CLFunctions::compileCLKernelFromString( const char* kernelSource, const char* kernelName, const char* additionalMacros )
{
printf("compiling kernelName: %s ",kernelName);
cl_kernel kernel;
@@ -1229,19 +1571,45 @@ cl_kernel btOpenCLSoftBodySolver::compileCLKernelFromString( const char* kernelS
// oclCHECKERROR(ciErrNum, CL_SUCCESS);
// Build the program with 'mad' Optimization option
#ifdef MAC
char* flags = "-cl-mad-enable -DMAC -DGUID_ARG";
#else
const char* flags = "-DGUID_ARG=";
//const char* flags = "-DGUID_ARG= -fno-alias";
const char* flags = "-DGUID_ARG= ";
#endif
ciErrNum = clBuildProgram(m_cpProgram, 0, NULL, flags, NULL, NULL);
char* compileFlags = new char[strlen(additionalMacros) + strlen(flags) + 5];
sprintf(compileFlags, "%s %s", flags, additionalMacros);
ciErrNum = clBuildProgram(m_cpProgram, 0, NULL, compileFlags, NULL, NULL);
if (ciErrNum != CL_SUCCESS)
{
printf("Error in clBuildProgram, Line %u in file %s !!!\n\n", __LINE__, __FILE__);
size_t numDevices;
clGetProgramInfo( m_cpProgram, CL_PROGRAM_DEVICES, 0, 0, &numDevices );
cl_device_id *devices = new cl_device_id[numDevices];
clGetProgramInfo( m_cpProgram, CL_PROGRAM_DEVICES, numDevices, devices, &numDevices );
for( int i = 0; i < 2; ++i )
{
char *build_log;
size_t ret_val_size;
clGetProgramBuildInfo(m_cpProgram, devices[i], CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
build_log = new char[ret_val_size+1];
clGetProgramBuildInfo(m_cpProgram, devices[i], CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL);
// to be carefully, terminate with \0
// there's no information in the reference whether the string is 0 terminated or not
build_log[ret_val_size] = '\0';
printf("Error in clBuildProgram, Line %u in file %s, Log: \n%s\n !!!\n\n", __LINE__, __FILE__, build_log);
delete[] build_log;
}
btAssert(0);
exit(0);
}
// Create the kernel
kernel = clCreateKernel(m_cpProgram, kernelName, &ciErrNum);
if (ciErrNum != CL_SUCCESS)
@@ -1252,37 +1620,123 @@ cl_kernel btOpenCLSoftBodySolver::compileCLKernelFromString( const char* kernelS
}
printf("ready. \n");
delete [] compileFlags;
return kernel;
}
void btOpenCLSoftBodySolver::predictMotion( float timeStep )
{
// Fill the force arrays with current acceleration data etc
m_perClothWindVelocity.resize( m_softBodySet.size() );
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
// Clear the collision shape array for the next frame
// Ensure that the DX11 ones are moved off the device so they will be updated correctly
m_clCollisionObjectDetails.changedOnCPU();
m_clPerClothCollisionObjects.changedOnCPU();
m_collisionObjectDetails.clear();
{
btSoftBody *softBody = m_softBodySet[softBodyIndex]->getSoftBody();
m_perClothWindVelocity[softBodyIndex] = toVector3(softBody->getWindVelocity());
BT_PROFILE("perClothWindVelocity");
// Fill the force arrays with current acceleration data etc
m_perClothWindVelocity.resize( m_softBodySet.size() );
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
{
btSoftBody *softBody = m_softBodySet[softBodyIndex]->getSoftBody();
m_perClothWindVelocity[softBodyIndex] = toVector3(softBody->getWindVelocity());
}
}
{
BT_PROFILE("changedOnCPU");
m_clPerClothWindVelocity.changedOnCPU();
}
m_clPerClothWindVelocity.changedOnCPU();
// Apply forces that we know about to the cloths
applyForces( timeStep * getTimeScale() );
{
BT_PROFILE("applyForces");
// Apply forces that we know about to the cloths
applyForces( timeStep * getTimeScale() );
}
// Itegrate motion for all soft bodies dealt with by the solver
integrate( timeStep * getTimeScale() );
{
BT_PROFILE("integrate");
// Itegrate motion for all soft bodies dealt with by the solver
integrate( timeStep * getTimeScale() );
}
{
BT_PROFILE("updateBounds");
updateBounds();
}
// End prediction work for solvers
}
static Vectormath::Aos::Transform3 toTransform3( const btTransform &transform )
{
Vectormath::Aos::Transform3 outTransform;
outTransform.setCol(0, toVector3(transform.getBasis().getColumn(0)));
outTransform.setCol(1, toVector3(transform.getBasis().getColumn(1)));
outTransform.setCol(2, toVector3(transform.getBasis().getColumn(2)));
outTransform.setCol(3, toVector3(transform.getOrigin()));
return outTransform;
}
void btOpenCLAcceleratedSoftBodyInterface::updateBounds( const btVector3 &lowerBound, const btVector3 &upperBound )
{
float scalarMargin = this->getSoftBody()->getCollisionShape()->getMargin();
btVector3 vectorMargin( scalarMargin, scalarMargin, scalarMargin );
m_softBody->m_bounds[0] = lowerBound - vectorMargin;
m_softBody->m_bounds[1] = upperBound + vectorMargin;
} // btOpenCLSoftBodySolver::btDX11AcceleratedSoftBodyInterface::updateBounds
void btOpenCLSoftBodySolver::processCollision( btSoftBody*, btSoftBody* )
{
}
// Add the collision object to the set to deal with for a particular soft body
void btOpenCLSoftBodySolver::processCollision( btSoftBody *softBody, btCollisionObject* collisionObject )
{
int softBodyIndex = findSoftBodyIndex( softBody );
if( softBodyIndex >= 0 )
{
btCollisionShape *collisionShape = collisionObject->getCollisionShape();
float friction = collisionObject->getFriction();
int shapeType = collisionShape->getShapeType();
if( shapeType == CAPSULE_SHAPE_PROXYTYPE )
{
// Add to the list of expected collision objects
CollisionShapeDescription newCollisionShapeDescription;
newCollisionShapeDescription.softBodyIdentifier = softBodyIndex;
newCollisionShapeDescription.collisionShapeType = shapeType;
// TODO: May need to transpose this matrix either here or in HLSL
newCollisionShapeDescription.shapeTransform = toTransform3(collisionObject->getWorldTransform());
btCapsuleShape *capsule = static_cast<btCapsuleShape*>( collisionShape );
newCollisionShapeDescription.radius = capsule->getRadius();
newCollisionShapeDescription.halfHeight = capsule->getHalfHeight();
newCollisionShapeDescription.margin = capsule->getMargin();
newCollisionShapeDescription.upAxis = capsule->getUpAxis();
newCollisionShapeDescription.friction = friction;
btRigidBody* body = static_cast< btRigidBody* >( collisionObject );
newCollisionShapeDescription.linearVelocity = toVector3(body->getLinearVelocity());
newCollisionShapeDescription.angularVelocity = toVector3(body->getAngularVelocity());
m_collisionObjectDetails.push_back( newCollisionShapeDescription );
} else {
btAssert("Unsupported collision shape type\n");
}
} else {
btAssert("Unknown soft body");
}
} // btOpenCLSoftBodySolver::processCollision
btOpenCLAcceleratedSoftBodyInterface *btOpenCLSoftBodySolver::findSoftBodyInterface( const btSoftBody* const softBody )
btOpenCLAcceleratedSoftBodyInterface* btOpenCLSoftBodySolver::findSoftBodyInterface( const btSoftBody* const softBody )
{
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
{
btOpenCLAcceleratedSoftBodyInterface *softBodyInterface = m_softBodySet[softBodyIndex];
btOpenCLAcceleratedSoftBodyInterface* softBodyInterface = m_softBodySet[softBodyIndex];
if( softBodyInterface->getSoftBody() == softBody )
return softBodyInterface;
}
@@ -1290,27 +1744,50 @@ btOpenCLAcceleratedSoftBodyInterface *btOpenCLSoftBodySolver::findSoftBodyInterf
}
int btOpenCLSoftBodySolver::findSoftBodyIndex( const btSoftBody* const softBody )
{
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
{
btOpenCLAcceleratedSoftBodyInterface* softBodyInterface = m_softBodySet[softBodyIndex];
if( softBodyInterface->getSoftBody() == softBody )
return softBodyIndex;
}
return 1;
}
bool btOpenCLSoftBodySolver::checkInitialized()
{
if( !m_shadersInitialized )
if( buildShaders() )
m_shadersInitialized = true;
return m_shadersInitialized;
}
bool btOpenCLSoftBodySolver::buildShaders()
{
// Ensure current kernels are released first
releaseKernels();
bool returnVal = true;
if( m_shadersInitialized )
return true;
prepareLinksKernel = compileCLKernelFromString( PrepareLinksCLString, "PrepareLinksKernel" );
updatePositionsFromVelocitiesKernel = compileCLKernelFromString( UpdatePositionsFromVelocitiesCLString, "UpdatePositionsFromVelocitiesKernel" );
solvePositionsFromLinksKernel = compileCLKernelFromString( SolvePositionsCLString, "SolvePositionsFromLinksKernel" );
updateVelocitiesFromPositionsWithVelocitiesKernel = compileCLKernelFromString( UpdateNodesCLString, "updateVelocitiesFromPositionsWithVelocitiesKernel" );
updateVelocitiesFromPositionsWithoutVelocitiesKernel = compileCLKernelFromString( UpdatePositionsCLString, "updateVelocitiesFromPositionsWithoutVelocitiesKernel" );
integrateKernel = compileCLKernelFromString( IntegrateCLString, "IntegrateKernel" );
applyForcesKernel = compileCLKernelFromString( ApplyForcesCLString, "ApplyForcesKernel" );
prepareLinksKernel = clFunctions.compileCLKernelFromString( PrepareLinksCLString, "PrepareLinksKernel" );
updatePositionsFromVelocitiesKernel = clFunctions.compileCLKernelFromString( UpdatePositionsFromVelocitiesCLString, "UpdatePositionsFromVelocitiesKernel" );
solvePositionsFromLinksKernel = clFunctions.compileCLKernelFromString( SolvePositionsCLString, "SolvePositionsFromLinksKernel" );
updateVelocitiesFromPositionsWithVelocitiesKernel = clFunctions.compileCLKernelFromString( UpdateNodesCLString, "updateVelocitiesFromPositionsWithVelocitiesKernel" );
updateVelocitiesFromPositionsWithoutVelocitiesKernel = clFunctions.compileCLKernelFromString( UpdatePositionsCLString, "updateVelocitiesFromPositionsWithoutVelocitiesKernel" );
computeBoundsKernel = clFunctions.compileCLKernelFromString( ComputeBoundsCLString, "ComputeBoundsKernel" );
solveCollisionsAndUpdateVelocitiesKernel = clFunctions.compileCLKernelFromString( SolveCollisionsAndUpdateVelocitiesCLString, "SolveCollisionsAndUpdateVelocitiesKernel" );
integrateKernel = clFunctions.compileCLKernelFromString( IntegrateCLString, "IntegrateKernel" );
applyForcesKernel = clFunctions.compileCLKernelFromString( ApplyForcesCLString, "ApplyForcesKernel" );
// TODO: Rename to UpdateSoftBodies
resetNormalsAndAreasKernel = compileCLKernelFromString( UpdateNormalsCLString, "ResetNormalsAndAreasKernel" );
normalizeNormalsAndAreasKernel = compileCLKernelFromString( UpdateNormalsCLString, "NormalizeNormalsAndAreasKernel" );
updateSoftBodiesKernel = compileCLKernelFromString( UpdateNormalsCLString, "UpdateSoftBodiesKernel" );
//outputToVertexArrayWithNormalsKernel = compileCLKernelFromString( OutputToVertexArrayCLString, "OutputToVertexArrayWithNormalsKernel" );
//outputToVertexArrayWithoutNormalsKernel = compileCLKernelFromString( OutputToVertexArrayCLString, "OutputToVertexArrayWithoutNormalsKernel" );
resetNormalsAndAreasKernel = clFunctions.compileCLKernelFromString( UpdateNormalsCLString, "ResetNormalsAndAreasKernel" );
normalizeNormalsAndAreasKernel = clFunctions.compileCLKernelFromString( UpdateNormalsCLString, "NormalizeNormalsAndAreasKernel" );
updateSoftBodiesKernel = clFunctions.compileCLKernelFromString( UpdateNormalsCLString, "UpdateSoftBodiesKernel" );
if( returnVal )

View File

@@ -25,12 +25,60 @@ subject to the following restrictions:
#include "btSoftBodySolverVertexData_OpenCL.h"
#include "btSoftBodySolverTriangleData_OpenCL.h"
class CLFunctions
{
protected:
cl_command_queue m_cqCommandQue;
cl_context m_cxMainContext;
public:
CLFunctions(cl_command_queue cqCommandQue, cl_context cxMainContext) :
m_cqCommandQue( cqCommandQue ),
m_cxMainContext( cxMainContext )
{
}
/**
* Compile a compute shader kernel from a string and return the appropriate cl_kernel object.
*/
cl_kernel compileCLKernelFromString( const char* kernelSource, const char* kernelName, const char* additionalMacros = "" );
};
/**
* SoftBody class to maintain information about a soft body instance
* within a solver.
* This data addresses the main solver arrays.
* Entry in the collision shape array.
* Specifies the shape type, the transform matrix and the necessary details of the collisionShape.
*/
struct CollisionShapeDescription
{
Vectormath::Aos::Transform3 shapeTransform;
Vectormath::Aos::Vector3 linearVelocity;
Vectormath::Aos::Vector3 angularVelocity;
int softBodyIdentifier;
int collisionShapeType;
// Both needed for capsule
float radius;
float halfHeight;
int upAxis;
float margin;
float friction;
CollisionShapeDescription()
{
collisionShapeType = 0;
margin = 0;
friction = 0;
}
};
/**
* SoftBody class to maintain information about a soft body instance
* within a solver.
* This data addresses the main solver arrays.
*/
class btOpenCLAcceleratedSoftBodyInterface
{
protected:
@@ -100,6 +148,11 @@ public:
{
return m_firstTriangle;
}
/**
* Update the bounds in the btSoftBody object
*/
void updateBounds( const btVector3 &lowerBound, const btVector3 &upperBound );
// TODO: All of these set functions will have to do checks and
// update the world because restructuring of the arrays will be necessary
@@ -108,7 +161,7 @@ public:
{
m_numVertices = numVertices;
}
void setNumTriangles( int numTriangles )
{
m_numTriangles = numTriangles;
@@ -172,20 +225,61 @@ public:
};
class btOpenCLSoftBodySolver : public btSoftBodySolver
{
private:
public:
struct UIntVector3
{
UIntVector3()
{
x = 0;
y = 0;
z = 0;
_padding = 0;
}
UIntVector3( unsigned int x_, unsigned int y_, unsigned int z_ )
{
x = x_;
y = y_;
z = z_;
_padding = 0;
}
unsigned int x;
unsigned int y;
unsigned int z;
unsigned int _padding;
};
struct CollisionObjectIndices
{
CollisionObjectIndices( int f, int e )
{
firstObject = f;
endObject = e;
}
int firstObject;
int endObject;
};
btSoftBodyLinkDataOpenCL m_linkData;
btSoftBodyVertexDataOpenCL m_vertexData;
btSoftBodyTriangleDataOpenCL m_triangleData;
protected:
CLFunctions clFunctions;
/** Variable to define whether we need to update solver constants on the next iteration */
bool m_updateSolverConstants;
bool m_shadersInitialized;
/**
* Cloths owned by this solver.
* Only our cloths are in this array.
@@ -224,6 +318,46 @@ private:
btAlignedObjectArray< float > m_perClothMediumDensity;
btOpenCLBuffer<float> m_clPerClothMediumDensity;
/**
* Collision shape details: pair of index of first collision shape for the cloth and number of collision objects.
*/
btAlignedObjectArray< CollisionObjectIndices > m_perClothCollisionObjects;
btOpenCLBuffer<CollisionObjectIndices> m_clPerClothCollisionObjects;
/**
* Collision shapes being passed across to the cloths in this solver.
*/
btAlignedObjectArray< CollisionShapeDescription > m_collisionObjectDetails;
btOpenCLBuffer< CollisionShapeDescription > m_clCollisionObjectDetails;
/**
* Minimum bounds for each cloth.
* Updated by GPU and returned for use by broad phase.
* These are int vectors as a reminder that they store the int representation of a float, not a float.
* Bit 31 is inverted - is floats are stored with int-sortable values.
* This is really a uint4 array but thanks to a limitation of OpenCL atomics we are using uints.
*/
btAlignedObjectArray< UIntVector3 > m_perClothMinBounds;
btOpenCLBuffer< UIntVector3 > m_clPerClothMinBounds;
/**
* Maximum bounds for each cloth.
* Updated by GPU and returned for use by broad phase.
* These are int vectors as a reminder that they store the int representation of a float, not a float.
* Bit 31 is inverted - is floats are stored with int-sortable values.
*/
btAlignedObjectArray< UIntVector3 > m_perClothMaxBounds;
btOpenCLBuffer< UIntVector3 > m_clPerClothMaxBounds;
/**
* Friction coefficient for each cloth
*/
btAlignedObjectArray< float > m_perClothFriction;
btOpenCLBuffer< float > m_clPerClothFriction;
cl_kernel prepareLinksKernel;
cl_kernel solvePositionsFromLinksKernel;
cl_kernel updateConstantsKernel;
@@ -233,41 +367,37 @@ private:
cl_kernel updateVelocitiesFromPositionsWithoutVelocitiesKernel;
cl_kernel updateVelocitiesFromPositionsWithVelocitiesKernel;
cl_kernel vSolveLinksKernel;
cl_kernel solveCollisionsAndUpdateVelocitiesKernel;
cl_kernel resetNormalsAndAreasKernel;
cl_kernel normalizeNormalsAndAreasKernel;
cl_kernel computeBoundsKernel;
cl_kernel updateSoftBodiesKernel;
cl_kernel outputToVertexArrayWithNormalsKernel;
cl_kernel outputToVertexArrayWithoutNormalsKernel;
cl_kernel outputToVertexArrayKernel;
cl_kernel applyForcesKernel;
cl_kernel collideSphereKernel;
cl_kernel collideCylinderKernel;
cl_command_queue m_cqCommandQue;
cl_context m_cxMainContext;
size_t m_defaultWorkGroupSize;
/**
* Compile a compute shader kernel from a string and return the appropriate cl_kernel object.
*/
cl_kernel compileCLKernelFromString( const char *shaderString, const char *shaderName );
bool buildShaders();
virtual bool buildShaders();
void resetNormalsAndAreas( int numVertices );
void normalizeNormalsAndAreas( int numVertices );
void executeUpdateSoftBodies( int firstTriangle, int numTriangles );
void prepareCollisionConstraints();
Vectormath::Aos::Vector3 ProjectOnAxis( const Vectormath::Aos::Vector3 &v, const Vectormath::Aos::Vector3 &a );
void ApplyClampedForce( float solverdt, const Vectormath::Aos::Vector3 &force, const Vectormath::Aos::Vector3 &vertexVelocity, float inverseMass, Vectormath::Aos::Vector3 &vertexForce );
btOpenCLAcceleratedSoftBodyInterface *findSoftBodyInterface( const btSoftBody* const softBody );
int findSoftBodyIndex( const btSoftBody* const softBody );
virtual void applyForces( float solverdt );
@@ -276,7 +406,7 @@ private:
*/
virtual void integrate( float solverdt );
void updateConstants( float timeStep );
virtual void updateConstants( float timeStep );
float computeTriangleArea(
const Vectormath::Aos::Point3 &vertex0,
@@ -292,15 +422,20 @@ private:
void updatePositionsFromVelocities( float solverdt );
void solveLinksForPosition( int startLink, int numLinks, float kst, float ti );
virtual void solveLinksForPosition( int startLink, int numLinks, float kst, float ti );
void updateVelocitiesFromPositionsWithVelocities( float isolverdt );
void updateVelocitiesFromPositionsWithoutVelocities( float isolverdt );
void computeBounds( );
virtual void solveCollisionsAndUpdateVelocities( float isolverdt );
// End kernel dispatches
/////////////////////////////////////
void updateBounds();
void releaseKernels();
public:
btOpenCLSoftBodySolver(cl_command_queue queue,cl_context ctx);
@@ -308,7 +443,8 @@ public:
virtual ~btOpenCLSoftBodySolver();
btOpenCLAcceleratedSoftBodyInterface *findSoftBodyInterface( const btSoftBody* const softBody );
virtual btSoftBodyLinkData &getLinkData();
@@ -316,20 +452,27 @@ public:
virtual btSoftBodyTriangleData &getTriangleData();
virtual SolverTypes getSolverType() const
{
return CL_SOLVER;
}
virtual bool checkInitialized();
virtual void updateSoftBodies( );
virtual void optimize( btAlignedObjectArray< btSoftBody * > &softBodies );
virtual void optimize( btAlignedObjectArray< btSoftBody * > &softBodies , bool forceUpdate=false);
virtual void copyBackToSoftBodies();
virtual void solveConstraints( float solverdt );
virtual void predictMotion( float solverdt );
virtual void copySoftBodyToVertexBuffer( const btSoftBody *const softBody, btVertexBufferDescriptor *vertexBuffer );
virtual void processCollision( btSoftBody *, btCollisionObject* );
virtual void processCollision( btSoftBody*, btSoftBody* );
virtual void setDefaultWorkgroupSize(size_t workGroupSize)
{
@@ -339,6 +482,27 @@ public:
{
return m_defaultWorkGroupSize;
}
}; // btOpenCLSoftBodySolver
/**
* Class to manage movement of data from a solver to a given target.
* This version is the CL to CPU version.
*/
class btSoftBodySolverOutputCLtoCPU : public btSoftBodySolverOutput
{
protected:
public:
btSoftBodySolverOutputCLtoCPU()
{
}
/** Output current computed vertex data to the vertex buffers for all cloths in the solver. */
virtual void copySoftBodyToVertexBuffer( const btSoftBody * const softBody, btVertexBufferDescriptor *vertexBuffer );
};
#endif // #ifndef BT_SOFT_BODY_SOLVER_OPENCL_H