Soft body simulation toy ^^

h4tt3n
Posts: 691
Joined: Oct 22, 2005 21:12
Location: Denmark

Soft body simulation toy ^^

Here's a little thing I stirred up. Soft body simulation with lots of interaction possibilities.

It is based on the following paper. The code examples in the paper are heavily un-optimized, so I fixed it. There's also an error in the volume calculation, so I replaced that with a standard polygon area algorithm.

Have fun!

http://panoramix.ift.uni.wroc.pl/~maq/s ... ftbody.pdf

Cheers Michael

Code: Select all

`'******************************************************************************'''   Soft body simulation. Michael "h4tt3n" Nissen, march 2008'   Press left mouse to pick up body and drag it around. '   Press Right mouse to prod soft body around with ball obstacle.'   Use left / right to decrease / incresase body pressure'   Use up / down to increase / decrease body sircumference'   (Press esc to quit)''******************************************************************************'''  set constants. experiment with these and see how the simulation reactsConst Pi                =     4*Atn(1)  ''  pi (better not change ^^)Const dt                =     0.01      ''  timestep, delta timeConst Prod_Radius       =     50Const Num_Masses        =     64        ''  number of masses in ropeConst Num_Obstacles     =     4Const Point_Mass        =     1         ''  mass of each point massConst Ks                =     8000      ''  spring stiffnesConst Kld               =     6         ''  linear spring dampingConst Kad               =     8         ''  angular spring damping (beta)Const Kps               =     10        ''  mouse-body pick up springConst Kpd               =     0.1       ''  mouse-body spring dampingConst Grav_Acc          =     800       ''  gravitational accelerationConst Wall_Friction     =     0.85      ''  friction force on wall contactConst Pick_mindist      =     25        ''  pick up mass within distanceDim As Single Ball_Radius     = 150        ''  ideal radius of soft bodyDim As Single Rest_Len        = (Ball_Radius*2*Pi)/Num_MassesDim As Single P               =     5000000   ''  pressure constantRandomize Timer''  define typesType Vector_Type  As Single X, YEnd TypeType Mass_Type  As Single Mass  As Vector_Type Frc, Acc, Vel, PosEnd Type Type Spring_Type  As Integer a, b  As Single Length  As Vector_Type normal, Lng_Hat, VelEnd TypeType Obstacle_Type  As Vector_Type Pos  As Integer RadiusEnd TypeDim As Vector_Type Dist, center_of_massDim As Mass_Type Mass(1 to Num_Masses)Dim As Spring_Type Spring(1 To Num_Masses)Dim As Obstacle_Type Obstacle(1 To Num_Obstacles)Dim As Single Force, temp_dist, distance, DampingDim As Integer i, j, x, y, Scrn_Wid, Scrn_Hgt, Area, Pressure, mouse_x, mouse_y, mouse_btn, pick_state, pickedScrn_Wid = 800Scrn_Hgt = 600ScreenRes Scrn_Wid, Scrn_hgt, 16For i = Lbound(Mass) To Ubound(Mass)  With Mass(i)    .Mass = Point_Mass    .pos.X = scrn_wid\2 + Ball_Radius*Cos(2*Pi*(i/Num_Masses))    .pos.Y = scrn_hgt\3 + Ball_Radius*Sin(2*Pi*(i/Num_Masses))  End With  With Spring(i)    j = i+1    If j > Num_Masses Then j -= Num_Masses    .a = i    .b = j  End WithNextFor i = Lbound(Obstacle) To Ubound(Obstacle)  With Obstacle(i)    .Radius = ((Scrn_Wid/Num_Obstacles)/3)    .Radius -= .Radius*Rnd*0.1    .Pos.X = i*(Scrn_Wid/(Num_Obstacles+1))    .Pos.Y = Scrn_Hgt-(.Radius+10+(Rnd*50))  End WithNextDo    Area = 0  Center_Of_Mass.x = 0  Center_Of_Mass.y = 0    ''  up arrow  If Multikey(&h48) Then    Ball_Radius += 0.1    Rest_Len = (Ball_Radius*2*Pi)/Num_Masses  End If  ''  down arrow  If Multikey(&h50) Then    Ball_Radius -= 0.1    Rest_Len = (Ball_Radius*2*Pi)/Num_Masses  End If  ''  left arrow  If Multikey(&h4b) Then    P /= 1.001  End If  ''  Right arrow  If Multikey(&h4d) Then    P *= 1.001  End If    Getmouse Mouse_X, Mouse_Y,, Mouse_Btn    ''  pick up point mass on leftmouse  If Mouse_Btn = 1 Then        If Pick_State = 0 Then            Temp_Dist = Pick_MinDist            For i = Lbound(mass) To Ubound(mass)                 Dist.X = mass(i).Pos.X-Mouse_X        Dist.Y = mass(i).Pos.Y-Mouse_Y        Distance = Sqr(Dist.X*Dist.X+Dist.Y*Dist.Y)                If Distance < Temp_Dist Then                     Temp_Dist = Distance          Picked = i                  End If              Next            If Picked <> -1 Then                Pick_State = 1              End If          Else            With Mass(Picked)                Dist.X = .Pos.X-Mouse_X        Dist.Y = .Pos.Y-Mouse_Y        Distance = Sqr(Dist.X*Dist.X+Dist.Y*Dist.Y)                Force = -Kps*Distance-Kpd*((Dist.X*.Vel.X+Dist.Y*.Vel.Y)/Distance)                Mass(Picked).Frc.X += Force*Dist.X        Mass(Picked).Frc.Y += Force*Dist.Y              End With          End If      Else        Pick_State = 0    Picked = -1      End If    ''  prod body around on right mouse  If Mouse_Btn = 2 Then        Pick_State = 0    Picked = -1        For i = Lbound(mass) To Ubound(mass)             Dist.X = mass(i).Pos.X-Mouse_X      Dist.Y = mass(i).Pos.Y-Mouse_Y      Distance = Sqr(Dist.X*Dist.X+Dist.Y*Dist.Y)            If Distance < Prod_Radius Then                 With Mass(i)                    Force = -200*(Distance-Prod_Radius)-0.5*((Dist.X*.Vel.X+Dist.Y*.Vel.Y)/Distance)                    .Frc.X += Force*Dist.X          .Frc.Y += Force*Dist.Y                    .Vel.X *= Wall_Friction          .Vel.Y *= Wall_Friction                  End With              End If          Next      End If    ''  calculate spring force, area, and center of mass  For i = Lbound(Spring) To Ubound(Spring)        With Spring(i)            Dist.X = Mass(.b).Pos.X-Mass(.a).Pos.X      Dist.Y = Mass(.b).Pos.Y-Mass(.a).Pos.Y      .Length = Sqr(Dist.X*Dist.X+Dist.Y*Dist.Y)            .Lng_Hat.X = Dist.X/.Length      .Lng_Hat.Y = Dist.Y/.Length            Area += Mass(.a).Pos.X*Mass(.b).Pos.Y-Mass(.b).Pos.X*Mass(.a).Pos.Y            Center_Of_Mass.X += (Mass(.a).Pos.X+Mass(.b).Pos.X)*(Mass(.a).Pos.X*Mass(.b).Pos.Y-Mass(.b).Pos.X*Mass(.a).Pos.Y)      Center_Of_Mass.Y += (Mass(.a).Pos.Y+Mass(.b).Pos.Y)*(Mass(.a).Pos.X*Mass(.b).Pos.Y-Mass(.b).Pos.X*Mass(.a).Pos.Y)            .Vel.X = Mass(.b).Vel.X-Mass(.a).Vel.X      .Vel.Y = Mass(.b).Vel.Y-Mass(.a).Vel.Y            Force = -Ks*(.Length-Rest_Len)-Kld*(.Lng_Hat.X*.Vel.X+.Lng_Hat.Y*.Vel.Y)            Mass(.a).Frc.X -= Force*.Lng_Hat.X      Mass(.a).Frc.Y -= Force*.Lng_Hat.Y      Mass(.b).Frc.X += Force*.Lng_Hat.X      Mass(.b).Frc.Y += Force*.Lng_Hat.Y          End With      Next    ''  finish calculation of area, pressire and COM  Area *= 0.5  Pressure = P/Area  Center_Of_Mass.X *= 1/(6*Area)  Center_Of_Mass.Y *= 1/(6*Area)    ''  calculate pressure force  For i = Lbound(Spring) To Ubound(Spring)        With Spring(i)            Force = .Length*Pressure      Damping = -Kad*(.Lng_Hat.X*.Vel.Y-.Lng_Hat.Y*.Vel.X)            Mass(.a).Frc.X += (Force+Damping)*.Lng_Hat.Y      Mass(.a).Frc.Y += (Force+Damping)*-.Lng_Hat.X      Mass(.b).Frc.X += (Force-Damping)*.Lng_Hat.Y      Mass(.b).Frc.Y += (Force-Damping)*-.Lng_Hat.X          End With      Next    ''  body-obstacle collision  For i = Lbound(mass) To Ubound(mass)         For j = Lbound(Obstacle) To Ubound(Obstacle)            Dist.X = mass(i).Pos.X-Obstacle(j).Pos.X      Dist.Y = mass(i).Pos.Y-Obstacle(j).Pos.Y      Distance = Sqr(Dist.X*Dist.X+Dist.Y*Dist.Y)            If Distance < Obstacle(j).Radius Then                 With Mass(i)                    Force = -200*(Distance-Obstacle(j).Radius)-0.2*((Dist.X*.Vel.X+Dist.Y*.Vel.Y)/Distance)                    .Frc.X += Force*Dist.X          .Frc.Y += Force*Dist.Y                    .Vel.X *= Wall_Friction          .Vel.Y *= Wall_Friction                  End With              End If          Next      Next  ''  integrate  For i = Lbound(Mass) To Ubound(Mass)        With Mass(i)            .Acc.X = .Frc.X/.mass      .Acc.Y = .Frc.Y/.mass            .Acc.Y += Grav_Acc            .Vel.X += .Acc.X*dt      .Vel.Y += .Acc.Y*dt            .Pos.X += .Vel.X*dt      .Pos.Y += .Vel.Y*dt            .frc.x = 0      .frc.y = 0          End With      Next    ''  screen boundaries  For i = Lbound(Mass) To Ubound(Mass)        With Mass(i)            ''  right      If .Pos.x > Scrn_Wid-1 Then        .Vel.X = -.vel.x        .pos.x = Scrn_Wid-1        .Vel.X *= wall_friction        .Vel.Y *= wall_friction      End If      ''  left      If .Pos.x < 1 Then        .Vel.X = -.vel.x        .pos.x = 1        .Vel.X *= wall_friction        .Vel.Y *= wall_friction      End If      ''  bottom      If .Pos.Y > Scrn_Hgt-1 Then        .vel.y = -.vel.y        .pos.y = Scrn_Hgt-1        .Vel.X *= wall_friction        .Vel.Y *= wall_friction      End If      ''  top      If .Pos.Y < 1 Then        .vel.y = -.vel.y        .pos.y = 1        .Vel.X *= wall_friction        .Vel.Y *= wall_friction      End If          End With      Next    ''  render to screen  ScreenLock        Cls        For i = Lbound(Spring) To Ubound(Spring)            With Spring(i)                Line _          (Mass(.a).Pos.X, Mass(.a).Pos.Y)-_          (Mass(.b).Pos.X, Mass(.b).Pos.Y), _          Rgb(64, 255, 64)                End With          Next        For i = Lbound(Obstacle) To Ubound(Obstacle)            With Obstacle(i)                Circle(.Pos.X, .Pos.Y), .Radius, RGB(255, 64, 64),,,1              End With          Next        Line _      (Center_Of_Mass.x, Center_Of_Mass.Y)-_      (Mass(1).Pos.X, Mass(1).Pos.Y), _      Rgb(32, 128, 32)        If Pick_State = 1 Then            Line _      (Mouse_x, Mouse_Y)-_      (Mass(Picked).Pos.X, Mass(Picked).Pos.Y), _      Rgb(255, 64, 64)          End If        If Mouse_Btn = 2 Then            Circle(Mouse_X, Mouse_Y), Prod_Radius, RGB(255, 64, 64),,,1          End If        Locate 2, 1: Print Using " Pressure coeff. : ########.##"; P    Locate 3, 1: Print Using " Ball Radius     : ########.##"; Ball_Radius      ScreenUnlock    Sleep 1, 1  Loop Until Multikey(1)End`

And here's a stripped down version with just the physics:

Code: Select all

`'******************************************************************************'''   Soft body simulation. Michael "h4tt3n" Nissen, march 2008''   (Press esc to quit)''******************************************************************************'''  set constants. experiment with these and see how the simulation reactsConst Pi                =     4*Atn(1)  ''  pi (better not change ^^)Const dt                =     0.01      ''  timestep, delta timeConst Num_Masses        =     32        ''  number of masses in bodyConst Point_Mass        =     1         ''  mass of each point massConst Ks                =     8000      ''  spring stiffnesConst Kld               =     6         ''  linear spring dampingConst Grav_Acc          =     800       ''  gravitational accelerationConst Wall_Friction     =     0.85      ''  friction force on wall contactConst Ball_Radius       =     150       ''  ideal radius of soft bodyConst Rest_Len          =     (Ball_Radius*2*Pi)/Num_Masses ''spring rest lengthConst P                 =     5000000   ''  pressure constant''  define typesType Vector_Type  As Single X, YEnd TypeType Mass_Type  As Single Mass  As Vector_Type Frc, Acc, Vel, PosEnd Type Type Spring_Type  As Integer a, b  As Single Length  As Vector_Type normal, Lng_Hat, VelEnd TypeDim As Vector_Type DistDim As Mass_Type Mass(1 to Num_Masses)Dim As Spring_Type Spring(1 To Num_Masses)Dim As Single ForceDim As Integer i, j, Scrn_Wid, Scrn_Hgt, Area, PressureScrn_Wid = 800Scrn_Hgt = 600ScreenRes Scrn_Wid, Scrn_hgt, 16For i = Lbound(Mass) To Ubound(Mass)  With Mass(i)    .Mass = Point_Mass    .pos.X = scrn_wid\2 + Ball_Radius*Cos(2*Pi*(i/Num_Masses))    .pos.Y = scrn_hgt\3 + Ball_Radius*Sin(2*Pi*(i/Num_Masses))  End With  With Spring(i)    j = i+1    If j > Num_Masses Then j -= Num_Masses    .a = i    .b = j  End WithNextDo    ''  reset area  Area = 0    ''  spring force and damping, area of soft body  For i = Lbound(Spring) To Ubound(Spring)        With Spring(i)            Dist.X = Mass(.b).Pos.X-Mass(.a).Pos.X      Dist.Y = Mass(.b).Pos.Y-Mass(.a).Pos.Y      .Length = Sqr(Dist.X*Dist.X+Dist.Y*Dist.Y)            ''  unit normal vector      .Lng_Hat.X = Dist.X/.Length      .Lng_Hat.Y = Dist.Y/.Length            Area += Mass(.a).Pos.X*Mass(.b).Pos.Y-Mass(.b).Pos.X*Mass(.a).Pos.Y            .Vel.X = Mass(.b).Vel.X-Mass(.a).Vel.X      .Vel.Y = Mass(.b).Vel.Y-Mass(.a).Vel.Y            Force = -Ks*(.Length-Rest_Len)-Kld*(.Lng_Hat.X*.Vel.X+.Lng_Hat.Y*.Vel.Y)            Mass(.a).Frc.X -= Force*.Lng_Hat.X      Mass(.a).Frc.Y -= Force*.Lng_Hat.Y      Mass(.b).Frc.X += Force*.Lng_Hat.X      Mass(.b).Frc.Y += Force*.Lng_Hat.Y          End With      Next    ''  finish area of soft body, pressure  Area *= 0.5  Pressure = P/Area    ''  pressure force normal to springs  For i = Lbound(Spring) To Ubound(Spring)        With Spring(i)            Force = .Length*Pressure            Mass(.a).Frc.X += Force*.Lng_Hat.Y      Mass(.a).Frc.Y += Force*-.Lng_Hat.X      Mass(.b).Frc.X += Force*.Lng_Hat.Y      Mass(.b).Frc.Y += Force*-.Lng_Hat.X          End With      Next  ''  integrate  For i = Lbound(Mass) To Ubound(Mass)        With Mass(i)            .Acc.X = .Frc.X/.mass      .Acc.Y = .Frc.Y/.mass            .Acc.Y += Grav_Acc            .Vel.X += .Acc.X*dt      .Vel.Y += .Acc.Y*dt            .Pos.X += .Vel.X*dt      .Pos.Y += .Vel.Y*dt            .frc.x = 0      .frc.y = 0          End With      Next    ''  screen boundaries  For i = Lbound(Mass) To Ubound(Mass)        With Mass(i)            ''  right      If .Pos.x > Scrn_Wid-1 Then        .Vel.X = -.vel.x        .pos.x = Scrn_Wid-1        .Vel.X *= wall_friction        .Vel.Y *= wall_friction      End If      ''  left      If .Pos.x < 1 Then        .Vel.X = -.vel.x        .pos.x = 1        .Vel.X *= wall_friction        .Vel.Y *= wall_friction      End If      ''  bottom      If .Pos.Y > Scrn_Hgt-1 Then        .vel.y = -.vel.y        .pos.y = Scrn_Hgt-1        .Vel.X *= wall_friction        .Vel.Y *= wall_friction      End If      ''  top      If .Pos.Y < 1 Then        .vel.y = -.vel.y        .pos.y = 1        .Vel.X *= wall_friction        .Vel.Y *= wall_friction      End If          End With      Next    ''  draw to screen  ScreenLock        Cls        For i = Lbound(Spring) To Ubound(Spring)            With Spring(i)                Line _          (Mass(.a).Pos.X, Mass(.a).Pos.Y)-_          (Mass(.b).Pos.X, Mass(.b).Pos.Y), _          Rgb(64, 255, 64)                End With          Next      ScreenUnlock    Sleep 1, 1  Loop Until Multikey(1)End`
Last edited by h4tt3n on Mar 12, 2008 23:47, edited 2 times in total.
Posts: 469
Joined: Dec 17, 2006 23:37
Contact:
Rah that's awesome !

Really funny toy :p
DaveUnit
Posts: 239
Joined: Apr 20, 2006 15:47
Location: Central MA
Contact:
that's f*cking awesome.
KristopherWindsor
Posts: 2428
Joined: Jul 19, 2006 19:17
Location: Sunnyvale, CA
Contact:
Nice! :-)

I managed to subdue the blob:

:-P
h4tt3n
Posts: 691
Joined: Oct 22, 2005 21:12
Location: Denmark
Ah well, there's still no self-collision or anything. Once I get that added you won't be able to do that. And then you can have several blobs crawling on top of each other ^^

Maybe a cool game could be based on this. Like Gish... Or like a really weird pong game :/ ... catch the bogeyman... 8-S

Anyway, If you're intereted I've posted a stripped down example with just the necessary physics in the ip.
Lachie Dazdarian
Posts: 2338
Joined: May 31, 2005 9:59
Location: Croatia
Contact:
Yeah, this is really cool.

If I only knew how to exploit this code.
h4tt3n
Posts: 691
Joined: Oct 22, 2005 21:12
Location: Denmark
Hey, if you don't understand my crappy code, just ask. The theory behind all this is fairly simple, it just looks a tad messy in code form.
integer
Posts: 386
Joined: Feb 01, 2007 16:54
Location: usa
...this is really cool.

...that's awesome !

that's f*cking awesome.

ditto
Dr_D
Posts: 2392
Joined: May 27, 2005 4:59
Contact:
Nice. ;)
anonymous1337
Posts: 5494
Joined: Sep 12, 2005 20:06
Location: California
Kill me for thinking naughty thoughts when I read the thread title as well as when I read "ditto".

;_;... Anyways awesome program :D
Lachie Dazdarian
Posts: 2338
Joined: May 31, 2005 9:59
Location: Croatia
Contact:
Yeah....soft...bodey. :P

Anyway, it's not that I don't understand your code h4tt3n. It just, I have no idea how to make something of it...like, a playable game.
DaveUnit
Posts: 239
Joined: Apr 20, 2006 15:47
Location: Central MA
Contact:
If you could find a way to use it, you could make a game similar to Loco Roco.
http://en.wikipedia.org/wiki/LocoRoco
h4tt3n
Posts: 691
Joined: Oct 22, 2005 21:12
Location: Denmark
anonymous1337 you... you... ewww! >X-C

Anyway check out this site for physics based games

http://www.fun-motion.com

especially the game Gish, which has a blob main character a bit like the one in my demo.
Merick
Posts: 1038
Joined: May 28, 2007 1:52
indigo
Posts: 2
Joined: Mar 10, 2008 11:00
Location: Greece
This is very fun to watch! Good job h4tt3n!!! ;)