Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

changes: #3

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions PBDSimulator/Assets/PBDCloth/Scripts/ClothData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,15 @@ struct CollidableSphereStruct {
struct CollidableCubeStruct {
public Vector3 center;
public Vector3 extent;
public Vector3 xVec;
public Vector3 yVec;
public Vector3 zVec;
}

struct CollidableCapsuleStruct
{
public Vector3 center;
public Vector3 up;
public float height;
public float radius;
}
49 changes: 45 additions & 4 deletions PBDSimulator/Assets/PBDCloth/Scripts/GPUClothSimulator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public class GPUClothSimulator : MonoBehaviour {
private float invMass;
private int numParticles;
private int numDistanceConstraints, numBendingConstraints;
private int numCollidableSpheres, numCollidableCubes, numPointConstraints;
private int numCollidableSpheres, numCollidableCubes, numCollidableCapsule, numPointConstraints;
// TODO: can we remove the following 3?
private Vector3[] deltaPositionArray; // The array that stores all the deltas
private int[] deltaCounterArray; // The array to initialize delta count buffer
Expand All @@ -72,6 +72,7 @@ public class GPUClothSimulator : MonoBehaviour {
private ComputeBuffer bendingConstraintsBuffer;
private ComputeBuffer collidableSpheresBuffer;
private ComputeBuffer collidableCubesBuffer;
private ComputeBuffer collidableCapsuleBuffer;
private ComputeBuffer pointConstraintsBuffer;
private ComputeBuffer frictionsBuffer;

Expand All @@ -84,6 +85,7 @@ public class GPUClothSimulator : MonoBehaviour {
private int satisfyPointConstraintsKernel;
private int satisfySphereCollisionsKernel;
private int satisfyCubeCollisionsKernel;
private int SatisfyCapsuleCollisionsKernel;
private int updatePositionsKernel;

// num of work groups
Expand Down Expand Up @@ -228,6 +230,10 @@ private void Update() {
if (numCollidableCubes > 0) {
PBDClothSolver.Dispatch(satisfyCubeCollisionsKernel, numGroups_Vertices, 1, 1);
}
if (numCollidableCapsule > 0)
{
PBDClothSolver.Dispatch(SatisfyCapsuleCollisionsKernel, numGroups_Vertices, 1, 1);
}
}

// satisfy pointConstraints
Expand Down Expand Up @@ -533,7 +539,7 @@ private void SetupComputeBuffers() {
positionsBuffer = new ComputeBuffer(numParticles, sizeof(float) * 3);
projectedPositionsBuffer = new ComputeBuffer(numParticles, sizeof(float) * 3);
velocitiesBuffer = new ComputeBuffer(numParticles, sizeof(float) * 3);
frictionsBuffer = new ComputeBuffer(numParticles, sizeof(float) * 3);
frictionsBuffer = new ComputeBuffer(numParticles, sizeof(float));
deltaPositionsBuffer = new ComputeBuffer(numParticles, sizeof(float) * 3);
deltaPositionsUIntBuffer = new ComputeBuffer(numParticles, sizeof(uint) * 3);
deltaCounterBuffer = new ComputeBuffer(numParticles, sizeof(int));
Expand Down Expand Up @@ -561,6 +567,7 @@ private void SetupComputeBuffers() {
updatePositionsKernel = PBDClothSolver.FindKernel("UpdatePositions");
satisfySphereCollisionsKernel = PBDClothSolver.FindKernel("SatisfySphereCollisions");
satisfyCubeCollisionsKernel = PBDClothSolver.FindKernel("SatisfyCubeCollisions");
SatisfyCapsuleCollisionsKernel = PBDClothSolver.FindKernel("SatisfyCapsuleCollisions");
satisfyPointConstraintsKernel = PBDClothSolver.FindKernel("SatisfyPointConstraints");


Expand Down Expand Up @@ -609,6 +616,7 @@ private void SetupComputeBuffers() {
private void SetupCollisionComputeBuffers() {
List<GameObject> spheres = new List<GameObject>();
List<GameObject> cubes = new List<GameObject>();
List<GameObject> capsules = new List<GameObject>();

// categorize all the collidable objects
for (int j = 0; j < collidableObjects.Length; j++) {
Expand All @@ -622,6 +630,10 @@ private void SetupCollisionComputeBuffers() {
else if (collider.GetType() == typeof(BoxCollider)) {
cubes.Add(collidableObjects[j]);
}
else if (collider.GetType() == typeof(CapsuleCollider))
{
capsules.Add(collidableObjects[j]);
}
}

// create the compute buffer for spheres
Expand All @@ -648,7 +660,10 @@ private void SetupCollisionComputeBuffers() {
CollidableCubeStruct[] collidableCubes = new CollidableCubeStruct[cubes.Count];
numCollidableCubes = cubes.Count;
for (int i = 0; i < numCollidableCubes; i++) {
collidableCubes[i].center = cubes[i].transform.position + cubes[i].GetComponent<BoxCollider>().center;
collidableCubes[i].center = cubes[i].transform.TransformPoint(cubes[i].GetComponent<BoxCollider>().center);
collidableCubes[i].xVec = cubes[i].transform.TransformVector(cubes[i].GetComponent<BoxCollider>().size.x / 2f, 0.0f, 0.0f);
collidableCubes[i].yVec = cubes[i].transform.TransformVector(0.0f, cubes[i].GetComponent<BoxCollider>().size.y / 2f, 0.0f);
collidableCubes[i].zVec = cubes[i].transform.TransformVector(0.0f, 0.0f, cubes[i].GetComponent<BoxCollider>().size.z / 2f);
float extent_x = cubes[i].transform.lossyScale.x * cubes[i].GetComponent<BoxCollider>().size.x / 2f;
float extent_y = cubes[i].transform.lossyScale.y * cubes[i].GetComponent<BoxCollider>().size.y / 2f;
float extent_z = cubes[i].transform.lossyScale.z * cubes[i].GetComponent<BoxCollider>().size.z / 2f;
Expand All @@ -657,7 +672,7 @@ private void SetupCollisionComputeBuffers() {
if (collidableCubesBuffer != null) collidableCubesBuffer.Release();

if (numCollidableCubes > 0) {
collidableCubesBuffer = new ComputeBuffer(numCollidableCubes, sizeof(float) * 6);
collidableCubesBuffer = new ComputeBuffer(numCollidableCubes, sizeof(float) * 15);
// fill buffers with initial data
collidableCubesBuffer.SetData(collidableCubes);
PBDClothSolver.SetInt("numCollidableCubes", numCollidableCubes);
Expand All @@ -666,6 +681,32 @@ private void SetupCollisionComputeBuffers() {
PBDClothSolver.SetBuffer(satisfyCubeCollisionsKernel, "frictions", frictionsBuffer);
}

// create the compute buffer for capsules
CollidableCapsuleStruct[] collidableCapsules = new CollidableCapsuleStruct[capsules.Count];
numCollidableCapsule = capsules.Count;
for (int i = 0; i < numCollidableCapsule; i++)
{
collidableCapsules[i].center = capsules[i].transform.TransformPoint(capsules[i].GetComponent<CapsuleCollider>().center);
//collidableCapsules[i].center = capsules[i].transform.position + capsules[i].GetComponent<CapsuleCollider>().center;
collidableCapsules[i].radius = capsules[i].GetComponent<CapsuleCollider>().radius * capsules[i].transform.lossyScale.x;
collidableCapsules[i].height = capsules[i].transform.lossyScale.x * capsules[i].GetComponent<CapsuleCollider>().height / 2 - collidableCapsules[i].radius;
Vector3 upVec = new Vector3(0.0f, collidableCapsules[i].height / capsules[i].transform.lossyScale.x, 0.0f);
collidableCapsules[i].up = capsules[i].transform.TransformPoint(upVec + capsules[i].GetComponent<CapsuleCollider>().center);
}
if (collidableCapsuleBuffer != null) collidableCapsuleBuffer.Release();

if (numCollidableCapsule > 0)
{
collidableCapsuleBuffer = new ComputeBuffer(numCollidableCapsule, sizeof(float) * 8);
// fill buffers with initial data
collidableCapsuleBuffer.SetData(collidableCapsules);
PBDClothSolver.SetInt("numCollidableCapsules", numCollidableSpheres);
PBDClothSolver.SetBuffer(SatisfyCapsuleCollisionsKernel, "projectedPositions", projectedPositionsBuffer);
PBDClothSolver.SetBuffer(SatisfyCapsuleCollisionsKernel, "collidableCapsule", collidableCapsuleBuffer);
PBDClothSolver.SetBuffer(SatisfyCapsuleCollisionsKernel, "frictions", frictionsBuffer);
int a = 0;
}

// create compute buffer for point constraints
AddPointConstraints();
if (pointConstraintsBuffer != null) pointConstraintsBuffer.Release();
Expand Down
108 changes: 87 additions & 21 deletions PBDSimulator/Assets/PBDCloth/Scripts/PBDClothSolver.compute
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,16 @@ struct CollidableSphereStruct {
struct CollidableCubeStruct {
float3 center;
float3 extent;
float3 xVec;
float3 yVec;
float3 zVec;
};

struct CollidableCapsuleStruct{
float3 center;
float3 up;
float height;
float radius;
};

// Uniform data
Expand All @@ -34,6 +44,7 @@ uint numBendingConstraints;
uint numAllConstraints;
uint numCollidableSpheres;
uint numCollidableCubes;
uint numCollidableCapsules;
uint numPointConstraints;
float3 gravity;
float invMass;
Expand All @@ -54,6 +65,7 @@ StructuredBuffer<DistanceConstraintStruct> distanceConstraints;
StructuredBuffer<BendingConstraintStruct> bendingConstraints;
StructuredBuffer<CollidableSphereStruct> collidableSpheres;
StructuredBuffer<CollidableCubeStruct> collidableCubes;
StructuredBuffer<CollidableCapsuleStruct> collidableCapsule;
StructuredBuffer<int> pointConstraints;

bool hasTempPointConstraint;
Expand Down Expand Up @@ -312,6 +324,38 @@ bool IsPointInCube(float3 position, float3 extent) {
return abs(position.x) < extent.x && abs(position.y) < extent.y && abs(position.z) < extent.z;
}

struct CubeCollisionInfo{
bool ifCubeCollision;
float3 moveOut;
};

CubeCollisionInfo IsPointInCube2(float3 position, float3 xx, float3 yy,float3 zz) {
CubeCollisionInfo res;
float3 nPosition=normalize(position);
float minDistance=length(xx)+length(yy)+length(zz);
float3 moveout=xx;
float xPos=length(position)*dot(normalize(xx),nPosition);
if(sign(xPos)* (sign(xPos)*length(xx)-xPos) <minDistance){
minDistance=sign(xPos)* (sign(xPos)*length(xx)-xPos);
moveout=sign(xPos)*normalize(xx);
}
float yPos=length(position)*dot(normalize(yy),nPosition);
if(sign(yPos)* (sign(yPos)*length(yy)-yPos) <minDistance){
minDistance=sign(yPos)* (sign(yPos)*length(yy)-yPos);
moveout=sign(yPos)*normalize(yy);
}

float zPos=length(position)*dot(normalize(zz),nPosition);
if(sign(zPos)* (sign(zPos)*length(zz)-zPos) <minDistance){
minDistance=sign(zPos)* (sign(zPos)*length(zz)-zPos);
moveout=sign(zPos)*normalize(zz);
}

res.ifCubeCollision=abs(xPos)<length(xx) && abs(yPos)<length(yy) && abs(zPos)<length(zz);
res.moveOut=moveout*(minDistance+0.001f);
return res;
}

[numthreads(8, 1, 1)] // TODO: play around with numthread size
void SatisfyCubeCollisions(uint3 id : SV_DispatchThreadID) {
if (id.x >= numParticles) return;
Expand All @@ -321,38 +365,60 @@ void SatisfyCubeCollisions(uint3 id : SV_DispatchThreadID) {
for (uint i = 0; i < numCollidableCubes; i++) {
float3 center = collidableCubes[i].center;
float3 extent = collidableCubes[i].extent;
float3 xx=collidableCubes[i].xVec;
float3 yy=collidableCubes[i].yVec;
float3 zz=collidableCubes[i].zVec;
float3 localPosition = projectedPosition - center;

if (IsPointInCube(localPosition, extent)) {
int closestAxis = -1;
float closestDist = 99999;
for (int i = 0; i < 3; i++) {
float dist = abs(localPosition[i] - extent[i]);
if (dist < closestDist) {
closestDist = dist;
closestAxis = i;
}
}
CubeCollisionInfo cubeCollisionInfo=IsPointInCube2(localPosition,xx,yy,zz);

float3 newPos = localPosition;
if (closestAxis == 0) {
newPos.x = (extent.x + 0.001f) * sign(localPosition.x);
}
else if (closestAxis == 1) {
newPos.y = (extent.y + 0.001f) * sign(localPosition.y);
}
else if (closestAxis == 2) {
newPos.z = (extent.z + 0.001f) * sign(localPosition.z);
}

projectedPosition = newPos + center;
if(cubeCollisionInfo.ifCubeCollision){
projectedPosition = projectedPosition + cubeCollisionInfo.moveOut;
frictions[id.x] = 0.8f;
}

}

projectedPositions[id.x] = projectedPosition;
}

#pragma kernel SatisfyCapsuleCollisions

[numthreads(8, 1, 1)] // TODO: play around with numthread size
void SatisfyCapsuleCollisions(uint3 id : SV_DispatchThreadID) {
if (id.x >= numParticles) return;

float3 projectedPosition = projectedPositions[id.x];
for (uint i = 0; i < numCollidableCapsules; i++) {
float3 center = collidableCapsule[i].center;
float radius = collidableCapsule[i].radius;
float3 up = collidableCapsule[i].up;

float3 D=projectedPosition-center;
float cosTheta=dot(normalize(D),normalize(up-center));
float sinTheta=sqrt(1-pow(cosTheta,2));
float heightDistance=length(D)*cosTheta;
float height=length(up-center);
if((heightDistance>=-height)&&(heightDistance<=height)&&(length(D)*sinTheta<=radius)){
float3 temp=cross(D,(up-center));
float3 moveOut=normalize(cross((up-center),temp));
projectedPosition = center+normalize(up-center)*length(D)*cosTheta + moveOut*(radius+0.01f);
frictions[id.x] = 0.8f;
}else if((heightDistance>=-height-radius)&&(heightDistance<=height+radius)&&
(length(projectedPosition-up)<=radius)){
float3 n = normalize(projectedPosition - up);
projectedPosition = up + n * (radius + 0.01f);
frictions[id.x] = 0.8f;
}else if((heightDistance>=-height-radius)&&(heightDistance<=height+radius)&&
(length(projectedPosition-2*center+up)<=radius)){
float3 n = normalize(projectedPosition - 2*center+up);
projectedPosition = 2*center-up + n * (radius + 0.01f);
frictions[id.x] = 0.8f;
}
projectedPositions[id.x] = projectedPosition;
}
}

#pragma kernel SatisfyPointConstraints
[numthreads(8, 1, 1)] // TODO: play around with numthread size
Expand Down