Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice
  2. Ever participated in one our Game Jams? Want pointers on your project? Our Evangelists will be available on Friday to give feedback. Come share your games with us!
    Dismiss Notice

Compute Shader for Cloth Simulation (PBD)

Discussion in 'Physics' started by nyxaiot, May 21, 2020.

  1. nyxaiot

    nyxaiot

    Joined:
    Oct 8, 2019
    Posts:
    10
    Hi everyone! Is there anyone making cloth simulations using compute shader? I am currently on journey to use GPU to simulate cloth and soft body physics. Does anyone has any solutions or guides on how this can be achieved? I have searched online for alot of solutions but just can't come up with a decent solution. Alot of people used mass spring cloth simulation but it is actually really expensive to simulate as you need to dispatch a kernel a few hundred times per FixedUpdate() to get a decent simulation.

    I wanna achieve sth like this but unfortunately the person who made this, Jim Hugunin, did not post any links or open source it...



    I know that Nvidia has their Flex Physics system on the asset store but it is only limited to NVIDIA graphics card and doesn't work well on other GPUs. I am looking for a GPGPU solution. Any links to Nvidia's cloth simulation tutorial or research paper will be much appreciated too!
     
  2. joshuacwilde

    joshuacwilde

    Joined:
    Feb 4, 2018
    Posts:
    40
    You could try something like speculative constraints for the cloth. It is very similar to a regular mass spring system. Just a different solver. But it is a lot more robust and can achieve stiffness faster than a mass spring system.
     
  3. nyxaiot

    nyxaiot

    Joined:
    Oct 8, 2019
    Posts:
    10
    Hi @joshuacwilde , first of all thank you for replying! If possible could you point me to any links or research paper regarding this technique? Thank you very much!
     
  4. nyxaiot

    nyxaiot

    Joined:
    Oct 8, 2019
    Posts:
    10
    upload_2020-5-23_12-11-4.png
    I actually made a post on FB with more detail on why mass spring simulation is not efficient and expensive..
     
  5. joshuacwilde

    joshuacwilde

    Joined:
    Feb 4, 2018
    Posts:
    40
  6. nyxaiot

    nyxaiot

    Joined:
    Oct 8, 2019
    Posts:
    10
    This is a great resource but it is for collision detection, it can definitely help alot in collision detection and self collision for cloth. But I don't know how to use this method to hold the particles together on a cloth, sorry if I'm not understanding your reply but I am new to these...
     
  7. nyxaiot

    nyxaiot

    Joined:
    Oct 8, 2019
    Posts:
    10
    Code (CSharp):
    1.  
    Hi guys, I think I should at least post my most recent solution for cloth simulation to give you guys an idea on where I am right now. This is my mass spring cloth simulation: (this is the compute shader code)

    Code (CSharp):
    1. // Each #kernel tells which function to compile; you can have many kernels
    2. #pragma kernel Cloth
    3.  
    4.  
    5. float3 gravity;
    6. uint totalParticles;
    7. float particleMass;
    8. float invertParticleMass;
    9. uint springK;
    10. float maxStretch;
    11. float damping;
    12. float deltaT;
    13.  
    14.  
    15. struct Neighbor
    16. {
    17.   uint n1;
    18.   uint n2;
    19.   uint n3;
    20.   uint n4;
    21.   uint n5;
    22.   uint n6;
    23.   uint n7;
    24.   uint n8;
    25. };
    26.  
    27.  
    28. struct Dist
    29. {
    30.   float d1;
    31.   float d2;
    32.   float d3;
    33.   float d4;
    34.   float d5;
    35.   float d6;
    36.   float d7;
    37.   float d8;
    38. };
    39.  
    40.  
    41. struct NeighborVert
    42. {
    43.   uint origin;
    44.   Neighbor neighbor;
    45.   Dist dist;
    46. };
    47.  
    48.  
    49. RWStructuredBuffer<NeighborVert> neighborVerts;
    50. RWStructuredBuffer<uint> controlled;
    51. RWStructuredBuffer<float3> pos;
    52. RWStructuredBuffer<float3> vel;
    53.  
    54.  
    55. float3 SpingForce(uint origin, uint neighbor, float dist)
    56. {
    57.   float3 originPos = pos[origin];
    58.   float3 neighborPos = pos[neighbor];
    59.  
    60.  
    61.   float3 r = neighborPos - originPos;
    62.   float3 force = normalize(r) * springK * (length(r) - dist);
    63.  
    64.  
    65.   return force;
    66. }
    67.  
    68.  
    69. [numthreads(8, 1, 1)]
    70. void Cloth (uint3 id : SV_DispatchThreadID)
    71. {
    72.   uint idx = id.x;
    73.   NeighborVert nv = neighborVerts[idx];
    74.  
    75.  
    76.   float3 f = gravity * particleMass;
    77.   float3 a;
    78.   float3 v = vel[idx];
    79.   float3 p = pos[idx];
    80.  
    81.  
    82.   if (controlled[idx] == 0)
    83.   {
    84.     if (nv.neighbor.n1 != -1) f += SpingForce(nv.origin, nv.neighbor.n1, nv.dist.d1);
    85.     if (nv.neighbor.n2 != -1) f += SpingForce(nv.origin, nv.neighbor.n2, nv.dist.d2);
    86.     if (nv.neighbor.n3 != -1) f += SpingForce(nv.origin, nv.neighbor.n3, nv.dist.d3);
    87.     if (nv.neighbor.n4 != -1) f += SpingForce(nv.origin, nv.neighbor.n4, nv.dist.d4);
    88.     if (nv.neighbor.n5 != -1) f += SpingForce(nv.origin, nv.neighbor.n5, nv.dist.d5);
    89.     if (nv.neighbor.n6 != -1) f += SpingForce(nv.origin, nv.neighbor.n6, nv.dist.d6);
    90.     if (nv.neighbor.n7 != -1) f += SpingForce(nv.origin, nv.neighbor.n7, nv.dist.d7);
    91.     if (nv.neighbor.n8 != -1) f += SpingForce(nv.origin, nv.neighbor.n8, nv.dist.d8);
    92.  
    93.  
    94.     // apply damping force
    95.     f += -damping * v;
    96.  
    97.  
    98.     // calculate acceleration using Newton's second law (f=ma)
    99.     a = f * invertParticleMass;
    100.     v += a * deltaT;
    101.     p += v * deltaT;
    102.     pos[idx] = p;
    103.     vel[idx] = v;
    104.   }
    105. }
    As you can see, all particles is controlled by a spring connected to each neighbor particles. The stiffness of the spring is defined by a spring constant
    springK

    To achieve a stable result for a high resolution mesh, you will need a very small deltaT and you will need to Dispatch this kernel alot of times.
     
  8. joshuacwilde

    joshuacwilde

    Joined:
    Feb 4, 2018
    Posts:
    40
    replace your spring force function with the following (taken from that website I sent you btw) :



    float timeStep = 1.0f / 60.0f;

    float3 originPos = pos[origin];
    float3 neighborPos = pos[neighbor];
    float3 r = neighborPos - originPos;
    float dist = length(r);
    float3 n = r * (1.0f / dist); //normal


    // get all of relative normal velocity
    float relNv = dot(vel[origin]-vel[neighbor], n);

    // remove all of it + resolve penetration over the course of some frames
    float remove = relNv + dist / timeStep; //time step is 1/60 if running at 60 fps
    float particleInvMass = 1.0f / particleMass;

    float imp = remove / (particleInvMass * 2.0f);

    // apply impulse
    vel[origin] += imp * n * particleInvMass ;
    vel[neighbor] -= imp * n * particleInvMass;



    obviously this isn't a force function anymore. you can change this to return void or recalculate the last two lines outside of the function.

    the main idea behind this is that you are changing the velocity directly, rather than changing the force.

    you might need to change the sign of the normal vector btw. this is all untested, but should work with a tweak or two ;)

    then you would also get rid of your force integration at the bottom of the Cloth function. but keep the velocity integration to get your new position

    also I would recommend trying to put your velocity integration (how you get your position) to a new function that is run after your cloth solver. Further, I would recommend creating this all in c# first. Debugging with compute shaders is really time consuming and probably not worth the effort when you are just starting with this. You can always port it back to compute shaders later.
     
  9. nyxaiot

    nyxaiot

    Joined:
    Oct 8, 2019
    Posts:
    10
    Hey thanks for replying with a solution! It seems that you are using a impulse force based solution to achieve more stable result! I really thank you for putting effort to help me! In the meantime, I also have been research for quite awhile already so I have come up with a solution proposed on a NVIDIA paper about Position Based Dynamics, let me briefly explain it here and once I got the code up and running I might post it here or at least post the base code XD.

    In PBD, we directly manipulate the position of the particles when solving constraints. The easiest example is the distance constraint:
    let m = mass of particle, d = rest length, w = 1/m, x = position of particle
    Imagine we have 2 particles constraint based on a distance d, then we can formulate 2 simple equation:
    1. delta x1 = 1/2 * (distance(x1, x2) - d) * -normalize(x1 - x2)
    2. delta x2 = 1/2 * (distance(x1, x2) - d) * normalize(x1 - x2)
    we divide into half by multiplying 1/2 because the constraint needs to be distributed to both particles, next we multiply the difference between particle distance and rest length to calculate how much displacement is needed in order to satisfy the distance constraint. Next we multiply the normalized difference of particles to get the direction of where the particle should go in 3D space. Hope this make sense!
     
  10. joshuacwilde

    joshuacwilde

    Joined:
    Feb 4, 2018
    Posts:
    40
    hey yeah I would be interested in looking at the PBD solver when you are done. Good luck!
     
    nyxaiot likes this.
unityunity