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

@@ -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
}