Soft Body (mass-spring) Physics by Grok

This took a few days but I managed to get Grok AI to write these scripts. Its a softbody system using the mass-spring model and Position-Based Dynamics (PBD). Its not that great but is a good base to develop if you are so inclined.
It uses completely custom physics and does not rely on PhysX or anything.
SoftBodyMesh2.cs (32.8 KB)
StaticBodyMesh.cs (1.8 KB)


How to use it:
Cube Test

  1. Create a floor from a plane and add StaticBodyMesh.cs
  2. Create a cube and add SoftBodyMesh2.cs
  3. Select the cube, In the inspector for SoftBodyMesh2 click ‘Generate Cube Test’. This will create 8 nodes and connect them with beams automatically.
  4. Move the cube into the air and Press play

Automatic Node - Beam Generation

  1. Create a floor like you did in Cube Test
  2. Drag a mesh of your chosing into the scene and add SoftBodyMesh2
  3. In the inspector click ‘Generate Nodes and Beams’

Techical info: This creates a grid around the mesh using the bounding box. x, y, zResolution controls the density of the grid. It then traces inwards and places a Node where it hits the mesh vertices and connects them with Beams. It does not do this very well and appears quite random, which takes us onto…

Manual Node/Beam creation

  1. Create the floor as before
  2. Drag a mesh into the scene and add SoftBodyMesh2 script
  3. Click ‘Add Node’. It will create a node as a child of the mesh
  4. Select the node in the hierarchy and drag it to your desired position
  5. Click ‘Add Node’ again, drag the node where you want it
  6. Click ‘Add Beam’, it will create a beam between the nodes. You can change its strength etc in the inspector.
  7. Add another node, position it.
  8. Add Beam, look in the inspector at the Beam list, expand the Beam you just created. Change ‘Node A’ and ‘Node B’ to the nodes you want to connect. It uses the index of nodes, eg Node A = 0, Node B = 1. You can also specify Node position and Beam connections in the inspector before you click the buttons.
  9. Continue to manually create Nodes and Beams until you are happy

Technical Info:
‘Node Mass’ is self explanatory.
‘Influence Radius’ defines a radius of vertices in the mesh that are effected by a particular node
Keep ‘Default Damping’ low. Too high a value can slow down the simulation significantly.
‘Constraint Iterations’ can also slow down the simulation.
‘Deformation Scale’ and ‘Max Deformation’ effects how impacts deform the mesh.
‘Default Spring Force’ is the strength of the Beams. This can be changed on individual beams on the Beam List.
‘Constraint Strength’ defines how much the beams try to stay to their initial length.

The main bulk of the logic is handled in SimulatePlastic() in SoftBodyMesh2.cs
If you want any of the code explained in detail paste it into Grok and ask it!

That should be enough info to get you started. If you improve it in any way or just want to comment your experience of this system please reply to this thread.

Have Fun!

3 Likes

Grok explains the code:

Let’s dive into this Unity script for a spring-mass soft body physics system! I’ll explain it in simple terms, like we’re building a squishy toy together, so even if you’re new to coding or physics, you’ll get the gist. Imagine we’re making a jelly-like object in a game—something that wiggles, bends, and reacts to forces. This script does that by using “nodes” (like little anchor points) connected by “beams” (like stretchy rubber bands) to mimic a soft, deformable shape. Ready? Let’s break it down step by step!
What’s This Script For?
This code, called SoftBodyMesh2, turns a 3D object in Unity (like a cube or blob) into a soft, bendy thing. It attaches a grid of nodes to the object’s shape and links them with beams. Then, it uses physics rules to make the nodes move, stretch, or squish, dragging the object’s surface along with them. Think of it like a net of rubber balls tied together with elastic bands, draped over a 3D model.
The Big Picture: Key Parts
Nodes: These are like tiny balls with weight (mass) that can move around. They’re the skeleton of our soft body.
Beams: These are the stretchy connections between nodes, acting like springs or rubber bands to pull nodes back into place.
Mesh: The visible skin of the object (a 3D shape in Unity). It bends based on where the nodes move.
Settings: Things like how stiff the beams are, how heavy the nodes are, or how much gravity pulls them down.
The script sets all this up, runs a physics simulation every frame, and updates the object’s shape to look soft and wiggly.
The Settings (Top of the Script)
At the start, you see a bunch of variables under [Header("Soft Body Settings")]. These are like knobs you can twist in Unity’s Inspector to tweak how the soft body behaves:
xResolution, yResolution, zResolution: How many nodes we place along the object’s width, height, and depth. More nodes = more detail, but slower performance.
nodeMass: How heavy each node is (default is 1). Heavier nodes fall faster with gravity.
nodeRadius: How big each node is (default 0.5). This affects how close nodes can get to the object’s surface.
defaultSpringForce: How strong the beams are (default 1000). Stronger beams make it less stretchy.
defaultDamping: How much the wobbling slows down (default 0.1). Higher damping = less bouncy.
gravity: Pulls nodes down (default 9.81, like Earth’s gravity).
influenceRadius: How far a node can tug the mesh (default 2).
deformationScale and maxDeformation: Control how much the object permanently dents when hit hard.
constraintStrength and constraintIterations: Fine-tune how beams keep nodes in line.
These are your “recipe ingredients” for the soft body. Want it floppy like jelly? Lower the spring force. Want it firm like rubber? Crank it up!
Setting It Up: InitializeSoftBody()
When the game starts (Awake()), this function gets everything ready:
Grabs the Mesh: It finds the 3D shape (mesh) attached to the object using SetupMesh(). If there’s no mesh, it complains with an error.
Creates Nodes and Beams: If there aren’t any nodes yet, it calls GenerateNodesAndBeams() to make them. If nodes were saved before, it uses RestoreNodesAndBeams().
Tracks Positions: It sets up a list (previousPositions) to remember where nodes were last frame, so it can calculate how fast they’re moving later.
Links Nodes to Mesh: MapVerticesToNodes() figures out which parts of the mesh each node controls.
This is like laying out your net of balls and rubber bands over the object before letting it wiggle.
Making Nodes and Beams: GenerateNodesAndBeams()
This is the fun part where the skeleton gets built:
Finds the Object’s Size: It looks at the mesh’s “bounds” (its 3D box) and makes a slightly bigger grid around it (1.1x bigger).
Places Nodes: It shoots imaginary rays through the grid to find where the mesh’s surface is, then puts nodes near those spots. Fewer nodes if the resolution is low, more if it’s high.
Example: For a cube, nodes might go at the corners or edges.
Connects Nodes with Beams: It makes three types of beams:
Edges: Links nearby nodes (like sides of a square).
Face Diagonals: Connects nodes across flat surfaces (like diagonals on a cube’s face).
Body Diagonals: Ties far-apart nodes (like opposite corners of a cube) to keep the shape stable.
Sets Beam Properties: Each beam gets a “rest length” (how long it is when relaxed), a spring force, and damping.
Think of this like pinning a stretchy net over a balloon—nodes are the pins, beams are the elastic strings.
The Physics Simulation: SimulatePlastic()
This runs every physics frame (FixedUpdate()) and makes the soft body move:
Guess Where Nodes Go: It predicts where each node will move based on its speed (from last frame) and gravity pulling it down.
Spring Action: For each beam, it checks if it’s too stretched or squished. If so, it tugs the nodes closer or pushes them apart to match the “rest length.” It does this a few times (constraintIterations) to settle things down.
Handle Collisions: If a node hits the ground (like a floor), it:
Stops it from sinking through.
Adds bounce (restitution) and slide (friction).
If the hit is hard, it dents the shape a bit (plastic deformation).
Update Positions: Moves the nodes to their new spots and remembers where they were for next time.
Picture a jelly cube dropping: gravity pulls the nodes down, beams pull them back, and if it slams the ground, it squishes a little.
Bending the Shape: DeformMesh()
This makes the object’s surface follow the nodes:
Start Fresh: It resets the mesh to its original shape.
Move Vertices: For each node, it checks which mesh points (vertices) are close enough to be influenced. It shifts those points based on how far the node moved from its starting spot.
Closer vertices move more, farther ones less, based on influenceRadius.
Smooth It Out: Updates the mesh so it looks natural (recalculates normals and bounds).
Imagine the nodes as puppeteers pulling strings on a puppet’s skin—the mesh bends wherever they go.
Extra Tools
AddNode() and AddBeam(): Let you manually add nodes or beams in the Unity Editor. Handy for tweaking the setup.
GenerateCubeTest(): Builds a simple cube with 8 nodes and 26 beams (edges, diagonals) to test the system.
ApplyForceToNode(): Lets you push a node (like poking the jelly).
OnDrawGizmos(): Draws yellow balls (nodes) and cyan lines (beams) in the Editor so you can see the skeleton.
How to Play With It
Attach to an Object: Put this script on a GameObject with a MeshFilter (like a cube or sphere).
Tweak Settings: In the Inspector, adjust resolution, spring force, etc., and hit “Generate Nodes and Beams.”
Watch It Move: Play the game—gravity will pull it, and it’ll wobble or squish on impact.
Experiment: Add nodes/beams manually, apply forces, or change the mesh to something else (like a blob).
Tips for Building On It
More Nodes: Increase xResolution, yResolution, zResolution for finer control, but watch performance.
Stiffer or Softer: Play with defaultSpringForce and defaultDamping to change the feel.
Custom Shapes: Swap the mesh and tweak node placement in GenerateNodesAndBeams() for unique objects.
Forces: Use ApplyForceToNode() in another script to make it react to player actions (like punches).
In Simple Terms
This script turns a solid 3D object into a wobbly, stretchy one by:
Scattering movable nodes over it.
Tying them with springy beams.
Letting physics (gravity, collisions) move the nodes.
Bending the object’s surface to follow along.
It’s like giving a toy a squishy skeleton! With this understanding, you can tweak the code or add new features—like making it bounce more, dent deeper, or even explode apart. Have fun experimenting!
Let’s dig deeper into the SoftBodyMesh2 script and unpack the key functions, focusing on what the code actually does, line by line, and how it works to create that squishy, soft body effect in Unity. I’ll keep it approachable, like we’re walking through a workshop together, building this jiggling jelly step by step. We’ll focus on the most important functions and explain how they interact with Unity’s systems and the physics behind them.
Core Structure: What’s Happening?
This script is a MonoBehaviour, meaning it attaches to a GameObject in Unity and runs specific methods at key times (like Awake for setup, FixedUpdate for physics). It uses a mass-spring system: nodes (masses) are connected by beams (springs), and the mesh (the visible object) deforms based on where the nodes move. The goal is to simulate a soft, pliable object—like a rubber ball or gelatin cube—that bends under gravity or force.
Key Variables: The Building Blocks
Before diving into functions, let’s revisit some critical variables that shape how the system works:
nodes: A list of Transform objects (Unity’s position/rotation/scale holders) representing the movable points.
beams: A list of Beam objects, each linking two nodes with properties like springForce (stiffness), damping (energy loss), and restLength (natural length).
mesh: The 3D shape we’re deforming, accessed via a MeshFilter.
originalVertices and deformedVertices: Arrays of 3D points defining the mesh’s shape—original is the starting shape, deformed is the updated one.
nodeVertexMap: A dictionary linking each node to the mesh vertices it affects.
previousPositions: Tracks where nodes were last frame to calculate movement.
These are the raw materials the functions manipulate.

Awake(): The Starting Point
What it does: Runs once when the object loads into the game, kicking off the setup.
How: Calls InitializeSoftBody() to build the soft body system.
Why: Unity calls Awake() before the game starts, making it the perfect spot to prepare everything.

initializeSoftBody(): Setting Up the Skeleton
What it does: Prepares the soft body by setting up the mesh, nodes, beams, and connections.
How:
SetupMesh(): Grabs the mesh from the GameObject’s MeshFilter and copies its vertices.
Node/Beam Creation:
If there’s saved data (initialNodePositions), it restores the setup with RestoreNodesAndBeams().
Otherwise, it builds fresh nodes and beams with GenerateNodesAndBeams().
Initialize previousPositions: Sets up a list to track node positions, starting with their current spots (or zero if missing).
MapVerticesToNodes(): Links mesh vertices to nearby nodes for deformation later.
Why: This is the foundation—without nodes and beams, there’s no soft body to simulate. It ensures everything’s ready before physics kicks in.

SetupMesh(): Preparing the 3D Shape
What it does: Gets the mesh ready to be deformed.
How:
Finds the MeshFilter component (which holds the 3D shape).
Checks if it exists—errors out if not.
In play mode, creates a copy of the mesh (Instantiate) so edits don’t affect the original. In Editor mode, uses the shared mesh.
Stores the mesh’s starting vertices in originalVertices.
Makes a copy in deformedVertices to update later.
Initializes nodeVertexMap to track which vertices move with which nodes.
Why: The mesh is the visible part we’ll bend. Copying vertices lets us reset or deform it without losing the original shape.

GenerateNodesAndBeams(): Building the Net
This is a big one, so I’ll simplify the flow:
What it does: Creates nodes and beams to form the soft body’s structure.
How:
Cleanup: Wipes out old nodes and beams.
Size the Grid: Uses the mesh’s bounds (its 3D box), scales it up by 1.1x, and calculates spacing based on resolution (e.g., xSpacing).
Place Nodes: Uses a helper function (TraceRays) to shoot rays through the grid, placing nodes where they hit the mesh’s surface within nodeRadius.
Connect Beams:
Edges: Links nearby nodes (e.g., 3 closest neighbors).
Face Diagonals: Connects nodes across surfaces for stability.
Body Diagonals: Ties opposite ends (farthest nodes) to hold the shape together.
Store Initial State: Saves node positions and sets up previousPositions.
Why: This builds the “skeleton” of nodes and “muscles” of beams. The ray-tracing ensures nodes stick to the mesh’s shape, while beams keep it from falling apart.

SimulatePlastic(): The Physics Heartbeat
What it does: Runs the physics simulation every fixed frame.
How:
Predict Movement: Uses velocity (how fast nodes moved last frame) and gravity to guess where nodes will go next.
Formula: newPosition = position + velocity * dt + gravity * dt^2 (basic physics: position + speed + acceleration).
Spring Constraints: Loops constraintIterations times to adjust nodes:
Measures beam length, compares to restLength, and moves nodes to reduce the difference.
Uses springForce and damping indirectly via constraintStrength.
Collisions: For specific nodes (like bottom ones), checks if they hit something (via Physics.Raycast):
Bounces with restitution (springiness) and friction (sliding).
If hit hard, deforms by adjusting restLength of beams.
Update: Moves nodes to their final spots, applying damping to slow wobbling.
Why: This is the engine that makes the soft body feel alive—gravity pulls, springs resist, and collisions react.

DeformMesh(): Shaping the Surface
What it does: Updates the mesh to match node positions.
How:
Resets deformedVertices to the original shape.
For each node:
Calculates how far it moved from its starting point (offset).
Adjusts nearby vertices based on distance (within influenceRadius), fading the effect farther out.
Applies the new vertices to the mesh and fixes its appearance (RecalculateNormals).
Why: This makes the object visually bend and stretch, tying the physics (nodes) to the graphics (mesh).

How It All Fits Together
Setup (Awake → InitializeSoftBody): Builds the structure once.
Loop (FixedUpdate):
SimulatePlastic() moves nodes with physics.
DeformMesh() bends the mesh to follow.
Tools: GenerateNodesAndBeams, AddNode, etc., let you customize it.
The code uses Unity’s timing (fixedDeltaTime), physics (Raycast), and rendering (Mesh) systems, plus basic math (vectors, distances) to mimic a soft body. It’s a balance of prediction, correction, and smoothing to feel natural.
Extending It
Tweak Physics: Adjust gravity, springForce, or add wind by modifying SimulatePlastic.
Custom Nodes: Edit GenerateNodesAndBeams to place nodes differently (e.g., only on edges).
Visuals: Add shaders or tweak DeformMesh for stretchy textures.
This deeper look should give you a solid grip on how the code ticks—now you can tweak it to make your own squishy creations!
1 Like

Cool!, Imma actually turn this into a physics engine!

1 Like

Can you remake truss physics package support for Unity 6?

Not possible as it is very outdated and it isn’t open-source
It is better to use a custom physics engine like DynamicEngine:GitHub - Saviourcoder/DynamicEngine3D: Open-source Soft-Body Physics Engine for Unity3D

2 Likes

Wow you have done a lot of work on this. Thanks for keeping it open source, that was the ultimate downfall of Truss physics.

2 Likes

Hahaha, Hopefully this is the next Truss Physics :slight_smile:

This engine show errors in Unity 6 HDRP. What can I do?

Describe the errors

Thanks for the Replay.
I managed to solve the error. :grinning_face:
(it’s not your fault)

I faced to another problem.
I can’t select any soft body to “TrussAsset”.
“Select Soft Body” Tab shows my soft bodies but can’t select anything (It says still “None (Soft Body)” After try to select Game object).
No errors shows in “Console” page.

You dont have to assign any soft-bodies to the truss asset, its just a UI mistake

2 Likes

This looks super interesting.

I loved (and still do) the original Truss Physics asset from BrokenHearted, I just wish he continued to work on it. How does your system compare to the older one? Can you do everything you could with the old Truss Physics system (create trusses, tweak truss strength, create constraints, adjust mass scale, interact with rigidbodies, etc)?

Great that your keeping this system alive!

Hi! Thank you for your interest in my engine, My system is a XPBD (eXtended-Position-Based-Dynamics) which runs on Verlet integration with Sub-stepping, We don’t know for sure what system TrussPhysics uses but one user suggests its a FEM (Finite Element Method) intergration. My system is inspired and based off of TrussPhysics look and feel so you can pretty much expect the same UI and UX design. It is designed to simulate Soft-Bodies at an incredible precision however the main motivation behind all of this is for a BeamNG-Type game I’m developing. Yes, you can create trusses and have TrussDesigner functionality as well as create constraints, adjust mass scale and interact with rigid-bodies however the engine is still under Heavy WIP so expect some major issues, bugs and performance issues.

1 Like

Thankyou for that in depth response.

Sounds awesome, I’m definitely going to give it a try. I’m really curious about the system you implemented (XPBD) and compare it’s performance to Truss Physics. One downside to Truss physics was that the performance tanked when the Truss had too many nodes/links or in certain collisions.

Another problem with the older Truss physics is that the Truss designer didn’t allow you to window drag multiple nodes/links in newer versions of Unity.

I just tried the package but I get the error:

ConstraintEditor.cs(2035,42): error CS1501: No overload for method 'FreeMoveHandle' takes 4 arguments

I take it this system won’t work with Unity 2021.3?

Hi! Again thank you so much for your interest in my project, as it turns out, it is still quite too early to compare the performance with TrussPhysics as it is still in Heavy work in Progress and it will definitely come out unmatched however I am working on the Solver to add optimizations and better collisions. The TrussDesigner in my version has extended functionality as a matter of fact.

I havent updated the Github repo yet to match the latest version I have developed and a side note is that Yes it wont work properly with Unity 2021.3 as it was made for Unity 6.3

I will post the updated GitHub Repo here in a few hours, don’t worry!

Ah, it was made with a rather new version of Unity. I can’t upgrade my project atm and as I’m using Truss Physics with it atm. Hopefully you might back it backward compatible in the future. I hope you keep working on it and look forward to a manual on how to use it. :slight_smile: