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:
22
src/BulletMultiThreaded/GpuSoftBodySolvers/CMakeLists.txt
Normal file
22
src/BulletMultiThreaded/GpuSoftBodySolvers/CMakeLists.txt
Normal 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} )
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
Reference in New Issue
Block a user