Added GPU SoftBody constraint solvers for DirectX 11 (Direct Compute) and OpenCL, thanks to AMD.

See also http://code.google.com/p/bullet/issues/detail?id=390
Added Demos/DX11ClothDemo
(an OpenCL cloth demo will follow soon)
This commit is contained in:
erwin.coumans
2010-07-20 16:09:53 +00:00
parent 5fd08505ba
commit 11fa2e8b43
99 changed files with 117195 additions and 0 deletions

View File

@@ -77,6 +77,12 @@ ADD_LIBRARY(BulletMultiThreaded
../MiniCL/cl_MiniCL_Defs.h
)
#for now, only Direct 11 (Direct Compute)
IF(USE_DX11)
SUBDIRS(GpuSoftBodySolvers)
ENDIF(USE_DX11)
IF (BUILD_SHARED_LIBS)
TARGET_LINK_LIBRARIES(BulletMultiThreaded BulletDynamics BulletCollision)
ENDIF (BUILD_SHARED_LIBS)

View File

@@ -0,0 +1,22 @@
INCLUDE_DIRECTORIES(
${BULLET_PHYSICS_SOURCE_DIR}/src
)
LIST(APPEND SubDirList "CPU")
# Configure use of OpenCL and DX11
# Generates the settings file and defines libraries and include paths
OPTION(USE_OPENCL "Use OpenCL" OFF)
if( USE_OPENCL )
LIST(APPEND SubDirList "OpenCL")
endif( USE_OPENCL )
if( USE_DX11 )
LIST(APPEND SubDirList "DX11")
endif( USE_DX11 )
SUBDIRS( ${SubDirList} )

View File

@@ -0,0 +1,39 @@
INCLUDE_DIRECTORIES(
${BULLET_PHYSICS_SOURCE_DIR}/src
${VECTOR_MATH_INCLUDE}
)
SET(BulletSoftBodyCPUSolvers_SRCS
btSoftBodySolver_CPU.cpp
)
SET(BulletSoftBodyCPUSolvers_HDRS
btSoftBodySolver_CPU.h
btSoftBodySolverData.h
)
ADD_LIBRARY(BulletSoftBodySolvers_CPU ${BulletSoftBodyCPUSolvers_SRCS} ${BulletSoftBodyCPUSolvers_HDRS} )
SET_TARGET_PROPERTIES(BulletSoftBodySolvers_CPU PROPERTIES VERSION ${BULLET_VERSION})
SET_TARGET_PROPERTIES(BulletSoftBodySolvers_CPU PROPERTIES SOVERSION ${BULLET_VERSION})
IF (INSTALL_LIBS)
IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES)
IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5)
IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK)
INSTALL(TARGETS BulletSoftBodySolvers_CPU DESTINATION .)
ELSE (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK)
INSTALL(TARGETS BulletSoftBodySolvers_CPU DESTINATION lib${LIB_SUFFIX})
INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DESTINATION include FILES_MATCHING PATTERN "*.h")
ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK)
ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5)
IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK)
SET_TARGET_PROPERTIES(BulletSoftBodySolvers_CPU PROPERTIES FRAMEWORK true)
SET_TARGET_PROPERTIES(BulletSoftBodySolvers_CPU PROPERTIES PUBLIC_HEADER "${BulletSoftBodyCPUSolvers_HDRS}")
ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK)
ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES)
ENDIF (INSTALL_LIBS)

View File

@@ -0,0 +1,717 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_SOFT_BODY_SOLVER_DATA_H
#define BT_SOFT_BODY_SOLVER_DATA_H
#include "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h"
#include "vectormath_aos.h"
class btSoftBodyLinkData
{
public:
/**
* Class representing a link as a set of three indices into the vertex array.
*/
class LinkNodePair
{
public:
int vertex0;
int vertex1;
LinkNodePair()
{
vertex0 = 0;
vertex1 = 0;
}
LinkNodePair( int v0, int v1 )
{
vertex0 = v0;
vertex1 = v1;
}
};
/**
* Class describing a link for input into the system.
*/
class LinkDescription
{
protected:
int m_vertex0;
int m_vertex1;
float m_linkLinearStiffness;
float m_linkStrength;
public:
LinkDescription()
{
m_vertex0 = 0;
m_vertex1 = 0;
m_linkLinearStiffness = 1.0;
m_linkStrength = 1.0;
}
LinkDescription( int newVertex0, int newVertex1, float linkLinearStiffness )
{
m_vertex0 = newVertex0;
m_vertex1 = newVertex1;
m_linkLinearStiffness = linkLinearStiffness;
m_linkStrength = 1.0;
}
LinkNodePair getVertexPair() const
{
LinkNodePair nodes;
nodes.vertex0 = m_vertex0;
nodes.vertex1 = m_vertex1;
return nodes;
}
void setVertex0( int vertex )
{
m_vertex0 = vertex;
}
void setVertex1( int vertex )
{
m_vertex1 = vertex;
}
void setLinkLinearStiffness( float linearStiffness )
{
m_linkLinearStiffness = linearStiffness;
}
void setLinkStrength( float strength )
{
m_linkStrength = strength;
}
int getVertex0() const
{
return m_vertex0;
}
int getVertex1() const
{
return m_vertex1;
}
float getLinkStrength() const
{
return m_linkStrength;
}
float getLinkLinearStiffness() const
{
return m_linkLinearStiffness;
}
};
protected:
// NOTE:
// Vertex reference data is stored relative to global array, not relative to individual cloth.
// Values must be correct if being passed into single-cloth VBOs or when migrating from one solver
// to another.
btAlignedObjectArray< LinkNodePair > m_links; // Vertex pair for the link
btAlignedObjectArray< float > m_linkStrength; // Strength of each link
// (inverseMassA + inverseMassB)/ linear stiffness coefficient
btAlignedObjectArray< float > m_linksMassLSC;
btAlignedObjectArray< float > m_linksRestLengthSquared;
// Current vector length of link
btAlignedObjectArray< Vectormath::Aos::Vector3 > m_linksCLength;
// 1/(current length * current length * massLSC)
btAlignedObjectArray< float > m_linksLengthRatio;
btAlignedObjectArray< float > m_linksRestLength;
btAlignedObjectArray< float > m_linksMaterialLinearStiffnessCoefficient;
public:
btSoftBodyLinkData()
{
}
virtual ~btSoftBodyLinkData()
{
}
virtual void clear()
{
m_links.resize(0);
m_linkStrength.resize(0);
m_linksMassLSC.resize(0);
m_linksRestLengthSquared.resize(0);
m_linksLengthRatio.resize(0);
m_linksRestLength.resize(0);
m_linksMaterialLinearStiffnessCoefficient.resize(0);
}
int getNumLinks()
{
return m_links.size();
}
/** Allocate enough space in all link-related arrays to fit numLinks links */
virtual void createLinks( int numLinks )
{
int previousSize = m_links.size();
int newSize = previousSize + numLinks;
// Resize all the arrays that store link data
m_links.resize( newSize );
m_linkStrength.resize( newSize );
m_linksMassLSC.resize( newSize );
m_linksRestLengthSquared.resize( newSize );
m_linksCLength.resize( newSize );
m_linksLengthRatio.resize( newSize );
m_linksRestLength.resize( newSize );
m_linksMaterialLinearStiffnessCoefficient.resize( newSize );
}
/** Insert the link described into the correct data structures assuming space has already been allocated by a call to createLinks */
virtual void setLinkAt( const LinkDescription &link, int linkIndex )
{
m_links[linkIndex] = link.getVertexPair();
m_linkStrength[linkIndex] = link.getLinkStrength();
m_linksMassLSC[linkIndex] = 0.f;
m_linksRestLengthSquared[linkIndex] = 0.f;
m_linksCLength[linkIndex] = Vectormath::Aos::Vector3(0.f, 0.f, 0.f);
m_linksLengthRatio[linkIndex] = 0.f;
m_linksRestLength[linkIndex] = 0.f;
m_linksMaterialLinearStiffnessCoefficient[linkIndex] = link.getLinkLinearStiffness();
}
/**
* Return true if data is on the accelerator.
* The CPU version of this class will return true here because
* the CPU is the same as the accelerator.
*/
virtual bool onAccelerator()
{
return true;
}
/**
* Move data from host memory to the accelerator.
* The CPU version will always return that it has moved it.
*/
virtual bool moveToAccelerator()
{
return true;
}
/**
* Move data from host memory from the accelerator.
* The CPU version will always return that it has moved it.
*/
virtual bool moveFromAccelerator()
{
return true;
}
/**
* Return reference to the vertex index pair for link linkIndex as stored on the host.
*/
LinkNodePair &getVertexPair( int linkIndex )
{
return m_links[linkIndex];
}
/**
* Return reference to strength of link linkIndex as stored on the host.
*/
float &getStrength( int linkIndex )
{
return m_linkStrength[linkIndex];
}
/**
* Return a reference to the strength of the link corrected for link sorting.
* This is important if we are using data on an accelerator which has the data sorted in some fashion.
*/
virtual float &getStrengthCorrected( int linkIndex )
{
return getStrength( linkIndex );
}
/**
* Return reference to the rest length of link linkIndex as stored on the host.
*/
float &getRestLength( int linkIndex )
{
return m_linksRestLength[linkIndex];
}
/**
* Return reference to linear stiffness coefficient for link linkIndex as stored on the host.
*/
float &getLinearStiffnessCoefficient( int linkIndex )
{
return m_linksMaterialLinearStiffnessCoefficient[linkIndex];
}
/**
* Return reference to the MassLSC value for link linkIndex as stored on the host.
*/
float &getMassLSC( int linkIndex )
{
return m_linksMassLSC[linkIndex];
}
/**
* Return reference to rest length squared for link linkIndex as stored on the host.
*/
float &getRestLengthSquared( int linkIndex )
{
return m_linksRestLengthSquared[linkIndex];
}
/**
* Return reference to current length of link linkIndex as stored on the host.
*/
Vectormath::Aos::Vector3 &getCurrentLength( int linkIndex )
{
return m_linksCLength[linkIndex];
}
/**
* Return the link length ratio from for link linkIndex as stored on the host.
*/
float &getLinkLengthRatio( int linkIndex )
{
return m_linksLengthRatio[linkIndex];
}
};
/**
* Wrapper for vertex data information.
* By wrapping it like this we stand a good chance of being able to optimise for storage format easily.
* It should also help us make sure all the data structures remain consistent.
*/
class btSoftBodyVertexData
{
public:
/**
* Class describing a vertex for input into the system.
*/
class VertexDescription
{
private:
Vectormath::Aos::Point3 m_position;
/** Inverse mass. If this is 0f then the mass was 0 because that simplifies calculations. */
float m_inverseMass;
public:
VertexDescription()
{
m_position = Vectormath::Aos::Point3( 0.f, 0.f, 0.f );
m_inverseMass = 0.f;
}
VertexDescription( const Vectormath::Aos::Point3 &position, float mass )
{
m_position = position;
if( mass > 0.f )
m_inverseMass = 1.0f/mass;
else
m_inverseMass = 0.f;
}
void setPosition( const Vectormath::Aos::Point3 &position )
{
m_position = position;
}
void setInverseMass( float inverseMass )
{
m_inverseMass = inverseMass;
}
void setMass( float mass )
{
if( mass > 0.f )
m_inverseMass = 1.0f/mass;
else
m_inverseMass = 0.f;
}
Vectormath::Aos::Point3 getPosition() const
{
return m_position;
}
float getInverseMass() const
{
return m_inverseMass;
}
float getMass() const
{
if( m_inverseMass == 0.f )
return 0.f;
else
return 1.0f/m_inverseMass;
}
};
protected:
// identifier for the individual cloth
// For the CPU we don't really need this as we can grab the cloths and iterate over only their vertices
// For a parallel accelerator knowing on a per-vertex basis which cloth we're part of will help for obtaining
// per-cloth data
// For sorting etc it might also be helpful to be able to use in-array data such as this.
btAlignedObjectArray< int > m_clothIdentifier;
btAlignedObjectArray< Vectormath::Aos::Point3 > m_vertexPosition; // vertex positions
btAlignedObjectArray< Vectormath::Aos::Point3 > m_vertexPreviousPosition; // vertex positions
btAlignedObjectArray< Vectormath::Aos::Vector3 > m_vertexVelocity; // Velocity
btAlignedObjectArray< Vectormath::Aos::Vector3 > m_vertexForceAccumulator; // Force accumulator
btAlignedObjectArray< Vectormath::Aos::Vector3 > m_vertexNormal; // Normals
btAlignedObjectArray< float > m_vertexInverseMass; // Inverse mass
btAlignedObjectArray< float > m_vertexArea; // Area controlled by the vertex
btAlignedObjectArray< int > m_vertexTriangleCount; // Number of triangles touching this vertex
public:
btSoftBodyVertexData()
{
}
virtual void clear()
{
m_clothIdentifier.resize(0);
m_vertexPosition.resize(0);
m_vertexPreviousPosition.resize(0);
m_vertexVelocity.resize(0);
m_vertexForceAccumulator.resize(0);
m_vertexNormal.resize(0);
m_vertexInverseMass.resize(0);
m_vertexArea.resize(0);
m_vertexTriangleCount.resize(0);
}
int getNumVertices()
{
return m_vertexPosition.size();
}
int getClothIdentifier( int vertexIndex )
{
return m_clothIdentifier[vertexIndex];
}
void setVertexAt( const VertexDescription &vertex, int vertexIndex )
{
m_vertexPosition[vertexIndex] = vertex.getPosition();
m_vertexPreviousPosition[vertexIndex] = vertex.getPosition();
m_vertexVelocity[vertexIndex] = Vectormath::Aos::Vector3(0.f, 0.f, 0.f);
m_vertexForceAccumulator[vertexIndex] = Vectormath::Aos::Vector3(0.f, 0.f, 0.f);
m_vertexNormal[vertexIndex] = Vectormath::Aos::Vector3(0.f, 0.f, 0.f);
m_vertexInverseMass[vertexIndex] = vertex.getInverseMass();
m_vertexArea[vertexIndex] = 0.f;
m_vertexTriangleCount[vertexIndex] = 0;
}
/** Create numVertices new vertices for cloth clothIdentifier */
void createVertices( int numVertices, int clothIdentifier )
{
int previousSize = m_vertexPosition.size();
int newSize = previousSize + numVertices;
// Resize all the arrays that store vertex data
m_clothIdentifier.resize( newSize );
m_vertexPosition.resize( newSize );
m_vertexPreviousPosition.resize( newSize );
m_vertexVelocity.resize( newSize );
m_vertexForceAccumulator.resize( newSize );
m_vertexNormal.resize( newSize );
m_vertexInverseMass.resize( newSize );
m_vertexArea.resize( newSize );
m_vertexTriangleCount.resize( newSize );
for( int vertexIndex = previousSize; vertexIndex < newSize; ++vertexIndex )
m_clothIdentifier[vertexIndex] = clothIdentifier;
}
// Get and set methods in header so they can be inlined
/**
* Return a reference to the position of vertex vertexIndex as stored on the host.
*/
Vectormath::Aos::Point3 &getPosition( int vertexIndex )
{
return m_vertexPosition[vertexIndex];
}
/**
* Return a reference to the previous position of vertex vertexIndex as stored on the host.
*/
Vectormath::Aos::Point3 &getPreviousPosition( int vertexIndex )
{
return m_vertexPreviousPosition[vertexIndex];
}
/**
* Return a reference to the velocity of vertex vertexIndex as stored on the host.
*/
Vectormath::Aos::Vector3 &getVelocity( int vertexIndex )
{
return m_vertexVelocity[vertexIndex];
}
/**
* Return a reference to the force accumulator of vertex vertexIndex as stored on the host.
*/
Vectormath::Aos::Vector3 &getForceAccumulator( int vertexIndex )
{
return m_vertexForceAccumulator[vertexIndex];
}
/**
* Return a reference to the normal of vertex vertexIndex as stored on the host.
*/
Vectormath::Aos::Vector3 &getNormal( int vertexIndex )
{
return m_vertexNormal[vertexIndex];
}
/**
* Return a reference to the inverse mass of vertex vertexIndex as stored on the host.
*/
float &getInverseMass( int vertexIndex )
{
return m_vertexInverseMass[vertexIndex];
}
/**
* Get access to the area controlled by this vertex.
*/
float &getArea( int vertexIndex )
{
return m_vertexArea[vertexIndex];
}
/**
* Get access to the array of how many triangles touch each vertex.
*/
int &getTriangleCount( int vertexIndex )
{
return m_vertexTriangleCount[vertexIndex];
}
/**
* Return true if data is on the accelerator.
* The CPU version of this class will return true here because
* the CPU is the same as the accelerator.
*/
virtual bool onAccelerator()
{
return true;
}
/**
* Move data from host memory to the accelerator.
* The CPU version will always return that it has moved it.
*/
virtual bool moveToAccelerator()
{
return true;
}
/**
* Move data from host memory from the accelerator.
* The CPU version will always return that it has moved it.
*/
virtual bool moveFromAccelerator()
{
return true;
}
btAlignedObjectArray< Vectormath::Aos::Point3 > &getVertexPositions()
{
return m_vertexPosition;
}
};
class btSoftBodyTriangleData
{
public:
/**
* Class representing a triangle as a set of three indices into the
* vertex array.
*/
class TriangleNodeSet
{
public:
int vertex0;
int vertex1;
int vertex2;
int _padding;
TriangleNodeSet( )
{
vertex0 = 0;
vertex1 = 0;
vertex2 = 0;
_padding = -1;
}
TriangleNodeSet( int newVertex0, int newVertex1, int newVertex2 )
{
vertex0 = newVertex0;
vertex1 = newVertex1;
vertex2 = newVertex2;
}
};
class TriangleDescription
{
protected:
int m_vertex0;
int m_vertex1;
int m_vertex2;
public:
TriangleDescription()
{
m_vertex0 = 0;
m_vertex1 = 0;
m_vertex2 = 0;
}
TriangleDescription( int newVertex0, int newVertex1, int newVertex2 )
{
m_vertex0 = newVertex0;
m_vertex1 = newVertex1;
m_vertex2 = newVertex2;
}
TriangleNodeSet getVertexSet() const
{
btSoftBodyTriangleData::TriangleNodeSet nodes;
nodes.vertex0 = m_vertex0;
nodes.vertex1 = m_vertex1;
nodes.vertex2 = m_vertex2;
return nodes;
}
};
protected:
// NOTE:
// Vertex reference data is stored relative to global array, not relative to individual cloth.
// Values must be correct if being passed into single-cloth VBOs or when migrating from one solver
// to another.
btAlignedObjectArray< TriangleNodeSet > m_vertexIndices;
btAlignedObjectArray< float > m_area;
btAlignedObjectArray< Vectormath::Aos::Vector3 > m_normal;
public:
btSoftBodyTriangleData()
{
}
virtual void clear()
{
m_vertexIndices.resize(0);
m_area.resize(0);
m_normal.resize(0);
}
int getNumTriangles()
{
return m_vertexIndices.size();
}
virtual void setTriangleAt( const TriangleDescription &triangle, int triangleIndex )
{
m_vertexIndices[triangleIndex] = triangle.getVertexSet();
}
virtual void createTriangles( int numTriangles )
{
int previousSize = m_vertexIndices.size();
int newSize = previousSize + numTriangles;
// Resize all the arrays that store triangle data
m_vertexIndices.resize( newSize );
m_area.resize( newSize );
m_normal.resize( newSize );
}
/**
* Return the vertex index set for triangle triangleIndex as stored on the host.
*/
const TriangleNodeSet &getVertexSet( int triangleIndex )
{
return m_vertexIndices[triangleIndex];
}
/**
* Get access to the triangle area.
*/
float &getTriangleArea( int triangleIndex )
{
return m_area[triangleIndex];
}
/**
* Get access to the normal vector for this triangle.
*/
Vectormath::Aos::Vector3 &getNormal( int triangleIndex )
{
return m_normal[triangleIndex];
}
/**
* Return true if data is on the accelerator.
* The CPU version of this class will return true here because
* the CPU is the same as the accelerator.
*/
virtual bool onAccelerator()
{
return true;
}
/**
* Move data from host memory to the accelerator.
* The CPU version will always return that it has moved it.
*/
virtual bool moveToAccelerator()
{
return true;
}
/**
* Move data from host memory from the accelerator.
* The CPU version will always return that it has moved it.
*/
virtual bool moveFromAccelerator()
{
return true;
}
};
#endif // #ifndef BT_SOFT_BODY_SOLVER_DATA_H

View File

@@ -0,0 +1,766 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h"
#include "BulletCollision/CollisionDispatch/btCollisionObject.h"
#include "BulletCollision/CollisionShapes/btCollisionShape.h"
#include "vectormath_aos.h"
#include "BulletMultiThreaded/GpuSoftBodySolvers/CPU/btSoftBodySolver_CPU.h"
#include "BulletSoftBody/btSoftBody.h"
#include "BulletCollision/CollisionShapes/btCapsuleShape.h"
btCPUSoftBodySolver::btCPUSoftBodySolver()
{
// 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
// for performance in future once we understand more clearly when constants need to be updated
m_updateSolverConstants = true;
}
btCPUSoftBodySolver::~btCPUSoftBodySolver()
{
}
btSoftBodyLinkData &btCPUSoftBodySolver::getLinkData()
{
return m_linkData;
}
btSoftBodyVertexData &btCPUSoftBodySolver::getVertexData()
{
return m_vertexData;
}
btSoftBodyTriangleData &btCPUSoftBodySolver::getTriangleData()
{
return m_triangleData;
}
static Vectormath::Aos::Vector3 toVector3( const btVector3 &vec )
{
Vectormath::Aos::Vector3 outVec( vec.getX(), vec.getY(), vec.getZ() );
return outVec;
}
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 btCPUSoftBodySolver::optimize( btAlignedObjectArray< btSoftBody * > &softBodies )
{
if( m_softBodySet.size() != softBodies.size() )
{
// Have a change in the soft body set so update, reloading all the data
getVertexData().clear();
getTriangleData().clear();
getLinkData().clear();
m_softBodySet.resize(0);
for( int softBodyIndex = 0; softBodyIndex < softBodies.size(); ++softBodyIndex )
{
btSoftBody *softBody = softBodies[ softBodyIndex ];
using Vectormath::Aos::Matrix3;
using Vectormath::Aos::Point3;
// Create SoftBody that will store the information within the solver
btAcceleratedSoftBodyInterface *newSoftBody = new btAcceleratedSoftBodyInterface( softBody );
m_softBodySet.push_back( newSoftBody );
m_perClothAcceleration.push_back( toVector3(softBody->getWorldInfo()->m_gravity) );
m_perClothDampingFactor.push_back(softBody->m_cfg.kDP);
m_perClothVelocityCorrectionCoefficient.push_back( softBody->m_cfg.kVCF );
m_perClothLiftFactor.push_back( softBody->m_cfg.kLF );
m_perClothDragFactor.push_back( softBody->m_cfg.kDG );
m_perClothMediumDensity.push_back(softBody->getWorldInfo()->air_density);
// Add space for new vertices and triangles in the default solver for now
// TODO: Include space here for tearing too later
int firstVertex = getVertexData().getNumVertices();
int numVertices = softBody->m_nodes.size();
int maxVertices = numVertices;
// Allocate space for new vertices in all the vertex arrays
getVertexData().createVertices( maxVertices, softBodyIndex );
int firstTriangle = getTriangleData().getNumTriangles();
int numTriangles = softBody->m_faces.size();
int maxTriangles = numTriangles;
getTriangleData().createTriangles( maxTriangles );
// Copy vertices from softbody into the solver
for( int vertex = 0; vertex < numVertices; ++vertex )
{
Point3 multPoint(softBody->m_nodes[vertex].m_x.getX(), softBody->m_nodes[vertex].m_x.getY(), softBody->m_nodes[vertex].m_x.getZ());
btSoftBodyVertexData::VertexDescription desc;
// TODO: Position in the softbody might be pre-transformed
// or we may need to adapt for the pose.
//desc.setPosition( cloth.getMeshTransform()*multPoint );
desc.setPosition( multPoint );
float vertexInverseMass = softBody->m_nodes[vertex].m_im;
desc.setInverseMass(vertexInverseMass);
getVertexData().setVertexAt( desc, firstVertex + vertex );
}
// Copy triangles similarly
// We're assuming here that vertex indices are based on the firstVertex rather than the entire scene
for( int triangle = 0; triangle < numTriangles; ++triangle )
{
// Note that large array storage is relative to the array not to the cloth
// So we need to add firstVertex to each value
int vertexIndex0 = (softBody->m_faces[triangle].m_n[0] - &(softBody->m_nodes[0]));
int vertexIndex1 = (softBody->m_faces[triangle].m_n[1] - &(softBody->m_nodes[0]));
int vertexIndex2 = (softBody->m_faces[triangle].m_n[2] - &(softBody->m_nodes[0]));
btSoftBodyTriangleData::TriangleDescription newTriangle(vertexIndex0 + firstVertex, vertexIndex1 + firstVertex, vertexIndex2 + firstVertex);
getTriangleData().setTriangleAt( newTriangle, firstTriangle + triangle );
// Increase vertex triangle counts for this triangle
getVertexData().getTriangleCount(newTriangle.getVertexSet().vertex0)++;
getVertexData().getTriangleCount(newTriangle.getVertexSet().vertex1)++;
getVertexData().getTriangleCount(newTriangle.getVertexSet().vertex2)++;
}
int firstLink = getLinkData().getNumLinks();
int numLinks = softBody->m_links.size();
int maxLinks = numLinks;
// Allocate space for the links
getLinkData().createLinks( numLinks );
// Add the links
for( int link = 0; link < numLinks; ++link )
{
int vertexIndex0 = softBody->m_links[link].m_n[0] - &(softBody->m_nodes[0]);
int vertexIndex1 = softBody->m_links[link].m_n[1] - &(softBody->m_nodes[0]);
btSoftBodyLinkData::LinkDescription newLink(vertexIndex0 + firstVertex, vertexIndex1 + firstVertex, softBody->m_links[link].m_material->m_kLST);
newLink.setLinkStrength(1.f);
getLinkData().setLinkAt(newLink, firstLink + link);
}
newSoftBody->setFirstVertex( firstVertex );
newSoftBody->setFirstTriangle( firstTriangle );
newSoftBody->setNumVertices( numVertices );
newSoftBody->setMaxVertices( maxVertices );
newSoftBody->setNumTriangles( numTriangles );
newSoftBody->setMaxTriangles( maxTriangles );
newSoftBody->setFirstLink( firstLink );
newSoftBody->setNumLinks( numLinks );
}
updateConstants(0.f);
}
}
void btCPUSoftBodySolver::updateSoftBodies()
{
using namespace Vectormath::Aos;
int numVertices = m_vertexData.getNumVertices();
int numTriangles = m_triangleData.getNumTriangles();
// Initialise normal and vertex counts
for( int vertexIndex = 0; vertexIndex < numVertices; ++vertexIndex )
{
m_vertexData.getArea(vertexIndex) = 0.f;
m_vertexData.getNormal(vertexIndex) = Vector3(0.f, 0.f, 0.f);
}
// Update the areas for the triangles and vertices.
for( int triangleIndex = 0; triangleIndex < numTriangles; ++triangleIndex )
{
float &triangleArea( m_triangleData.getTriangleArea( triangleIndex ) );
const btSoftBodyTriangleData::TriangleNodeSet &vertices( m_triangleData.getVertexSet(triangleIndex) );
Point3 &vertexPosition0( m_vertexData.getPosition( vertices.vertex0 ) );
Point3 &vertexPosition1( m_vertexData.getPosition( vertices.vertex1 ) );
Point3 &vertexPosition2( m_vertexData.getPosition( vertices.vertex2 ) );
triangleArea = computeTriangleArea( vertexPosition0, vertexPosition1, vertexPosition2 );
// Add to areas for vertices and increase the count of the number of triangles affecting the vertex
m_vertexData.getArea(vertices.vertex0) += triangleArea;
m_vertexData.getArea(vertices.vertex1) += triangleArea;
m_vertexData.getArea(vertices.vertex2) += triangleArea;
Point3 &vertex0( m_vertexData.getPosition(vertices.vertex0) );
Point3 &vertex1( m_vertexData.getPosition(vertices.vertex1) );
Point3 &vertex2( m_vertexData.getPosition(vertices.vertex2) );
Vector3 triangleNormal = cross( vertex1-vertex0, vertex2 - vertex0 );
m_triangleData.getNormal(triangleIndex) = normalize(triangleNormal);
m_vertexData.getNormal(vertices.vertex0) += triangleNormal;
m_vertexData.getNormal(vertices.vertex1) += triangleNormal;
m_vertexData.getNormal(vertices.vertex2) += triangleNormal;
}
// Normalise the area and normals
for( int vertexIndex = 0; vertexIndex < numVertices; ++vertexIndex )
{
m_vertexData.getArea(vertexIndex) /= m_vertexData.getTriangleCount(vertexIndex);
m_vertexData.getNormal(vertexIndex) = normalize( m_vertexData.getNormal(vertexIndex) );
}
// Clear the collision shape array for the next frame
m_collisionObjectDetails.clear();
} // updateSoftBodies
Vectormath::Aos::Vector3 btCPUSoftBodySolver::ProjectOnAxis( const Vectormath::Aos::Vector3 &v, const Vectormath::Aos::Vector3 &a )
{
return a*Vectormath::Aos::dot(v, a);
}
void btCPUSoftBodySolver::ApplyClampedForce( float solverdt, const Vectormath::Aos::Vector3 &force, const Vectormath::Aos::Vector3 &vertexVelocity, float inverseMass, Vectormath::Aos::Vector3 &vertexForce )
{
float dtInverseMass = solverdt*inverseMass;
if( Vectormath::Aos::lengthSqr(force * dtInverseMass) > Vectormath::Aos::lengthSqr(vertexVelocity) )
{
vertexForce -= ProjectOnAxis( vertexVelocity, normalize( force ) )/dtInverseMass;
} else {
vertexForce += force;
}
}
bool btCPUSoftBodySolver::checkInitialized()
{
return true;
}
void btCPUSoftBodySolver::applyForces( float solverdt )
{
using namespace Vectormath::Aos;
int numVertices = m_vertexData.getNumVertices();
for( int clothIndex = 0; clothIndex < m_softBodySet.size(); ++clothIndex )
{
btAcceleratedSoftBodyInterface *currentCloth = m_softBodySet[clothIndex];
const int startVertex = currentCloth->getFirstVertex();
const int numVertices = currentCloth->getNumVertices();
Vector3 velocityChange = m_perClothAcceleration[clothIndex]*solverdt;
for( int vertexIndex = startVertex; vertexIndex < (startVertex + numVertices); ++vertexIndex )
{
float inverseMass = m_vertexData.getInverseMass( vertexIndex );
Vector3 &vertexVelocity( m_vertexData.getVelocity( vertexIndex ) );
// First apply the global acceleration to all vertices
if( inverseMass > 0 )
vertexVelocity += velocityChange;
// If it's a non-static vertex
if( m_vertexData.getInverseMass(vertexIndex) > 0 )
{
// Wind effects on a wind-per-cloth basis
float liftFactor = m_perClothLiftFactor[clothIndex];
float dragFactor = m_perClothDragFactor[clothIndex];
if( (liftFactor > 0.f) || (dragFactor > 0.f) )
{
Vector3 normal = m_vertexData.getNormal(vertexIndex);
Vector3 relativeWindVelocity = m_vertexData.getVelocity(vertexIndex) - m_perClothWindVelocity[clothIndex];
float relativeSpeedSquared = lengthSqr(relativeWindVelocity);
if( relativeSpeedSquared > FLT_EPSILON )
{
normal = normal * (dot(normal, relativeWindVelocity) < 0 ? -1.f : +1.f);
float dvNormal = dot(normal, relativeWindVelocity);
if( dvNormal > 0 )
{
Vector3 force( 0.f, 0.f, 0.f );
float c0 = m_vertexData.getArea(vertexIndex) * dvNormal * relativeSpeedSquared / 2;
float c1 = c0 * m_perClothMediumDensity[clothIndex];
force += normal * (-c1 * liftFactor);
force += normalize(relativeWindVelocity)*(-c1 * dragFactor);
Vectormath::Aos::Vector3 &vertexForce( m_vertexData.getForceAccumulator(vertexIndex) );
ApplyClampedForce( solverdt, force, vertexVelocity, inverseMass, vertexForce );
}
}
}
}
}
}
} // btCPUSoftBodySolver::applyForces
/**
* Integrate motion on the solver.
*/
void btCPUSoftBodySolver::integrate( float solverdt )
{
using namespace Vectormath::Aos;
int numVertices = m_vertexData.getNumVertices();
for( int vertexIndex = 0; vertexIndex < numVertices; ++vertexIndex )
{
Point3 &position( m_vertexData.getPosition(vertexIndex) );
Point3 &previousPosition( m_vertexData.getPreviousPosition(vertexIndex) );
Vector3 &forceAccumulator( m_vertexData.getForceAccumulator(vertexIndex) );
Vector3 &velocity( m_vertexData.getVelocity(vertexIndex) );
float inverseMass = m_vertexData.getInverseMass(vertexIndex);
previousPosition = position;
velocity += forceAccumulator * inverseMass * solverdt;
position += velocity * solverdt;
forceAccumulator = Vector3(0.f, 0.f, 0.f);
}
} // btCPUSoftBodySolver::integrate
float btCPUSoftBodySolver::computeTriangleArea(
const Vectormath::Aos::Point3 &vertex0,
const Vectormath::Aos::Point3 &vertex1,
const Vectormath::Aos::Point3 &vertex2 )
{
Vectormath::Aos::Vector3 a = vertex1 - vertex0;
Vectormath::Aos::Vector3 b = vertex2 - vertex0;
Vectormath::Aos::Vector3 crossProduct = cross(a, b);
float area = length( crossProduct );
return area;
}
void btCPUSoftBodySolver::updateConstants( float timeStep )
{
using namespace Vectormath::Aos;
if( m_updateSolverConstants )
{
m_updateSolverConstants = false;
// Will have to redo this if we change the structure (tear, maybe) or various other possible changes
// Initialise link constants
const int numLinks = m_linkData.getNumLinks();
for( int linkIndex = 0; linkIndex < numLinks; ++linkIndex )
{
btSoftBodyLinkData::LinkNodePair &vertices( m_linkData.getVertexPair(linkIndex) );
m_linkData.getRestLength(linkIndex) = length((m_vertexData.getPosition( vertices.vertex0 ) - m_vertexData.getPosition( vertices.vertex1 )));
float invMass0 = m_vertexData.getInverseMass(vertices.vertex0);
float invMass1 = m_vertexData.getInverseMass(vertices.vertex1);
float linearStiffness = m_linkData.getLinearStiffnessCoefficient(linkIndex);
float massLSC = (invMass0 + invMass1)/linearStiffness;
m_linkData.getMassLSC(linkIndex) = massLSC;
float restLength = m_linkData.getRestLength(linkIndex);
float restLengthSquared = restLength*restLength;
m_linkData.getRestLengthSquared(linkIndex) = restLengthSquared;
}
}
} // btCPUSoftBodySolver::updateConstants
/**
* 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
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] );
}
// Generating indexing for perClothCollisionObjects
// First clear the previous values
for( int clothIndex = 0; clothIndex < m_perClothCollisionObjects.size(); ++clothIndex )
{
m_perClothCollisionObjects[clothIndex].firstObject = 0;
m_perClothCollisionObjects[clothIndex].endObject = 0;
}
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;
}
}
//m_perClothCollisionObjects
} // prepareCollisionConstraints
void btCPUSoftBodySolver::solveConstraints( float solverdt )
{
using Vectormath::Aos::Vector3;
using Vectormath::Aos::Point3;
using Vectormath::Aos::lengthSqr;
using Vectormath::Aos::dot;
// Prepare links
int numLinks = m_linkData.getNumLinks();
int numVertices = m_vertexData.getNumVertices();
float kst = 1.f;
for( int linkIndex = 0; linkIndex < numLinks; ++linkIndex )
{
btSoftBodyLinkData::LinkNodePair &nodePair( m_linkData.getVertexPair(linkIndex) );
Vector3 currentLength = m_vertexData.getPreviousPosition( nodePair.vertex1 ) - m_vertexData.getPreviousPosition( nodePair.vertex0 );
m_linkData.getCurrentLength(linkIndex) = currentLength;
// If mass at both ends of links is 0 (both static points) then we don't want this information.
// In reality this would be a fairly pointless link, but it could have been inserted
float linkLengthRatio = 0;
if( m_linkData.getMassLSC(linkIndex) > 0 )
linkLengthRatio = 1.f/(lengthSqr(currentLength) * m_linkData.getMassLSC(linkIndex));
m_linkData.getLinkLengthRatio(linkIndex) = linkLengthRatio;
}
#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 )
{
// Solve velocity
for(int linkIndex = 0; linkIndex < numLinks; ++linkIndex)
{
int vertexIndex0 = m_linkData.getVertexPair(linkIndex).vertex0;
int vertexIndex1 = m_linkData.getVertexPair(linkIndex).vertex1;
float j = -dot(m_linkData.getCurrentLength(linkIndex), m_vertexData.getVelocity(vertexIndex0) - m_vertexData.getVelocity(vertexIndex1)) * m_linkData.getLinkLengthRatio(linkIndex)*kst;
// If both ends of the link have no mass then this will be zero. Catch that case.
// TODO: Should really catch the /0 in the link setup, too
//if(psb->m_linksc0[i]>0)
{
m_vertexData.getVelocity(vertexIndex0) = m_vertexData.getVelocity(vertexIndex0) + m_linkData.getCurrentLength(linkIndex)*j*m_vertexData.getInverseMass(vertexIndex0);
m_vertexData.getVelocity(vertexIndex1) = m_vertexData.getVelocity(vertexIndex1) - m_linkData.getCurrentLength(linkIndex)*j*m_vertexData.getInverseMass(vertexIndex1);
}
}
}
// 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
if( m_numberOfVelocityIterations > 0 )
{
for(int vertexIndex = 0; vertexIndex < numVertices; ++vertexIndex)
{
m_vertexData.getPosition(vertexIndex) = m_vertexData.getPreviousPosition(vertexIndex) + m_vertexData.getVelocity(vertexIndex) * solverdt;
m_vertexData.getPreviousPosition(vertexIndex) = m_vertexData.getPosition(vertexIndex);
}
}
// Solve drift
for( int iteration = 0; iteration < m_numberOfPositionIterations ; ++iteration )
{
for( int clothIndex = 0; clothIndex < m_softBodySet.size(); ++clothIndex )
{
btAcceleratedSoftBodyInterface *currentCloth = m_softBodySet[clothIndex];
const int startLink = currentCloth->getFirstLink();
const int numLinks = currentCloth->getNumLinks();
int endLink = startLink + numLinks;
for(int linkIndex = startLink; linkIndex < endLink; ++linkIndex)
{
int vertexIndex0 = m_linkData.getVertexPair(linkIndex).vertex0;
int vertexIndex1 = m_linkData.getVertexPair(linkIndex).vertex1;
float massLSC = m_linkData.getMassLSC(linkIndex);
if( massLSC > 0.f )
{
Point3 &vertexPosition0( m_vertexData.getPosition( vertexIndex0 ) );
Point3 &vertexPosition1( m_vertexData.getPosition( vertexIndex1 ) );
Vector3 del = vertexPosition1 - vertexPosition0;
float len = lengthSqr(del);
float restLength2 = m_linkData.getRestLengthSquared(linkIndex);
float k = ((restLength2 - len) / (massLSC * (restLength2 + len) ) )*kst;
vertexPosition0 -= del*(k*m_vertexData.getInverseMass(vertexIndex0));
vertexPosition1 += del*(k*m_vertexData.getInverseMass(vertexIndex1));
}
}
}
}
for( int clothIndex = 0; clothIndex < m_softBodySet.size(); ++clothIndex )
{
btAcceleratedSoftBodyInterface *currentCloth = m_softBodySet[clothIndex];
const int startLink = currentCloth->getFirstLink();
const int numLinks = currentCloth->getNumLinks();
const int startVertex = currentCloth->getFirstVertex();
const int numVertices = currentCloth->getNumVertices();
const int lastVertex = startVertex + numVertices;
// Update the velocities based on the change in position
// TODO: Damping should only be applied to the action of link constraints so the cloth still falls but then moves stiffly once it hits something
float velocityCoefficient = (1.f - m_perClothDampingFactor[clothIndex]);
float velocityCorrectionCoefficient = m_perClothVelocityCorrectionCoefficient[clothIndex];
float isolverDt = 1.f/solverdt;
if( m_numberOfVelocityIterations > 0 )
{
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);
}
}
}
} // btCPUSoftBodySolver::solveConstraints
btCPUSoftBodySolver::btAcceleratedSoftBodyInterface *btCPUSoftBodySolver::findSoftBodyInterface( const btSoftBody* const softBody )
{
for( int softBodyIndex = 0; softBodyIndex < m_softBodySet.size(); ++softBodyIndex )
{
btAcceleratedSoftBodyInterface *softBodyInterface = m_softBodySet[softBodyIndex];
if( softBodyInterface->getSoftBody() == softBody )
return softBodyInterface;
}
return 0;
}
void btCPUSoftBodySolver::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 );
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;
}
}
}
} // btCPUSoftBodySolver::outputToVertexBuffers
void btCPUSoftBodySolver::addCollisionObjectForSoftBody( int clothIndex, btCollisionObject *collisionObject )
{
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");
}
}
void btCPUSoftBodySolver::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 )
{
btSoftBody *softBody = m_softBodySet[softBodyIndex]->getSoftBody();
m_perClothWindVelocity[softBodyIndex] = toVector3(softBody->getWindVelocity());
}
// 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() );
// End prediction work for solvers
}

View File

@@ -0,0 +1,345 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_ACCELERATED_SOFT_BODY_CPU_SOLVER_H
#define BT_ACCELERATED_SOFT_BODY_CPU_SOLVER_H
#include "vectormath_aos.h"
#include "BulletSoftBody/btSoftBodySolvers.h"
#include "BulletSoftBody/btSoftBodySolverVertexBuffer.h"
#include "BulletMultiThreaded/GpuSoftBodySolvers/CPU/btSoftBodySolverData.h"
class btCPUSoftBodySolver : 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
{
int softBodyIdentifier;
int collisionShapeType;
Vectormath::Aos::Transform3 shapeTransform;
union
{
struct Sphere
{
float radius;
} sphere;
struct Capsule
{
float radius;
float halfHeight;
} capsule;
} shapeInformation;
CollisionShapeDescription()
{
collisionShapeType = 0;
}
};
/**
* 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;
}
// 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;
}
#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
};
struct CollisionObjectIndices
{
int firstObject;
int endObject;
};
btSoftBodyLinkData m_linkData;
btSoftBodyVertexData m_vertexData;
btSoftBodyTriangleData m_triangleData;
/** Variable to define whether we need to update solver constants on the next iteration */
bool m_updateSolverConstants;
/**
* Cloths owned by this solver.
* Only our cloths are in this array.
*/
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.
*/
btAlignedObjectArray< Vectormath::Aos::Vector3 > m_perClothAcceleration;
/** 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;
/** Velocity damping factor */
btAlignedObjectArray< float > m_perClothDampingFactor;
/** Velocity correction coefficient */
btAlignedObjectArray< float > m_perClothVelocityCorrectionCoefficient;
/** Lift parameter for wind effect on cloth. */
btAlignedObjectArray< float > m_perClothLiftFactor;
/** Drag parameter for wind effect on cloth. */
btAlignedObjectArray< float > m_perClothDragFactor;
/** Density of the medium in which each cloth sits */
btAlignedObjectArray< float > m_perClothMediumDensity;
/**
* Collision shape details: pair of index of first collision shape for the cloth and number of collision objects.
*/
btAlignedObjectArray< CollisionObjectIndices > m_perClothCollisionObjects;
/**
* Collision shapes being passed across to the cloths in this solver.
*/
btAlignedObjectArray< CollisionShapeDescription > m_collisionObjectDetails;
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 );
float computeTriangleArea(
const Vectormath::Aos::Point3 &vertex0,
const Vectormath::Aos::Point3 &vertex1,
const Vectormath::Aos::Point3 &vertex2 );
void applyForces( float solverdt );
void integrate( float solverdt );
void updateConstants( float timeStep );
btAcceleratedSoftBodyInterface *findSoftBodyInterface( const btSoftBody* const softBody );
public:
btCPUSoftBodySolver();
virtual ~btCPUSoftBodySolver();
virtual btSoftBodyLinkData &getLinkData();
virtual btSoftBodyVertexData &getVertexData();
virtual btSoftBodyTriangleData &getTriangleData();
/**
* Add a collision object to be used by the indicated softbody.
*/
virtual void addCollisionObjectForSoftBody( int clothIdentifier, btCollisionObject *collisionObject );
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 );
};
#endif // #ifndef BT_ACCELERATED_SOFT_BODY_CPU_SOLVER_H

View File

@@ -0,0 +1,76 @@
INCLUDE_DIRECTORIES(
${BULLET_PHYSICS_SOURCE_DIR}/src
)
SET(DXSDK_DIR $ENV{DXSDK_DIR})
SET(DX11_INCLUDE_PATH "${DIRECTX_SDK_BASE_DIR}/Include" CACHE DOCSTRING "Microsoft directX SDK include path")
INCLUDE_DIRECTORIES(
${DX11_INCLUDE_PATH} "../cpu/"
${VECTOR_MATH_INCLUDE}
)
SET(BulletSoftBodyDX11Solvers_SRCS
btSoftBodySolver_DX11.cpp
)
SET(BulletSoftBodyDX11Solvers_HDRS
btSoftBodySolver_DX11.h
../cpu/btSoftBodySolverData.h
btSoftBodySolverVertexData_DX11.h
btSoftBodySolverTriangleData_DX11.h
btSoftBodySolverLinkData_DX11.h
btSoftBodySolverBuffer_DX11.h
btSoftBodySolverVertexBuffer_DX11.h
)
# OpenCL and HLSL Shaders.
# Build rules generated to stringify these into headers
# which are needed by some of the sources
SET(BulletSoftBodyDX11Solvers_Shaders
OutputToVertexArray
UpdateNormals
Integrate
UpdatePositions
UpdateNodes
SolvePositions
UpdatePositionsFromVelocities
ApplyForces
PrepareLinks
VSolveLinks
)
foreach(f ${BulletSoftBodyDX11Solvers_Shaders})
LIST(APPEND BulletSoftBodyDX11Solvers_HLSL "HLSL/${f}.hlsl")
endforeach(f)
ADD_LIBRARY(BulletSoftBodySolvers_DX11 ${BulletSoftBodyDX11Solvers_SRCS} ${BulletSoftBodyDX11Solvers_HDRS} ${BulletSoftBodyDX11Solvers_HLSL})
SET_TARGET_PROPERTIES(BulletSoftBodySolvers_DX11 PROPERTIES VERSION ${BULLET_VERSION})
SET_TARGET_PROPERTIES(BulletSoftBodySolvers_DX11 PROPERTIES SOVERSION ${BULLET_VERSION})
IF (BUILD_SHARED_LIBS)
TARGET_LINK_LIBRARIES(BulletSoftBody BulletDynamics)
ENDIF (BUILD_SHARED_LIBS)
IF (INSTALL_LIBS)
IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES)
IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5)
IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK)
INSTALL(TARGETS BulletSoftBodySolvers_DX11 DESTINATION .)
ELSE (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK)
INSTALL(TARGETS BulletSoftBodySolvers_DX11 DESTINATION lib${LIB_SUFFIX})
INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DESTINATION include FILES_MATCHING PATTERN "*.h")
ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK)
ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5)
IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK)
SET_TARGET_PROPERTIES(BulletSoftBodySolvers_DX11 PROPERTIES FRAMEWORK true)
SET_TARGET_PROPERTIES(BulletSoftBodySolvers_DX11 PROPERTIES PUBLIC_HEADER "${BulletSoftBodyDX11Solvers_HDRS}")
ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK)
ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES)
ENDIF (INSTALL_LIBS)

View File

@@ -0,0 +1,95 @@
MSTRINGIFY(
cbuffer ApplyForcesCB : register( b0 )
{
unsigned int numNodes;
float solverdt;
float epsilon;
int padding3;
};
StructuredBuffer<int> g_vertexClothIdentifier : register( t0 );
StructuredBuffer<float4> g_vertexNormal : register( t1 );
StructuredBuffer<float> g_vertexArea : register( t2 );
StructuredBuffer<float> g_vertexInverseMass : register( t3 );
// TODO: These could be combined into a lift/drag factor array along with medium density
StructuredBuffer<float> g_clothLiftFactor : register( t4 );
StructuredBuffer<float> g_clothDragFactor : register( t5 );
StructuredBuffer<float4> g_clothWindVelocity : register( t6 );
StructuredBuffer<float4> g_clothAcceleration : register( t7 );
StructuredBuffer<float> g_clothMediumDensity : register( t8 );
RWStructuredBuffer<float4> g_vertexForceAccumulator : register( u0 );
RWStructuredBuffer<float4> g_vertexVelocity : register( u1 );
float3 projectOnAxis( float3 v, float3 a )
{
return (a*dot(v, a));
}
[numthreads(128, 1, 1)]
void
ApplyForcesKernel( uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint GI : SV_GroupIndex )
{
unsigned int nodeID = DTid.x;
if( nodeID < numNodes )
{
int clothId = g_vertexClothIdentifier[nodeID];
float nodeIM = g_vertexInverseMass[nodeID];
if( nodeIM > 0.0f )
{
float3 nodeV = g_vertexVelocity[nodeID].xyz;
float3 normal = g_vertexNormal[nodeID].xyz;
float area = g_vertexArea[nodeID];
float3 nodeF = g_vertexForceAccumulator[nodeID].xyz;
// Read per-cloth values
float3 clothAcceleration = g_clothAcceleration[clothId].xyz;
float3 clothWindVelocity = g_clothWindVelocity[clothId].xyz;
float liftFactor = g_clothLiftFactor[clothId];
float dragFactor = g_clothDragFactor[clothId];
float mediumDensity = g_clothMediumDensity[clothId];
// Apply the acceleration to the cloth rather than do this via a force
nodeV += (clothAcceleration*solverdt);
g_vertexVelocity[nodeID] = float4(nodeV, 0.f);
float3 relativeWindVelocity = nodeV - clothWindVelocity;
float relativeSpeedSquared = dot(relativeWindVelocity, relativeWindVelocity);
if( relativeSpeedSquared > epsilon )
{
// Correct direction of normal relative to wind direction and get dot product
normal = normal * (dot(normal, relativeWindVelocity) < 0 ? -1.f : 1.f);
float dvNormal = dot(normal, relativeWindVelocity);
if( dvNormal > 0 )
{
float3 force = float3(0.f, 0.f, 0.f);
float c0 = area * dvNormal * relativeSpeedSquared / 2.f;
float c1 = c0 * mediumDensity;
force += normal * (-c1 * liftFactor);
force += normalize(relativeWindVelocity)*(-c1 * dragFactor);
float dtim = solverdt * nodeIM;
float3 forceDTIM = force * dtim;
float3 nodeFPlusForce = nodeF + force;
// m_nodesf[i] -= ProjectOnAxis(m_nodesv[i], force.normalized())/dtim;
float3 nodeFMinus = nodeF - (projectOnAxis(nodeV, normalize(force))/dtim);
nodeF = nodeFPlusForce;
if( dot(forceDTIM, forceDTIM) > dot(nodeV, nodeV) )
nodeF = nodeFMinus;
g_vertexForceAccumulator[nodeID] = float4(nodeF, 0.0f);
}
}
}
}
}
);

View File

@@ -0,0 +1,41 @@
MSTRINGIFY(
cbuffer IntegrateCB : register( b0 )
{
int numNodes;
float solverdt;
int padding1;
int padding2;
};
// Node indices for each link
StructuredBuffer<float> g_vertexInverseMasses : register( t0 );
RWStructuredBuffer<float4> g_vertexPositions : register( u0 );
RWStructuredBuffer<float4> g_vertexVelocity : register( u1 );
RWStructuredBuffer<float4> g_vertexPreviousPositions : register( u2 );
RWStructuredBuffer<float4> g_vertexForceAccumulator : register( u3 );
[numthreads(128, 1, 1)]
void
IntegrateKernel( uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint GI : SV_GroupIndex )
{
int nodeID = DTid.x;
if( nodeID < numNodes )
{
float3 position = g_vertexPositions[nodeID].xyz;
float3 velocity = g_vertexVelocity[nodeID].xyz;
float3 force = g_vertexForceAccumulator[nodeID].xyz;
float inverseMass = g_vertexInverseMasses[nodeID];
g_vertexPreviousPositions[nodeID] = float4(position, 0.f);
velocity += force * inverseMass * solverdt;
position += velocity * solverdt;
g_vertexForceAccumulator[nodeID] = float4(0.f, 0.f, 0.f, 0.0f);
g_vertexPositions[nodeID] = float4(position, 0.f);
g_vertexVelocity[nodeID] = float4(velocity, 0.f);
}
}
);

View File

@@ -0,0 +1,63 @@
MSTRINGIFY(
cbuffer OutputToVertexArrayCB : register( b0 )
{
int startNode;
int numNodes;
int positionOffset;
int positionStride;
int normalOffset;
int normalStride;
int padding1;
int padding2;
};
StructuredBuffer<float4> g_vertexPositions : register( t0 );
StructuredBuffer<float4> g_vertexNormals : register( t1 );
RWBuffer<float> g_vertexBuffer : register( u0 );
[numthreads(128, 1, 1)]
void
OutputToVertexArrayWithNormalsKernel( uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint GI : SV_GroupIndex )
{
int nodeID = DTid.x;
if( nodeID < numNodes )
{
float4 position = g_vertexPositions[nodeID + startNode];
float4 normal = g_vertexNormals[nodeID + startNode];
// Stride should account for the float->float4 conversion
int positionDestination = nodeID * positionStride + positionOffset;
g_vertexBuffer[positionDestination] = position.x;
g_vertexBuffer[positionDestination+1] = position.y;
g_vertexBuffer[positionDestination+2] = position.z;
int normalDestination = nodeID * normalStride + normalOffset;
g_vertexBuffer[normalDestination] = normal.x;
g_vertexBuffer[normalDestination+1] = normal.y;
g_vertexBuffer[normalDestination+2] = normal.z;
}
}
[numthreads(128, 1, 1)]
void
OutputToVertexArrayWithoutNormalsKernel( uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint GI : SV_GroupIndex )
{
int nodeID = DTid.x;
if( nodeID < numNodes )
{
float4 position = g_vertexPositions[nodeID + startNode];
float4 normal = g_vertexNormals[nodeID + startNode];
// Stride should account for the float->float4 conversion
int positionDestination = nodeID * positionStride + positionOffset;
g_vertexBuffer[positionDestination] = position.x;
g_vertexBuffer[positionDestination+1] = position.y;
g_vertexBuffer[positionDestination+2] = position.z;
}
}
);

View File

@@ -0,0 +1,44 @@
MSTRINGIFY(
cbuffer PrepareLinksCB : register( b0 )
{
int numLinks;
int padding0;
int padding1;
int padding2;
};
// Node indices for each link
StructuredBuffer<int2> g_linksVertexIndices : register( t0 );
StructuredBuffer<float> g_linksMassLSC : register( t1 );
StructuredBuffer<float4> g_nodesPreviousPosition : register( t2 );
RWStructuredBuffer<float> g_linksLengthRatio : register( u0 );
RWStructuredBuffer<float4> g_linksCurrentLength : register( u1 );
[numthreads(128, 1, 1)]
void
PrepareLinksKernel( uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint GI : SV_GroupIndex )
{
int linkID = DTid.x;
if( linkID < numLinks )
{
int2 nodeIndices = g_linksVertexIndices[linkID];
int node0 = nodeIndices.x;
int node1 = nodeIndices.y;
float4 nodePreviousPosition0 = g_nodesPreviousPosition[node0];
float4 nodePreviousPosition1 = g_nodesPreviousPosition[node1];
float massLSC = g_linksMassLSC[linkID];
float4 linkCurrentLength = nodePreviousPosition1 - nodePreviousPosition0;
float linkLengthRatio = dot(linkCurrentLength, linkCurrentLength)*massLSC;
linkLengthRatio = 1./linkLengthRatio;
g_linksCurrentLength[linkID] = linkCurrentLength;
g_linksLengthRatio[linkID] = linkLengthRatio;
}
}
);

View File

@@ -0,0 +1,55 @@
MSTRINGIFY(
cbuffer SolvePositionsFromLinksKernelCB : register( b0 )
{
int startLink;
int numLinks;
float kst;
float ti;
};
// Node indices for each link
StructuredBuffer<int2> g_linksVertexIndices : register( t0 );
StructuredBuffer<float> g_linksMassLSC : register( t1 );
StructuredBuffer<float> g_linksRestLengthSquared : register( t2 );
StructuredBuffer<float> g_verticesInverseMass : register( t3 );
RWStructuredBuffer<float4> g_vertexPositions : register( u0 );
[numthreads(128, 1, 1)]
void
SolvePositionsFromLinksKernel( uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint GI : SV_GroupIndex )
{
int linkID = DTid.x + startLink;
if( DTid.x < numLinks )
{
float massLSC = g_linksMassLSC[linkID];
float restLengthSquared = g_linksRestLengthSquared[linkID];
if( massLSC > 0.0f )
{
int2 nodeIndices = g_linksVertexIndices[linkID];
int node0 = nodeIndices.x;
int node1 = nodeIndices.y;
float3 position0 = g_vertexPositions[node0].xyz;
float3 position1 = g_vertexPositions[node1].xyz;
float inverseMass0 = g_verticesInverseMass[node0];
float inverseMass1 = g_verticesInverseMass[node1];
float3 del = position1 - position0;
float len = dot(del, del);
float k = ((restLengthSquared - len)/(massLSC*(restLengthSquared+len)))*kst;
position0 = position0 - del*(k*inverseMass0);
position1 = position1 + del*(k*inverseMass1);
g_vertexPositions[node0] = float4(position0, 0.f);
g_vertexPositions[node1] = float4(position1, 0.f);
}
}
}
);

View File

@@ -0,0 +1,48 @@
MSTRINGIFY(
cbuffer UpdateConstantsCB : register( b0 )
{
int numLinks;
int padding0;
int padding1;
int padding2;
};
// Node indices for each link
StructuredBuffer<int2> g_linksVertexIndices : register( t0 );
StructuredBuffer<float4> g_vertexPositions : register( t1 );
StructuredBuffer<float> g_vertexInverseMasses : register( t2 );
StructuredBuffer<float> g_linksMaterialLSC : register( t3 );
RWStructuredBuffer<float> g_linksMassLSC : register( u0 );
RWStructuredBuffer<float> g_linksRestLengthSquared : register( u1 );
RWStructuredBuffer<float> g_linksRestLengths : register( u2 );
[numthreads(128, 1, 1)]
void
UpdateConstantsKernel( uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint GI : SV_GroupIndex )
{
int linkID = DTid.x;
if( linkID < numLinks )
{
int2 nodeIndices = g_linksVertexIndices[linkID];
int node0 = nodeIndices.x;
int node1 = nodeIndices.y;
float linearStiffnessCoefficient = g_linksMaterialLSC[ linkID ];
float3 position0 = g_vertexPositions[node0].xyz;
float3 position1 = g_vertexPositions[node1].xyz;
float inverseMass0 = g_vertexInverseMasses[node0];
float inverseMass1 = g_vertexInverseMasses[node1];
float3 difference = position0 - position1;
float length2 = dot(difference, difference);
float length = sqrt(length2);
g_linksRestLengths[linkID] = length;
g_linksMassLSC[linkID] = (inverseMass0 + inverseMass1)/linearStiffnessCoefficient;
g_linksRestLengthSquared[linkID] = length*length;
}
}
);

View File

@@ -0,0 +1,49 @@
MSTRINGIFY(
cbuffer UpdateVelocitiesFromPositionsWithVelocitiesCB : register( b0 )
{
int numNodes;
float isolverdt;
int padding1;
int padding2;
};
StructuredBuffer<float4> g_vertexPositions : register( t0 );
StructuredBuffer<float4> g_vertexPreviousPositions : register( t1 );
StructuredBuffer<int> g_vertexClothIndices : register( t2 );
StructuredBuffer<float> g_clothVelocityCorrectionCoefficients : register( t3 );
StructuredBuffer<float> g_clothDampingFactor : register( t4 );
RWStructuredBuffer<float4> g_vertexVelocities : register( u0 );
RWStructuredBuffer<float4> g_vertexForces : register( u1 );
[numthreads(128, 1, 1)]
void
updateVelocitiesFromPositionsWithVelocitiesKernel( uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint GI : SV_GroupIndex )
{
int nodeID = DTid.x;
if( nodeID < numNodes )
{
float3 position = g_vertexPositions[nodeID].xyz;
float3 previousPosition = g_vertexPreviousPositions[nodeID].xyz;
float3 velocity = g_vertexVelocities[nodeID].xyz;
int clothIndex = g_vertexClothIndices[nodeID];
float velocityCorrectionCoefficient = g_clothVelocityCorrectionCoefficients[clothIndex];
float dampingFactor = g_clothDampingFactor[clothIndex];
float velocityCoefficient = (1.f - dampingFactor);
float3 difference = position - previousPosition;
velocity += difference*velocityCorrectionCoefficient*isolverdt;
// Damp the velocity
velocity *= velocityCoefficient;
g_vertexVelocities[nodeID] = float4(velocity, 0.f);
g_vertexForces[nodeID] = float4(0.f, 0.f, 0.f, 0.f);
}
}
);

View File

@@ -0,0 +1,98 @@
MSTRINGIFY(
cbuffer UpdateSoftBodiesCB : register( b0 )
{
unsigned int numNodes;
unsigned int startFace;
unsigned int numFaces;
float epsilon;
};
// Node indices for each link
StructuredBuffer<int4> g_triangleVertexIndexSet : register( t0 );
StructuredBuffer<float4> g_vertexPositions : register( t1 );
StructuredBuffer<int> g_vertexTriangleCount : register( t2 );
RWStructuredBuffer<float4> g_vertexNormals : register( u0 );
RWStructuredBuffer<float> g_vertexArea : register( u1 );
RWStructuredBuffer<float4> g_triangleNormals : register( u2 );
RWStructuredBuffer<float> g_triangleArea : register( u3 );
[numthreads(128, 1, 1)]
void
ResetNormalsAndAreasKernel( uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint GI : SV_GroupIndex )
{
if( DTid.x < numNodes )
{
g_vertexNormals[DTid.x] = float4(0.0f, 0.0f, 0.0f, 0.0f);
g_vertexArea[DTid.x] = 0.0f;
}
}
[numthreads(128, 1, 1)]
void
UpdateSoftBodiesKernel( uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint GI : SV_GroupIndex )
{
int faceID = DTid.x + startFace;
if( DTid.x < numFaces )
{
int4 triangleIndexSet = g_triangleVertexIndexSet[ faceID ];
int nodeIndex0 = triangleIndexSet.x;
int nodeIndex1 = triangleIndexSet.y;
int nodeIndex2 = triangleIndexSet.z;
float3 node0 = g_vertexPositions[nodeIndex0].xyz;
float3 node1 = g_vertexPositions[nodeIndex1].xyz;
float3 node2 = g_vertexPositions[nodeIndex2].xyz;
float3 nodeNormal0 = g_vertexNormals[nodeIndex0].xyz;
float3 nodeNormal1 = g_vertexNormals[nodeIndex1].xyz;
float3 nodeNormal2 = g_vertexNormals[nodeIndex2].xyz;
float vertexArea0 = g_vertexArea[nodeIndex0];
float vertexArea1 = g_vertexArea[nodeIndex1];
float vertexArea2 = g_vertexArea[nodeIndex2];
float3 vector0 = node1 - node0;
float3 vector1 = node2 - node0;
float3 faceNormal = cross(vector0.xyz, vector1.xyz);
float triangleArea = length(faceNormal);
nodeNormal0 = nodeNormal0 + faceNormal;
nodeNormal1 = nodeNormal1 + faceNormal;
nodeNormal2 = nodeNormal2 + faceNormal;
vertexArea0 = vertexArea0 + triangleArea;
vertexArea1 = vertexArea1 + triangleArea;
vertexArea2 = vertexArea2 + triangleArea;
g_triangleNormals[faceID] = float4(normalize(faceNormal), 0.f);
g_vertexNormals[nodeIndex0] = float4(nodeNormal0, 0.f);
g_vertexNormals[nodeIndex1] = float4(nodeNormal1, 0.f);
g_vertexNormals[nodeIndex2] = float4(nodeNormal2, 0.f);
g_triangleArea[faceID] = triangleArea;
g_vertexArea[nodeIndex0] = vertexArea0;
g_vertexArea[nodeIndex1] = vertexArea1;
g_vertexArea[nodeIndex2] = vertexArea2;
}
}
[numthreads(128, 1, 1)]
void
NormalizeNormalsAndAreasKernel( uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint GI : SV_GroupIndex )
{
if( DTid.x < numNodes )
{
float4 normal = g_vertexNormals[DTid.x];
float area = g_vertexArea[DTid.x];
int numTriangles = g_vertexTriangleCount[DTid.x];
float vectorLength = length(normal);
g_vertexNormals[DTid.x] = normalize(normal);
g_vertexArea[DTid.x] = area/float(numTriangles);
}
}
);

View File

@@ -0,0 +1,44 @@
MSTRINGIFY(
cbuffer UpdateVelocitiesFromPositionsWithoutVelocitiesCB : register( b0 )
{
int numNodes;
float isolverdt;
int padding1;
int padding2;
};
StructuredBuffer<float4> g_vertexPositions : register( t0 );
StructuredBuffer<float4> g_vertexPreviousPositions : register( t1 );
StructuredBuffer<int> g_vertexClothIndices : register( t2 );
StructuredBuffer<float> g_clothDampingFactor : register( t3 );
RWStructuredBuffer<float4> g_vertexVelocities : register( u0 );
RWStructuredBuffer<float4> g_vertexForces : register( u1 );
[numthreads(128, 1, 1)]
void
updateVelocitiesFromPositionsWithoutVelocitiesKernel( uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint GI : SV_GroupIndex )
{
int nodeID = DTid.x;
if( nodeID < numNodes )
{
float3 position = g_vertexPositions[nodeID].xyz;
float3 previousPosition = g_vertexPreviousPositions[nodeID].xyz;
float3 velocity = g_vertexVelocities[nodeID].xyz;
int clothIndex = g_vertexClothIndices[nodeID];
float dampingFactor = g_clothDampingFactor[clothIndex];
float velocityCoefficient = (1.f - dampingFactor);
float3 difference = position - previousPosition;
velocity = difference*velocityCoefficient*isolverdt;
g_vertexVelocities[nodeID] = float4(velocity, 0.f);
g_vertexForces[nodeID] = float4(0.f, 0.f, 0.f, 0.f);
}
}
);

View File

@@ -0,0 +1,35 @@
MSTRINGIFY(
cbuffer UpdatePositionsFromVelocitiesCB : register( b0 )
{
int numNodes;
float solverSDT;
int padding1;
int padding2;
};
StructuredBuffer<float4> g_vertexVelocities : register( t0 );
RWStructuredBuffer<float4> g_vertexPreviousPositions : register( u0 );
RWStructuredBuffer<float4> g_vertexCurrentPosition : register( u1 );
[numthreads(128, 1, 1)]
void
UpdatePositionsFromVelocitiesKernel( uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint GI : SV_GroupIndex )
{
int vertexID = DTid.x;
if( vertexID < numNodes )
{
float3 previousPosition = g_vertexPreviousPositions[vertexID].xyz;
float3 velocity = g_vertexVelocities[vertexID].xyz;
float3 newPosition = previousPosition + velocity*solverSDT;
g_vertexCurrentPosition[vertexID] = float4(newPosition, 0.f);
g_vertexPreviousPositions[vertexID] = float4(newPosition, 0.f);
}
}
);

View File

@@ -0,0 +1,55 @@
MSTRINGIFY(
cbuffer VSolveLinksCB : register( b0 )
{
int startLink;
int numLinks;
float kst;
int padding;
};
// Node indices for each link
StructuredBuffer<int2> g_linksVertexIndices : register( t0 );
StructuredBuffer<float> g_linksLengthRatio : register( t1 );
StructuredBuffer<float4> g_linksCurrentLength : register( t2 );
StructuredBuffer<float> g_vertexInverseMass : register( t3 );
RWStructuredBuffer<float4> g_vertexVelocity : register( u0 );
[numthreads(128, 1, 1)]
void
VSolveLinksKernel( uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint GI : SV_GroupIndex )
{
int linkID = DTid.x + startLink;
if( DTid.x < numLinks )
{
int2 nodeIndices = g_linksVertexIndices[linkID];
int node0 = nodeIndices.x;
int node1 = nodeIndices.y;
float linkLengthRatio = g_linksLengthRatio[linkID];
float3 linkCurrentLength = g_linksCurrentLength[linkID].xyz;
float3 vertexVelocity0 = g_vertexVelocity[node0].xyz;
float3 vertexVelocity1 = g_vertexVelocity[node1].xyz;
float vertexInverseMass0 = g_vertexInverseMass[node0];
float vertexInverseMass1 = g_vertexInverseMass[node1];
float3 nodeDifference = vertexVelocity0 - vertexVelocity1;
float dotResult = dot(linkCurrentLength, nodeDifference);
float j = -dotResult*linkLengthRatio*kst;
float3 velocityChange0 = linkCurrentLength*(j*vertexInverseMass0);
float3 velocityChange1 = linkCurrentLength*(j*vertexInverseMass1);
vertexVelocity0 += velocityChange0;
vertexVelocity1 -= velocityChange1;
g_vertexVelocity[node0] = float4(vertexVelocity0, 0.f);
g_vertexVelocity[node1] = float4(vertexVelocity1, 0.f);
}
}
);

View File

@@ -0,0 +1,309 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_SOFT_BODY_SOLVER_BUFFER_DX11_H
#define BT_SOFT_BODY_SOLVER_BUFFER_DX11_H
// DX11 support
#include <windows.h>
#include <crtdbg.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dcompiler.h>
#ifndef SAFE_RELEASE
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
#endif
/**
* DX11 Buffer that tracks a host buffer on use to ensure size-correctness.
*/
template <typename ElementType> class btDX11Buffer
{
protected:
ID3D11Device* m_d3dDevice;
ID3D11DeviceContext* m_d3dDeviceContext;
ID3D11Buffer* m_Buffer;
ID3D11ShaderResourceView* m_SRV;
ID3D11UnorderedAccessView* m_UAV;
btAlignedObjectArray< ElementType >* m_CPUBuffer;
// TODO: Separate this from the main class
// as read back buffers can be shared between buffers
ID3D11Buffer* m_readBackBuffer;
int m_gpuSize;
bool m_onGPU;
bool m_readOnlyOnGPU;
bool createBuffer( ID3D11Buffer *preexistingBuffer = 0)
{
HRESULT hr = S_OK;
// Create all CS buffers
if( preexistingBuffer )
{
m_Buffer = preexistingBuffer;
} else {
D3D11_BUFFER_DESC buffer_desc;
ZeroMemory(&buffer_desc, sizeof(buffer_desc));
buffer_desc.Usage = D3D11_USAGE_DEFAULT;
if( m_readOnlyOnGPU )
buffer_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
else
buffer_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
buffer_desc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
buffer_desc.ByteWidth = m_CPUBuffer->size() * sizeof(ElementType);
buffer_desc.StructureByteStride = sizeof(ElementType);
hr = m_d3dDevice->CreateBuffer(&buffer_desc, NULL, &m_Buffer);
if( FAILED( hr ) )
return (hr==S_OK);
}
if( m_readOnlyOnGPU )
{
D3D11_SHADER_RESOURCE_VIEW_DESC srvbuffer_desc;
ZeroMemory(&srvbuffer_desc, sizeof(srvbuffer_desc));
srvbuffer_desc.Format = DXGI_FORMAT_UNKNOWN;
srvbuffer_desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
srvbuffer_desc.Buffer.ElementWidth = m_CPUBuffer->size();
hr = m_d3dDevice->CreateShaderResourceView(m_Buffer, &srvbuffer_desc, &m_SRV);
if( FAILED( hr ) )
return (hr==S_OK);
} else {
// Create SRV
D3D11_SHADER_RESOURCE_VIEW_DESC srvbuffer_desc;
ZeroMemory(&srvbuffer_desc, sizeof(srvbuffer_desc));
srvbuffer_desc.Format = DXGI_FORMAT_UNKNOWN;
srvbuffer_desc.ViewDimension = D3D11_SRV_DIMENSION_BUFFER;
srvbuffer_desc.Buffer.ElementWidth = m_CPUBuffer->size();
hr = m_d3dDevice->CreateShaderResourceView(m_Buffer, &srvbuffer_desc, &m_SRV);
if( FAILED( hr ) )
return (hr==S_OK);
// Create UAV
D3D11_UNORDERED_ACCESS_VIEW_DESC uavbuffer_desc;
ZeroMemory(&uavbuffer_desc, sizeof(uavbuffer_desc));
uavbuffer_desc.Format = DXGI_FORMAT_UNKNOWN;
uavbuffer_desc.ViewDimension = D3D11_UAV_DIMENSION_BUFFER;
uavbuffer_desc.Buffer.NumElements = m_CPUBuffer->size();
hr = m_d3dDevice->CreateUnorderedAccessView(m_Buffer, &uavbuffer_desc, &m_UAV);
if( FAILED( hr ) )
return (hr==S_OK);
// Create read back buffer
D3D11_BUFFER_DESC readback_buffer_desc;
ZeroMemory(&readback_buffer_desc, sizeof(readback_buffer_desc));
readback_buffer_desc.ByteWidth = m_CPUBuffer->size() * sizeof(ElementType);
readback_buffer_desc.Usage = D3D11_USAGE_STAGING;
readback_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
readback_buffer_desc.StructureByteStride = sizeof(ElementType);
hr = m_d3dDevice->CreateBuffer(&readback_buffer_desc, NULL, &m_readBackBuffer);
if( FAILED( hr ) )
return (hr==S_OK);
}
m_gpuSize = m_CPUBuffer->size();
return true;
}
public:
btDX11Buffer( ID3D11Device *d3dDevice, ID3D11DeviceContext *d3dDeviceContext, btAlignedObjectArray< ElementType > *CPUBuffer, bool readOnly )
{
m_d3dDevice = d3dDevice;
m_d3dDeviceContext = d3dDeviceContext;
m_Buffer = 0;
m_SRV = 0;
m_UAV = 0;
m_readBackBuffer = 0;
m_CPUBuffer = CPUBuffer;
m_gpuSize = 0;
m_onGPU = false;
m_readOnlyOnGPU = readOnly;
}
virtual ~btDX11Buffer()
{
SAFE_RELEASE(m_Buffer);
SAFE_RELEASE(m_SRV);
SAFE_RELEASE(m_UAV);
SAFE_RELEASE(m_readBackBuffer);
}
ID3D11ShaderResourceView* &getSRV()
{
return m_SRV;
}
ID3D11UnorderedAccessView* &getUAV()
{
return m_UAV;
}
ID3D11Buffer* &getBuffer()
{
return m_Buffer;
}
/**
* Move the data to the GPU if it is not there already.
*/
bool moveToGPU()
{
if( (m_CPUBuffer->size() != m_gpuSize) )
m_onGPU = false;
if( !m_onGPU && m_CPUBuffer->size() > 0 )
{
// If the buffer doesn't exist or the CPU-side buffer has changed size, create
// We should really delete the old one, too, but let's leave that for later
if( !m_Buffer || (m_CPUBuffer->size() != m_gpuSize) )
{
SAFE_RELEASE(m_Buffer);
SAFE_RELEASE(m_SRV);
SAFE_RELEASE(m_UAV);
SAFE_RELEASE(m_readBackBuffer);
if( !createBuffer() )
{
btAssert("Buffer creation failed.");
return false;
}
}
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;
}
return true;
}
/**
* Move the data back from the GPU if it is on there and isn't read only.
*/
bool moveFromGPU()
{
if( m_CPUBuffer->size() > 0 )
{
if( m_onGPU && !m_readOnlyOnGPU )
{
// Copy back
D3D11_MAPPED_SUBRESOURCE MappedResource = {0};
//m_pd3dImmediateContext->CopyResource(m_phAngVelReadBackBuffer, m_phAngVel);
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->CopySubresourceRegion(
m_readBackBuffer,
0,
0,
0,
0 ,
m_Buffer,
0,
&destRegion
);
m_d3dDeviceContext->Map(m_readBackBuffer, 0, D3D11_MAP_READ, 0, &MappedResource);
//memcpy(m_hAngVel, MappedResource.pData, (m_maxObjs * sizeof(float) ));
memcpy(&((*m_CPUBuffer)[0]), MappedResource.pData, ((m_CPUBuffer->size()) * sizeof(ElementType) ));
m_d3dDeviceContext->Unmap(m_readBackBuffer, 0);
m_onGPU = false;
}
}
return true;
}
/**
* Copy the data back from the GPU without changing its state to be CPU-side.
* Useful if we just want to view it on the host for visualization.
*/
bool copyFromGPU()
{
if( m_CPUBuffer->size() > 0 )
{
if( m_onGPU && !m_readOnlyOnGPU )
{
// Copy back
D3D11_MAPPED_SUBRESOURCE MappedResource = {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->CopySubresourceRegion(
m_readBackBuffer,
0,
0,
0,
0 ,
m_Buffer,
0,
&destRegion
);
m_d3dDeviceContext->Map(m_readBackBuffer, 0, D3D11_MAP_READ, 0, &MappedResource);
//memcpy(m_hAngVel, MappedResource.pData, (m_maxObjs * sizeof(float) ));
memcpy(&((*m_CPUBuffer)[0]), MappedResource.pData, ((m_CPUBuffer->size()) * sizeof(ElementType) ));
m_d3dDeviceContext->Unmap(m_readBackBuffer, 0);
}
}
return true;
}
/**
* Call if data has changed on the CPU.
* Can then trigger a move to the GPU as necessary.
*/
virtual void changedOnCPU()
{
m_onGPU = false;
}
}; // class btDX11Buffer
#endif // #ifndef BT_SOFT_BODY_SOLVER_BUFFER_DX11_H

View File

@@ -0,0 +1,103 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "BulletMultiThreaded/GpuSoftBodySolvers/CPU/btSoftBodySolverData.h"
#include "btSoftBodySolverBuffer_DX11.h"
#ifndef BT_SOFT_BODY_SOLVER_LINK_DATA_DX11_H
#define BT_SOFT_BODY_SOLVER_LINK_DATA_DX11_H
struct ID3D11Device;
struct ID3D11DeviceContext;
class btSoftBodyLinkDataDX11 : public btSoftBodyLinkData
{
public:
bool m_onGPU;
ID3D11Device *m_d3dDevice;
ID3D11DeviceContext *m_d3dDeviceContext;
btDX11Buffer<LinkNodePair> m_dx11Links;
btDX11Buffer<float> m_dx11LinkStrength;
btDX11Buffer<float> m_dx11LinksMassLSC;
btDX11Buffer<float> m_dx11LinksRestLengthSquared;
btDX11Buffer<Vectormath::Aos::Vector3> m_dx11LinksCLength;
btDX11Buffer<float> m_dx11LinksLengthRatio;
btDX11Buffer<float> m_dx11LinksRestLength;
btDX11Buffer<float> m_dx11LinksMaterialLinearStiffnessCoefficient;
struct BatchPair
{
int start;
int length;
BatchPair() :
start(0),
length(0)
{
}
BatchPair( int s, int l ) :
start( s ),
length( l )
{
}
};
/**
* Link addressing information for each cloth.
* Allows link locations to be computed independently of data batching.
*/
btAlignedObjectArray< int > m_linkAddresses;
/**
* Start and length values for computation batches over link data.
*/
btAlignedObjectArray< BatchPair > m_batchStartLengths;
//ID3D11Buffer* readBackBuffer;
btSoftBodyLinkDataDX11( ID3D11Device *d3dDevice, ID3D11DeviceContext *d3dDeviceContext );
virtual ~btSoftBodyLinkDataDX11();
/** Allocate enough space in all link-related arrays to fit numLinks links */
virtual void createLinks( int numLinks );
/** Insert the link described into the correct data structures assuming space has already been allocated by a call to createLinks */
virtual void setLinkAt( const LinkDescription &link, int linkIndex );
virtual bool onAccelerator();
virtual bool moveToAccelerator();
virtual bool moveFromAccelerator();
/**
* Generate (and later update) the batching for the entire link set.
* This redoes a lot of work because it batches the entire set when each cloth is inserted.
* In theory we could delay it until just before we need the cloth.
* It's a one-off overhead, though, so that is a later optimisation.
*/
void generateBatches();
};
#endif // #ifndef BT_SOFT_BODY_SOLVER_LINK_DATA_DX11_H

View File

@@ -0,0 +1,96 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "BulletMultiThreaded/GpuSoftBodySolvers/CPU/btSoftBodySolverData.h"
#include "btSoftBodySolverBuffer_DX11.h"
#ifndef BT_SOFT_BODY_SOLVER_TRIANGLE_DATA_DX11_H
#define BT_SOFT_BODY_SOLVER_TRIANGLE_DATA_DX11_H
struct ID3D11Device;
struct ID3D11DeviceContext;
class btSoftBodyTriangleDataDX11 : public btSoftBodyTriangleData
{
public:
bool m_onGPU;
ID3D11Device *m_d3dDevice;
ID3D11DeviceContext *m_d3dDeviceContext;
btDX11Buffer<btSoftBodyTriangleData::TriangleNodeSet> m_dx11VertexIndices;
btDX11Buffer<float> m_dx11Area;
btDX11Buffer<Vectormath::Aos::Vector3> m_dx11Normal;
struct BatchPair
{
int start;
int length;
BatchPair() :
start(0),
length(0)
{
}
BatchPair( int s, int l ) :
start( s ),
length( l )
{
}
};
/**
* Link addressing information for each cloth.
* Allows link locations to be computed independently of data batching.
*/
btAlignedObjectArray< int > m_triangleAddresses;
/**
* Start and length values for computation batches over link data.
*/
btAlignedObjectArray< BatchPair > m_batchStartLengths;
//ID3D11Buffer* readBackBuffer;
public:
btSoftBodyTriangleDataDX11( ID3D11Device *d3dDevice, ID3D11DeviceContext *d3dDeviceContext );
virtual ~btSoftBodyTriangleDataDX11();
/** Allocate enough space in all link-related arrays to fit numLinks links */
virtual void createTriangles( int numTriangles );
/** Insert the link described into the correct data structures assuming space has already been allocated by a call to createLinks */
virtual void setTriangleAt( const btSoftBodyTriangleData::TriangleDescription &triangle, int triangleIndex );
virtual bool onAccelerator();
virtual bool moveToAccelerator();
virtual bool moveFromAccelerator();
/**
* Generate (and later update) the batching for the entire triangle set.
* This redoes a lot of work because it batches the entire set when each cloth is inserted.
* In theory we could delay it until just before we need the cloth.
* It's a one-off overhead, though, so that is a later optimisation.
*/
void generateBatches();
};
#endif // #ifndef BT_SOFT_BODY_SOLVER_TRIANGLE_DATA_DX11_H

View File

@@ -0,0 +1,107 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_SOFT_BODY_SOLVER_VERTEX_BUFFER_DX11_H
#define BT_SOFT_BODY_SOLVER_VERTEX_BUFFER_DX11_H
#include "BulletSoftBody/btSoftBodySolverVertexBuffer.h"
#include <windows.h>
#include <crtdbg.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dcompiler.h>
class btDX11VertexBufferDescriptor : public btVertexBufferDescriptor
{
protected:
/** Context of the DX11 device on which the vertex buffer is stored. */
ID3D11DeviceContext* m_context;
/** DX11 vertex buffer */
ID3D11Buffer* m_vertexBuffer;
/** UAV for DX11 buffer */
ID3D11UnorderedAccessView* m_vertexBufferUAV;
public:
/**
* buffer is a pointer to the DX11 buffer to place the vertex data in.
* UAV is a pointer to the UAV representation of the buffer laid out in floats.
* vertexOffset is the offset in floats to the first vertex.
* vertexStride is the stride in floats between vertices.
*/
btDX11VertexBufferDescriptor( ID3D11DeviceContext* context, ID3D11Buffer* buffer, ID3D11UnorderedAccessView *UAV, int vertexOffset, int vertexStride )
{
m_context = context;
m_vertexBuffer = buffer;
m_vertexBufferUAV = UAV;
m_vertexOffset = vertexOffset;
m_vertexStride = vertexStride;
m_hasVertexPositions = true;
}
/**
* buffer is a pointer to the DX11 buffer to place the vertex data in.
* UAV is a pointer to the UAV representation of the buffer laid out in floats.
* vertexOffset is the offset in floats to the first vertex.
* vertexStride is the stride in floats between vertices.
* normalOffset is the offset in floats to the first normal.
* normalStride is the stride in floats between normals.
*/
btDX11VertexBufferDescriptor( ID3D11DeviceContext* context, ID3D11Buffer* buffer, ID3D11UnorderedAccessView *UAV, int vertexOffset, int vertexStride, int normalOffset, int normalStride )
{
m_context = context;
m_vertexBuffer = buffer;
m_vertexBufferUAV = UAV;
m_vertexOffset = vertexOffset;
m_vertexStride = vertexStride;
m_hasVertexPositions = true;
m_normalOffset = normalOffset;
m_normalStride = normalStride;
m_hasNormals = true;
}
virtual ~btDX11VertexBufferDescriptor()
{
}
/**
* Return the type of the vertex buffer descriptor.
*/
virtual BufferTypes getBufferType() const
{
return DX11_BUFFER;
}
virtual ID3D11DeviceContext* getContext() const
{
return m_context;
}
virtual ID3D11Buffer* getbtDX11Buffer() const
{
return m_vertexBuffer;
}
virtual ID3D11UnorderedAccessView* getDX11UAV() const
{
return m_vertexBufferUAV;
}
};
#endif // #ifndef BT_SOFT_BODY_SOLVER_VERTEX_BUFFER_DX11_H

View File

@@ -0,0 +1,63 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "BulletMultiThreaded/GpuSoftBodySolvers/CPU/btSoftBodySolverData.h"
#include "btSoftBodySolverBuffer_DX11.h"
#ifndef BT_SOFT_BHODY_SOLVER_VERTEX_DATA_DX11_H
#define BT_SOFT_BHODY_SOLVER_VERTEX_DATA_DX11_H
class btSoftBodyLinkData;
class btSoftBodyLinkData::LinkDescription;
struct ID3D11Device;
struct ID3D11DeviceContext;
class btSoftBodyVertexDataDX11 : public btSoftBodyVertexData
{
protected:
bool m_onGPU;
ID3D11Device *m_d3dDevice;
ID3D11DeviceContext *m_d3dDeviceContext;
public:
btDX11Buffer<int> m_dx11ClothIdentifier;
btDX11Buffer<Vectormath::Aos::Point3> m_dx11VertexPosition;
btDX11Buffer<Vectormath::Aos::Point3> m_dx11VertexPreviousPosition;
btDX11Buffer<Vectormath::Aos::Vector3> m_dx11VertexVelocity;
btDX11Buffer<Vectormath::Aos::Vector3> m_dx11VertexForceAccumulator;
btDX11Buffer<Vectormath::Aos::Vector3> m_dx11VertexNormal;
btDX11Buffer<float> m_dx11VertexInverseMass;
btDX11Buffer<float> m_dx11VertexArea;
btDX11Buffer<int> m_dx11VertexTriangleCount;
//ID3D11Buffer* readBackBuffer;
public:
btSoftBodyVertexDataDX11( ID3D11Device *d3dDevice, ID3D11DeviceContext *d3dDeviceContext );
virtual ~btSoftBodyVertexDataDX11();
virtual bool onAccelerator();
virtual bool moveToAccelerator();
virtual bool moveFromAccelerator();
};
#endif // #ifndef BT_SOFT_BHODY_SOLVER_VERTEX_DATA_DX11_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,480 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "vectormath_aos.h"
#include "BulletSoftBody/btSoftBodySolvers.h"
#include "btSoftBodySolverVertexBuffer_DX11.h"
#include "btSoftBodySolverLinkData_DX11.h"
#include "btSoftBodySolverVertexData_DX11.h"
#include "btSoftBodySolverTriangleData_DX11.h"
#ifndef BT_ACCELERATED_SOFT_BODY_DX11_SOLVER_H
#define BT_ACCELERATED_SOFT_BODY_DX11_SOLVER_H
class btDX11SoftBodySolver : public btSoftBodySolver
{
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;
}
// 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;
}
#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 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
}
};
struct PrepareLinksCB
{
int numLinks;
int padding0;
int padding1;
int padding2;
};
struct SolvePositionsFromLinksKernelCB
{
int startLink;
int numLinks;
float kst;
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;
};
struct VSolveLinksCB
{
int startLink;
int numLinks;
float kst;
int padding;
};
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. */
btSoftBodyLinkDataDX11 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;
/** 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 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;
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 );
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 );
// End kernel dispatches
/////////////////////////////////////
public:
btDX11SoftBodySolver(ID3D11Device * dx11Device, ID3D11DeviceContext* dx11Context);
virtual ~btDX11SoftBodySolver();
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 );
};
#endif // #ifndef BT_ACCELERATED_SOFT_BODY_DX11_SOLVER_H

View File

@@ -0,0 +1,71 @@
INCLUDE_DIRECTORIES(
${BULLET_PHYSICS_SOURCE_DIR}/src
)
SET(OPENCL_DIR $ENV{ATISTREAMSDKROOT})
SET(OPENCL_INCLUDE_PATH "${ATISTREAMSDKROOT}/include" CACHE DOCSTRING "OpenCL SDK include path")
INCLUDE_DIRECTORIES(${OPENCL_INCLUDE_PATH} "../cpu/")
SET(BulletSoftBodyOpenCLSolvers_SRCS
btSoftBodySolver_OpenCL.cpp
)
SET(BulletSoftBodyOpenCLSolvers_HDRS
btSoftBodySolver_OpenCL.h
../cpu/btSoftBodySolverData.h
btSoftBodySolverVertexData_OpenCL.h
btSoftBodySolverTriangleData_OpenCL.h
btSoftBodySolverLinkData_OpenCL.h
btSoftBodySolverBuffer_OpenCL.h
)
# OpenCL and HLSL Shaders.
# Build rules generated to stringify these into headers
# which are needed by some of the sources
SET(BulletSoftBodyOpenCLSolvers_Shaders
# OutputToVertexArray
UpdateNormals
Integrate
UpdatePositions
UpdateNodes
SolvePositions
UpdatePositionsFromVelocities
ApplyForces
PrepareLinks
VSolveLinks
)
foreach(f ${BulletSoftBodyOpenCLSolvers_Shaders})
LIST(APPEND BulletSoftBodyOpenCLSolvers_OpenCLC "OpenCLC/${f}.cl")
endforeach(f)
ADD_LIBRARY(BulletSoftBodySolvers_OpenCL ${BulletSoftBodyOpenCLSolvers_SRCS} ${BulletSoftBodyOpenCLSolvers_HDRS} ${BulletSoftBodyOpenCLSolvers_OpenCLC})
SET_TARGET_PROPERTIES(BulletSoftBodySolvers_OpenCL PROPERTIES VERSION ${BULLET_VERSION})
SET_TARGET_PROPERTIES(BulletSoftBodySolvers_OpenCL PROPERTIES SOVERSION ${BULLET_VERSION})
IF (BUILD_SHARED_LIBS)
TARGET_LINK_LIBRARIES(BulletSoftBody BulletDynamics)
ENDIF (BUILD_SHARED_LIBS)
IF (INSTALL_LIBS)
IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES)
IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5)
IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK)
INSTALL(TARGETS BulletSoftBodySolvers_OpenCL DESTINATION .)
ELSE (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK)
INSTALL(TARGETS BulletSoftBodySolvers_OpenCL DESTINATION lib${LIB_SUFFIX})
INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DESTINATION include FILES_MATCHING PATTERN "*.h")
ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK)
ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5)
IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK)
SET_TARGET_PROPERTIES(BulletSoftBodySolvers_OpenCL PROPERTIES FRAMEWORK true)
SET_TARGET_PROPERTIES(BulletSoftBodySolvers_OpenCL PROPERTIES PUBLIC_HEADER "${BulletSoftBodyOpenCLSolvers_HDRS}")
ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK)
ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES)
ENDIF (INSTALL_LIBS)

View File

@@ -0,0 +1,91 @@
MSTRINGIFY(
/*#define float3 float4
float dot3(float3 a, float3 b)
{
return a.x*b.x + a.y*b.y + a.z*b.z;
}*/
float3 projectOnAxis( float3 v, float3 a )
{
return (a*dot(v, a));
}
__kernel void
ApplyForcesKernel(
const uint numNodes,
const float solverdt,
const float epsilon,
__global int * g_vertexClothIdentifier,
__global float4 * g_vertexNormal,
__global float * g_vertexArea,
__global float * g_vertexInverseMass,
__global float * g_clothLiftFactor,
__global float * g_clothDragFactor,
__global float4 * g_clothWindVelocity,
__global float4 * g_clothAcceleration,
__global float * g_clothMediumDensity,
__global float4 * g_vertexForceAccumulator,
__global float4 * g_vertexVelocity)
{
unsigned int nodeID = get_global_id(0);
if( nodeID < numNodes )
{
int clothId = g_vertexClothIdentifier[nodeID];
float nodeIM = g_vertexInverseMass[nodeID];
if( nodeIM > 0.0f )
{
float3 nodeV = g_vertexVelocity[nodeID].xyz;
float3 normal = g_vertexNormal[nodeID].xyz;
float area = g_vertexArea[nodeID];
float3 nodeF = g_vertexForceAccumulator[nodeID].xyz;
// Read per-cloth values
float3 clothAcceleration = g_clothAcceleration[clothId].xyz;
float3 clothWindVelocity = g_clothWindVelocity[clothId].xyz;
float liftFactor = g_clothLiftFactor[clothId];
float dragFactor = g_clothDragFactor[clothId];
float mediumDensity = g_clothMediumDensity[clothId];
// Apply the acceleration to the cloth rather than do this via a force
nodeV += (clothAcceleration*solverdt);
g_vertexVelocity[nodeID] = (float4)(nodeV, 0.f);
float3 relativeWindVelocity = nodeV - clothWindVelocity;
float relativeSpeedSquared = dot(relativeWindVelocity, relativeWindVelocity);
if( relativeSpeedSquared > epsilon )
{
// Correct direction of normal relative to wind direction and get dot product
normal = normal * (dot(normal, relativeWindVelocity) < 0 ? -1.f : 1.f);
float dvNormal = dot(normal, relativeWindVelocity);
if( dvNormal > 0 )
{
float3 force = (float3)(0.f, 0.f, 0.f);
float c0 = area * dvNormal * relativeSpeedSquared / 2.f;
float c1 = c0 * mediumDensity;
force += normal * (-c1 * liftFactor);
force += normalize(relativeWindVelocity)*(-c1 * dragFactor);
float dtim = solverdt * nodeIM;
float3 forceDTIM = force * dtim;
float3 nodeFPlusForce = nodeF + force;
// m_nodesf[i] -= ProjectOnAxis(m_nodesv[i], force.normalized())/dtim;
float3 nodeFMinus = nodeF - (projectOnAxis(nodeV, normalize(force))/dtim);
nodeF = nodeFPlusForce;
if( dot(forceDTIM, forceDTIM) > dot(nodeV, nodeV) )
nodeF = nodeFMinus;
g_vertexForceAccumulator[nodeID] = (float4)(nodeF, 0.0f);
}
}
}
}
}
);

View File

@@ -0,0 +1,35 @@
MSTRINGIFY(
// Node indices for each link
//#define float3 float4
__kernel void
IntegrateKernel(
const int numNodes,
const float solverdt,
__global float * g_vertexInverseMasses,
__global float4 * g_vertexPositions,
__global float4 * g_vertexVelocity,
__global float4 * g_vertexPreviousPositions,
__global float4 * g_vertexForceAccumulator)
{
int nodeID = get_global_id(0);
if( nodeID < numNodes )
{
float3 position = g_vertexPositions[nodeID].xyz;
float3 velocity = g_vertexVelocity[nodeID].xyz;
float3 force = g_vertexForceAccumulator[nodeID].xyz;
float inverseMass = g_vertexInverseMasses[nodeID];
g_vertexPreviousPositions[nodeID] = (float4)(position, 0.f);
velocity += force * inverseMass * solverdt;
position += velocity * solverdt;
g_vertexForceAccumulator[nodeID] = (float4)(0.f, 0.f, 0.f, 0.0f);
g_vertexPositions[nodeID] = (float4)(position, 0.f);
g_vertexVelocity[nodeID] = (float4)(velocity, 0.f);
}
}
);

View File

@@ -0,0 +1,34 @@
MSTRINGIFY(
__kernel void
PrepareLinksKernel(
const int numLinks,
__global int2 * g_linksVertexIndices,
__global float * g_linksMassLSC,
__global float4 * g_nodesPreviousPosition,
__global float * g_linksLengthRatio,
__global float4 * g_linksCurrentLength)
{
int linkID = get_global_id(0);
if( linkID < numLinks )
{
int2 nodeIndices = g_linksVertexIndices[linkID];
int node0 = nodeIndices.x;
int node1 = nodeIndices.y;
float4 nodePreviousPosition0 = g_nodesPreviousPosition[node0];
float4 nodePreviousPosition1 = g_nodesPreviousPosition[node1];
float massLSC = g_linksMassLSC[linkID];
float4 linkCurrentLength = nodePreviousPosition1 - nodePreviousPosition0;
float linkLengthRatio = dot(linkCurrentLength, linkCurrentLength)*massLSC;
linkLengthRatio = 1.0f/linkLengthRatio;
g_linksCurrentLength[linkID] = linkCurrentLength;
g_linksLengthRatio[linkID] = linkLengthRatio;
}
}
);

View File

@@ -0,0 +1,55 @@
MSTRINGIFY(
/*#define float3 float4
float dot3(float3 a, float3 b)
{
return a.x*b.x + a.y*b.y + a.z*b.z;
}*/
__kernel void
SolvePositionsFromLinksKernel(
const int startLink,
const int numLinks,
const float kst,
const float ti,
__global int2 * g_linksVertexIndices,
__global float * g_linksMassLSC,
__global float * g_linksRestLengthSquared,
__global float * g_verticesInverseMass,
__global float4 * g_vertexPositions)
{
int linkID = get_global_id(0) + startLink;
if( get_global_id(0) < numLinks )
{
float massLSC = g_linksMassLSC[linkID];
float restLengthSquared = g_linksRestLengthSquared[linkID];
if( massLSC > 0.0f )
{
int2 nodeIndices = g_linksVertexIndices[linkID];
int node0 = nodeIndices.x;
int node1 = nodeIndices.y;
float3 position0 = g_vertexPositions[node0].xyz;
float3 position1 = g_vertexPositions[node1].xyz;
float inverseMass0 = g_verticesInverseMass[node0];
float inverseMass1 = g_verticesInverseMass[node1];
float3 del = position1 - position0;
float len = dot(del, del);
float k = ((restLengthSquared - len)/(massLSC*(restLengthSquared+len)))*kst;
position0 = position0 - del*(k*inverseMass0);
position1 = position1 + del*(k*inverseMass1);
g_vertexPositions[node0] = (float4)(position0, 0.f);
g_vertexPositions[node1] = (float4)(position1, 0.f);
}
}
}
);

View File

@@ -0,0 +1,44 @@
MSTRINGIFY(
/*#define float3 float4
float dot3(float3 a, float3 b)
{
return a.x*b.x + a.y*b.y + a.z*b.z;
}*/
__kernel void
UpdateConstantsKernel(
const int numLinks,
__global int2 * g_linksVertexIndices,
__global float4 * g_vertexPositions,
__global float * g_vertexInverseMasses,
__global float * g_linksMaterialLSC,
__global float * g_linksMassLSC,
__global float * g_linksRestLengthSquared,
__global float * g_linksRestLengths)
{
int linkID = get_global_id(0);
if( linkID < numLinks )
{
int2 nodeIndices = g_linksVertexIndices[linkID];
int node0 = nodeIndices.x;
int node1 = nodeIndices.y;
float linearStiffnessCoefficient = g_linksMaterialLSC[ linkID ];
float3 position0 = g_vertexPositions[node0].xyz;
float3 position1 = g_vertexPositions[node1].xyz;
float inverseMass0 = g_vertexInverseMasses[node0];
float inverseMass1 = g_vertexInverseMasses[node1];
float3 difference = position0 - position1;
float length2 = dot(difference, difference);
float length = sqrt(length2);
g_linksRestLengths[linkID] = length;
g_linksMassLSC[linkID] = (inverseMass0 + inverseMass1)/linearStiffnessCoefficient;
g_linksRestLengthSquared[linkID] = length*length;
}
}
);

View File

@@ -0,0 +1,40 @@
MSTRINGIFY(
//#define float3 float4
__kernel void
updateVelocitiesFromPositionsWithVelocitiesKernel(
int numNodes,
float isolverdt,
__global float4 * g_vertexPositions,
__global float4 * g_vertexPreviousPositions,
__global int * g_vertexClothIndices,
__global float *g_clothVelocityCorrectionCoefficients,
__global float * g_clothDampingFactor,
__global float4 * g_vertexVelocities,
__global float4 * g_vertexForces)
{
int nodeID = get_global_id(0);
if( nodeID < numNodes )
{
float3 position = g_vertexPositions[nodeID].xyz;
float3 previousPosition = g_vertexPreviousPositions[nodeID].xyz;
float3 velocity = g_vertexVelocities[nodeID].xyz;
int clothIndex = g_vertexClothIndices[nodeID];
float velocityCorrectionCoefficient = g_clothVelocityCorrectionCoefficients[clothIndex];
float dampingFactor = g_clothDampingFactor[clothIndex];
float velocityCoefficient = (1.f - dampingFactor);
float3 difference = position - previousPosition;
velocity += difference*velocityCorrectionCoefficient*isolverdt;
// Damp the velocity
velocity *= velocityCoefficient;
g_vertexVelocities[nodeID] = (float4)(velocity, 0.f);
g_vertexForces[nodeID] = (float4)(0.f, 0.f, 0.f, 0.f);
}
}
);

View File

@@ -0,0 +1,103 @@
MSTRINGIFY(
//#define float3 float4
/*float length3(float3 a)
{
a.w = 0;
return length(a);
}
float normalize3(float3 a)
{
a.w = 0;
return normalize(a);
}*/
__kernel void
ResetNormalsAndAreasKernel(
const unsigned int numNodes,
__global float4 * g_vertexNormals,
__global float * g_vertexArea)
{
if( get_global_id(0) < numNodes )
{
g_vertexNormals[get_global_id(0)] = (float4)(0.0f, 0.0f, 0.0f, 0.0f);
g_vertexArea[get_global_id(0)] = 0.0f;
}
}
__kernel void
UpdateSoftBodiesKernel(
const unsigned int startFace,
const unsigned int numFaces,
__global int4 * g_triangleVertexIndexSet,
__global float4 * g_vertexPositions,
__global float4 * g_vertexNormals,
__global float * g_vertexArea,
__global float4 * g_triangleNormals,
__global float * g_triangleArea)
{
int faceID = get_global_id(0) + startFace;
if( get_global_id(0) < numFaces )
{
int4 triangleIndexSet = g_triangleVertexIndexSet[ faceID ];
int nodeIndex0 = triangleIndexSet.x;
int nodeIndex1 = triangleIndexSet.y;
int nodeIndex2 = triangleIndexSet.z;
float3 node0 = g_vertexPositions[nodeIndex0].xyz;
float3 node1 = g_vertexPositions[nodeIndex1].xyz;
float3 node2 = g_vertexPositions[nodeIndex2].xyz;
float3 nodeNormal0 = g_vertexNormals[nodeIndex0].xyz;
float3 nodeNormal1 = g_vertexNormals[nodeIndex1].xyz;
float3 nodeNormal2 = g_vertexNormals[nodeIndex2].xyz;
float vertexArea0 = g_vertexArea[nodeIndex0];
float vertexArea1 = g_vertexArea[nodeIndex1];
float vertexArea2 = g_vertexArea[nodeIndex2];
float3 vector0 = node1 - node0;
float3 vector1 = node2 - node0;
float3 faceNormal = cross(vector0.xyz, vector1.xyz);
float triangleArea = length(faceNormal);
nodeNormal0 = nodeNormal0 + faceNormal;
nodeNormal1 = nodeNormal1 + faceNormal;
nodeNormal2 = nodeNormal2 + faceNormal;
vertexArea0 = vertexArea0 + triangleArea;
vertexArea1 = vertexArea1 + triangleArea;
vertexArea2 = vertexArea2 + triangleArea;
g_triangleNormals[faceID] = (float4)(normalize(faceNormal), 0.f);
g_vertexNormals[nodeIndex0] = (float4)(nodeNormal0, 0.f);
g_vertexNormals[nodeIndex1] = (float4)(nodeNormal1, 0.f);
g_vertexNormals[nodeIndex2] = (float4)(nodeNormal2, 0.f);
g_triangleArea[faceID] = triangleArea;
g_vertexArea[nodeIndex0] = vertexArea0;
g_vertexArea[nodeIndex1] = vertexArea1;
g_vertexArea[nodeIndex2] = vertexArea2;
}
}
__kernel void
NormalizeNormalsAndAreasKernel(
const unsigned int numNodes,
__global int * g_vertexTriangleCount,
__global float4 * g_vertexNormals,
__global float * g_vertexArea)
{
if( get_global_id(0) < numNodes )
{
float4 normal = g_vertexNormals[get_global_id(0)];
float area = g_vertexArea[get_global_id(0)];
int numTriangles = g_vertexTriangleCount[get_global_id(0)];
float vectorLength = length(normal);
g_vertexNormals[get_global_id(0)] = normalize(normal);
g_vertexArea[get_global_id(0)] = area/(float)(numTriangles);
}
}
);

View File

@@ -0,0 +1,36 @@
MSTRINGIFY(
//#define float3 float4
__kernel void
updateVelocitiesFromPositionsWithoutVelocitiesKernel(
const int numNodes,
const float isolverdt,
__global float4 * g_vertexPositions,
__global float4 * g_vertexPreviousPositions,
__global int * g_vertexClothIndices,
__global float * g_clothDampingFactor,
__global float4 * g_vertexVelocities,
__global float4 * g_vertexForces)
{
int nodeID = get_global_id(0);
if( nodeID < numNodes )
{
float3 position = g_vertexPositions[nodeID].xyz;
float3 previousPosition = g_vertexPreviousPositions[nodeID].xyz;
float3 velocity = g_vertexVelocities[nodeID].xyz;
int clothIndex = g_vertexClothIndices[nodeID];
float dampingFactor = g_clothDampingFactor[clothIndex];
float velocityCoefficient = (1.f - dampingFactor);
float3 difference = position - previousPosition;
velocity = difference*velocityCoefficient*isolverdt;
g_vertexVelocities[nodeID] = (float4)(velocity, 0.f);
g_vertexForces[nodeID] = (float4)(0.f, 0.f, 0.f, 0.f);
}
}
);

View File

@@ -0,0 +1,26 @@
MSTRINGIFY(
//#define float3 float4
__kernel void
UpdatePositionsFromVelocitiesKernel(
const int numNodes,
const float solverSDT,
__global float4 * g_vertexVelocities,
__global float4 * g_vertexPreviousPositions,
__global float4 * g_vertexCurrentPosition)
{
int vertexID = get_global_id(0);
if( vertexID < numNodes )
{
float3 previousPosition = g_vertexPreviousPositions[vertexID].xyz;
float3 velocity = g_vertexVelocities[vertexID].xyz;
float3 newPosition = previousPosition + velocity*solverSDT;
g_vertexCurrentPosition[vertexID] = (float4)(newPosition, 0.f);
g_vertexPreviousPositions[vertexID] = (float4)(newPosition, 0.f);
}
}
);

View File

@@ -0,0 +1,45 @@
MSTRINGIFY(
__kernel void
VSolveLinksKernel(
int startLink,
int numLinks,
float kst,
__global int2 * g_linksVertexIndices,
__global float * g_linksLengthRatio,
__global float4 * g_linksCurrentLength,
__global float * g_vertexInverseMass,
__global float4 * g_vertexVelocity)
{
int linkID = get_global_id(0) + startLink;
if( get_global_id(0) < numLinks )
{
int2 nodeIndices = g_linksVertexIndices[linkID];
int node0 = nodeIndices.x;
int node1 = nodeIndices.y;
float linkLengthRatio = g_linksLengthRatio[linkID];
float3 linkCurrentLength = g_linksCurrentLength[linkID].xyz;
float3 vertexVelocity0 = g_vertexVelocity[node0].xyz;
float3 vertexVelocity1 = g_vertexVelocity[node1].xyz;
float vertexInverseMass0 = g_vertexInverseMass[node0];
float vertexInverseMass1 = g_vertexInverseMass[node1];
float3 nodeDifference = vertexVelocity0 - vertexVelocity1;
float dotResult = dot(linkCurrentLength, nodeDifference);
float j = -dotResult*linkLengthRatio*kst;
float3 velocityChange0 = linkCurrentLength*(j*vertexInverseMass0);
float3 velocityChange1 = linkCurrentLength*(j*vertexInverseMass1);
vertexVelocity0 += velocityChange0;
vertexVelocity1 -= velocityChange1;
g_vertexVelocity[node0] = (float4)(vertexVelocity0, 0.f);
g_vertexVelocity[node1] = (float4)(vertexVelocity1, 0.f);
}
}
);

View File

@@ -0,0 +1,183 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_SOFT_BODY_SOLVER_BUFFER_OPENCL_H
#define BT_SOFT_BODY_SOLVER_BUFFER_OPENCL_H
// OpenCL support
#include <CL/cl.hpp>
#ifndef SAFE_RELEASE
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
#endif
template <typename ElementType> class btOpenCLBuffer
{
protected:
cl::CommandQueue m_queue;
btAlignedObjectArray< ElementType > * m_CPUBuffer;
cl::Buffer m_buffer;
int m_gpuSize;
bool m_onGPU;
bool m_readOnlyOnGPU;
bool m_allocated;
// TODO: Remove this once C++ bindings are fixed
cl::Context context;
bool createBuffer( cl::Buffer *preexistingBuffer = 0)
{
cl_int err;
if( preexistingBuffer )
{
m_buffer = *preexistingBuffer;
}
else {
m_buffer = cl::Buffer(
context,
m_readOnlyOnGPU ? CL_MEM_READ_ONLY : CL_MEM_READ_WRITE,
m_CPUBuffer->size() * sizeof(ElementType),
0,
&err);
if( err != CL_SUCCESS )
{
btAssert( "Buffer::Buffer(m_buffer)");
}
}
m_gpuSize = m_CPUBuffer->size();
return true;
}
public:
btOpenCLBuffer(
cl::CommandQueue queue,
btAlignedObjectArray< ElementType > *CPUBuffer,
bool readOnly) :
m_queue(queue),
m_CPUBuffer(CPUBuffer),
m_gpuSize(0),
m_onGPU(false),
m_readOnlyOnGPU(readOnly),
m_allocated(false)
{
context = m_queue.getInfo<CL_QUEUE_CONTEXT>();
}
~btOpenCLBuffer()
{
}
cl::Buffer getBuffer()
{
return m_buffer;
}
bool moveToGPU()
{
cl_int err;
if( (m_CPUBuffer->size() != m_gpuSize) )
{
m_onGPU = false;
}
if( !m_onGPU && m_CPUBuffer->size() > 0 )
{
if (!m_allocated || (m_CPUBuffer->size() != m_gpuSize)) {
if (!createBuffer()) {
return false;
}
m_allocated = true;
}
err = m_queue.enqueueWriteBuffer(
m_buffer,
CL_FALSE,
0,
m_CPUBuffer->size() * sizeof(ElementType),
&((*m_CPUBuffer)[0]));
if( err != CL_SUCCESS )
{
btAssert( "CommandQueue::enqueueWriteBuffer(m_buffer)" );
}
m_onGPU = true;
}
return true;
}
bool moveFromGPU()
{
cl_int err;
if (m_CPUBuffer->size() > 0) {
if (m_onGPU && !m_readOnlyOnGPU) {
err = m_queue.enqueueReadBuffer(
m_buffer,
CL_TRUE,
0,
m_CPUBuffer->size() * sizeof(ElementType),
&((*m_CPUBuffer)[0]));
if( err != CL_SUCCESS )
{
btAssert( "CommandQueue::enqueueReadBuffer(m_buffer)" );
}
m_onGPU = false;
}
}
return true;
}
bool copyFromGPU()
{
cl_int err;
if (m_CPUBuffer->size() > 0) {
if (m_onGPU && !m_readOnlyOnGPU) {
err = m_queue.enqueueReadBuffer(
m_buffer,
CL_TRUE,
0,
m_CPUBuffer->size() * sizeof(ElementType),
&((*m_CPUBuffer)[0]));
if( err != CL_SUCCESS )
{
btAssert( "CommandQueue::enqueueReadBuffer(m_buffer)");
}
}
}
return true;
}
virtual void changedOnCPU()
{
m_onGPU = false;
}
}; // class btOpenCLBuffer
#endif // #ifndef BT_SOFT_BODY_SOLVER_BUFFER_OPENCL_H

View File

@@ -0,0 +1,79 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "BulletSoftBody/Solvers/CPU/btSoftBodySolverData.h"
#include "BulletSoftBody/Solvers/OpenCL/btSoftBodySolverBuffer_OpenCL.h"
#ifndef BT_SOFT_BODY_SOLVER_LINK_DATA_OPENCL_H
#define BT_SOFT_BODY_SOLVER_LINK_DATA_OPENCL_H
class btSoftBodyLinkDataOpenCL : public btSoftBodyLinkData
{
public:
bool m_onGPU;
cl::CommandQueue m_queue;
btOpenCLBuffer<LinkNodePair> m_clLinks;
btOpenCLBuffer<float> m_clLinkStrength;
btOpenCLBuffer<float> m_clLinksMassLSC;
btOpenCLBuffer<float> m_clLinksRestLengthSquared;
btOpenCLBuffer<Vectormath::Aos::Vector3> m_clLinksCLength;
btOpenCLBuffer<float> m_clLinksLengthRatio;
btOpenCLBuffer<float> m_clLinksRestLength;
btOpenCLBuffer<float> m_clLinksMaterialLinearStiffnessCoefficient;
/**
* Link addressing information for each cloth.
* Allows link locations to be computed independently of data batching.
*/
btAlignedObjectArray< int > m_linkAddresses;
/**
* Start and length values for computation batches over link data.
*/
btAlignedObjectArray< std::pair< int, int > > m_batchStartLengths;
btSoftBodyLinkDataOpenCL(cl::CommandQueue queue);
virtual ~btSoftBodyLinkDataOpenCL();
/** Allocate enough space in all link-related arrays to fit numLinks links */
virtual void createLinks( int numLinks );
/** Insert the link described into the correct data structures assuming space has already been allocated by a call to createLinks */
virtual void setLinkAt(
const LinkDescription &link,
int linkIndex );
virtual bool onAccelerator();
virtual bool moveToAccelerator();
virtual bool moveFromAccelerator();
/**
* Generate (and later update) the batching for the entire link set.
* This redoes a lot of work because it batches the entire set when each cloth is inserted.
* In theory we could delay it until just before we need the cloth.
* It's a one-off overhead, though, so that is a later optimisation.
*/
void generateBatches();
};
#endif // #ifndef BT_SOFT_BODY_SOLVER_LINK_DATA_OPENCL_H

View File

@@ -0,0 +1,74 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "BulletSoftBody/Solvers/CPU/btSoftBodySolverData.h"
#include "BulletSoftBody/Solvers/OpenCL/btSoftBodySolverBuffer_OpenCL.h"
#ifndef BT_SOFT_BODY_SOLVER_TRIANGLE_DATA_OPENCL_H
#define BT_SOFT_BODY_SOLVER_TRIANGLE_DATA_OPENCL_H
class btSoftBodyTriangleDataOpenCL : public btSoftBodyTriangleData
{
public:
bool m_onGPU;
cl::CommandQueue m_queue;
btOpenCLBuffer<btSoftBodyTriangleData::TriangleNodeSet> m_clVertexIndices;
btOpenCLBuffer<float> m_clArea;
btOpenCLBuffer<Vectormath::Aos::Vector3> m_clNormal;
/**
* Link addressing information for each cloth.
* Allows link locations to be computed independently of data batching.
*/
btAlignedObjectArray< int > m_triangleAddresses;
/**
* Start and length values for computation batches over link data.
*/
btAlignedObjectArray< std::pair< int, int > > m_batchStartLengths;
public:
btSoftBodyTriangleDataOpenCL( cl::CommandQueue queue );
virtual ~btSoftBodyTriangleDataOpenCL();
/** Allocate enough space in all link-related arrays to fit numLinks links */
virtual void createTriangles( int numTriangles );
/** Insert the link described into the correct data structures assuming space has already been allocated by a call to createLinks */
virtual void setTriangleAt( const btSoftBodyTriangleData::TriangleDescription &triangle, int triangleIndex );
virtual bool onAccelerator();
virtual bool moveToAccelerator();
virtual bool moveFromAccelerator();
/**
* Generate (and later update) the batching for the entire triangle set.
* This redoes a lot of work because it batches the entire set when each cloth is inserted.
* In theory we could delay it until just before we need the cloth.
* It's a one-off overhead, though, so that is a later optimisation.
*/
void generateBatches();
}; // class btSoftBodyTriangleDataOpenCL
#endif // #ifndef BT_SOFT_BODY_SOLVER_TRIANGLE_DATA_OPENCL_H

View File

@@ -0,0 +1,52 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "BulletSoftBody/Solvers/CPU/btSoftBodySolverData.h"
#include "BulletSoftBody/Solvers/OpenCL/btSoftBodySolverBuffer_OpenCL.h"
#ifndef BT_SOFT_BODY_SOLVER_VERTEX_DATA_OPENCL_H
#define BT_SOFT_BODY_SOLVER_VERTEX_DATA_OPENCL_H
class btSoftBodyVertexDataOpenCL : public btSoftBodyVertexData
{
protected:
bool m_onGPU;
cl::CommandQueue m_queue;
public:
btOpenCLBuffer<int> m_clClothIdentifier;
btOpenCLBuffer<Vectormath::Aos::Point3> m_clVertexPosition;
btOpenCLBuffer<Vectormath::Aos::Point3> m_clVertexPreviousPosition;
btOpenCLBuffer<Vectormath::Aos::Vector3> m_clVertexVelocity;
btOpenCLBuffer<Vectormath::Aos::Vector3> m_clVertexForceAccumulator;
btOpenCLBuffer<Vectormath::Aos::Vector3> m_clVertexNormal;
btOpenCLBuffer<float> m_clVertexInverseMass;
btOpenCLBuffer<float> m_clVertexArea;
btOpenCLBuffer<int> m_clVertexTriangleCount;
public:
btSoftBodyVertexDataOpenCL( cl::CommandQueue queue);
virtual ~btSoftBodyVertexDataOpenCL();
virtual bool onAccelerator();
virtual bool moveToAccelerator();
virtual bool moveFromAccelerator();
};
#endif // #ifndef BT_SOFT_BODY_SOLVER_VERTEX_DATA_OPENCL_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,377 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_SOFT_BODY_SOLVER_OPENCL_H
#define BT_SOFT_BODY_SOLVER_OPENCL_H
#include "BulletMultiThreaded/vectormath/scalar/cpp/vectormath_aos.h"
#include "BulletMultiThreaded/vectormath/scalar/cpp/mat_aos.h"
#include "BulletMultiThreaded/vectormath/scalar/cpp/vec_aos.h"
#include "BulletSoftBody/btSoftBodySolvers.h"
#include "BulletSoftBody/solvers/OpenCL/btSoftBodySolverBuffer_OpenCL.h"
#include "BulletSoftBody/solvers/OpenCL/btSoftBodySolverLinkData_OpenCL.h"
#include "BulletSoftBody/solvers/OpenCL/btSoftBodySolverVertexData_OpenCL.h"
#include "BulletSoftBody/solvers/OpenCL/btSoftBodySolverTriangleData_OpenCL.h"
class btOpenCLSoftBodySolver : public btSoftBodySolver
{
private:
/**
* 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;
}
// 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;
}
#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 KernelDesc
{
protected:
public:
cl::Kernel kernel;
KernelDesc()
{
}
virtual ~KernelDesc()
{
}
};
btSoftBodyLinkDataOpenCL m_linkData;
btSoftBodyVertexDataOpenCL m_vertexData;
btSoftBodyTriangleDataOpenCL 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;
/** 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;
btOpenCLBuffer<Vectormath::Aos::Vector3> m_clPerClothAcceleration;
/** 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;
btOpenCLBuffer<Vectormath::Aos::Vector3> m_clPerClothWindVelocity;
/** Velocity damping factor */
btAlignedObjectArray< float > m_perClothDampingFactor;
btOpenCLBuffer<float> m_clPerClothDampingFactor;
/** Velocity correction coefficient */
btAlignedObjectArray< float > m_perClothVelocityCorrectionCoefficient;
btOpenCLBuffer<float> m_clPerClothVelocityCorrectionCoefficient;
/** Lift parameter for wind effect on cloth. */
btAlignedObjectArray< float > m_perClothLiftFactor;
btOpenCLBuffer<float> m_clPerClothLiftFactor;
/** Drag parameter for wind effect on cloth. */
btAlignedObjectArray< float > m_perClothDragFactor;
btOpenCLBuffer<float> m_clPerClothDragFactor;
/** Density of the medium in which each cloth sits */
btAlignedObjectArray< float > m_perClothMediumDensity;
btOpenCLBuffer<float> m_clPerClothMediumDensity;
KernelDesc prepareLinksKernel;
KernelDesc solvePositionsFromLinksKernel;
KernelDesc updateConstantsKernel;
KernelDesc integrateKernel;
KernelDesc addVelocityKernel;
KernelDesc updatePositionsFromVelocitiesKernel;
KernelDesc updateVelocitiesFromPositionsWithoutVelocitiesKernel;
KernelDesc updateVelocitiesFromPositionsWithVelocitiesKernel;
KernelDesc vSolveLinksKernel;
KernelDesc resetNormalsAndAreasKernel;
KernelDesc normalizeNormalsAndAreasKernel;
KernelDesc updateSoftBodiesKernel;
KernelDesc outputToVertexArrayWithNormalsKernel;
KernelDesc outputToVertexArrayWithoutNormalsKernel;
KernelDesc outputToVertexArrayKernel;
KernelDesc applyForcesKernel;
KernelDesc collideSphereKernel;
KernelDesc collideCylinderKernel;
static const int workGroupSize = 128;
cl::CommandQueue m_queue;
cl::Context context;
cl::Device device;
/**
* Compile a compute shader kernel from a string and return the appropriate KernelDesc object.
*/
KernelDesc compileCLKernelFromString( const char *shaderString, const char *shaderName );
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 );
btAcceleratedSoftBodyInterface *findSoftBodyInterface( const btSoftBody* const softBody );
virtual void applyForces( float solverdt );
/**
* Integrate motion on the solver.
*/
virtual void integrate( float solverdt );
void updateConstants( float timeStep );
float computeTriangleArea(
const Vectormath::Aos::Point3 &vertex0,
const Vectormath::Aos::Point3 &vertex1,
const Vectormath::Aos::Point3 &vertex2 );
//////////////////////////////////////
// Kernel dispatches
void prepareLinks();
void solveLinksForVelocity( int startLink, int numLinks, float kst );
void updatePositionsFromVelocities( float solverdt );
void solveLinksForPosition( int startLink, int numLinks, float kst, float ti );
void updateVelocitiesFromPositionsWithVelocities( float isolverdt );
void updateVelocitiesFromPositionsWithoutVelocities( float isolverdt );
// End kernel dispatches
/////////////////////////////////////
public:
btOpenCLSoftBodySolver(const cl::CommandQueue &queue);
virtual ~btOpenCLSoftBodySolver();
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 );
}; // btOpenCLSoftBodySolver
#endif #ifndef BT_SOFT_BODY_SOLVER_OPENCL_H