diff --git a/PBDSimulator/Assets/PBDCloth/Scripts/ClothData.cs b/PBDSimulator/Assets/PBDCloth/Scripts/ClothData.cs index 653b84d..9e334a5 100644 --- a/PBDSimulator/Assets/PBDCloth/Scripts/ClothData.cs +++ b/PBDSimulator/Assets/PBDCloth/Scripts/ClothData.cs @@ -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; } \ No newline at end of file diff --git a/PBDSimulator/Assets/PBDCloth/Scripts/GPUClothSimulator.cs b/PBDSimulator/Assets/PBDCloth/Scripts/GPUClothSimulator.cs index 19b0a2f..2e0c498 100644 --- a/PBDSimulator/Assets/PBDCloth/Scripts/GPUClothSimulator.cs +++ b/PBDSimulator/Assets/PBDCloth/Scripts/GPUClothSimulator.cs @@ -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 @@ -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; @@ -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 @@ -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 @@ -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)); @@ -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"); @@ -609,6 +616,7 @@ private void SetupComputeBuffers() { private void SetupCollisionComputeBuffers() { List spheres = new List(); List cubes = new List(); + List capsules = new List(); // categorize all the collidable objects for (int j = 0; j < collidableObjects.Length; j++) { @@ -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 @@ -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().center; + collidableCubes[i].center = cubes[i].transform.TransformPoint(cubes[i].GetComponent().center); + collidableCubes[i].xVec = cubes[i].transform.TransformVector(cubes[i].GetComponent().size.x / 2f, 0.0f, 0.0f); + collidableCubes[i].yVec = cubes[i].transform.TransformVector(0.0f, cubes[i].GetComponent().size.y / 2f, 0.0f); + collidableCubes[i].zVec = cubes[i].transform.TransformVector(0.0f, 0.0f, cubes[i].GetComponent().size.z / 2f); float extent_x = cubes[i].transform.lossyScale.x * cubes[i].GetComponent().size.x / 2f; float extent_y = cubes[i].transform.lossyScale.y * cubes[i].GetComponent().size.y / 2f; float extent_z = cubes[i].transform.lossyScale.z * cubes[i].GetComponent().size.z / 2f; @@ -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); @@ -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().center); + //collidableCapsules[i].center = capsules[i].transform.position + capsules[i].GetComponent().center; + collidableCapsules[i].radius = capsules[i].GetComponent().radius * capsules[i].transform.lossyScale.x; + collidableCapsules[i].height = capsules[i].transform.lossyScale.x * capsules[i].GetComponent().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().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(); diff --git a/PBDSimulator/Assets/PBDCloth/Scripts/PBDClothSolver.compute b/PBDSimulator/Assets/PBDCloth/Scripts/PBDClothSolver.compute index 26d656d..d7c7874 100644 --- a/PBDSimulator/Assets/PBDCloth/Scripts/PBDClothSolver.compute +++ b/PBDSimulator/Assets/PBDCloth/Scripts/PBDClothSolver.compute @@ -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 @@ -34,6 +44,7 @@ uint numBendingConstraints; uint numAllConstraints; uint numCollidableSpheres; uint numCollidableCubes; +uint numCollidableCapsules; uint numPointConstraints; float3 gravity; float invMass; @@ -54,6 +65,7 @@ StructuredBuffer distanceConstraints; StructuredBuffer bendingConstraints; StructuredBuffer collidableSpheres; StructuredBuffer collidableCubes; +StructuredBuffer collidableCapsule; StructuredBuffer pointConstraints; bool hasTempPointConstraint; @@ -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) = numParticles) return; @@ -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