From 6a9eef9b0a1dfb078bec0ef2afd98f1fd67a18c4 Mon Sep 17 00:00:00 2001 From: wangpffigure Date: Wed, 21 Aug 2019 16:06:25 +0800 Subject: [PATCH] changes: 1.fix error: the size of frictionsBuffer. 2.improve the performance of cube collision testing and manipulating. solve the problem that cube collision does not work correctly when the cube has been rotated. 3.finish the capsule collier( in compute shader only). --- .../Assets/PBDCloth/Scripts/ClothData.cs | 11 ++ .../PBDCloth/Scripts/GPUClothSimulator.cs | 49 +++++++- .../PBDCloth/Scripts/PBDClothSolver.compute | 108 ++++++++++++++---- 3 files changed, 143 insertions(+), 25 deletions(-) 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