Cloth physics simulation

I’m not going to deeply explain how to create cloth simulation, but I will publish the one I made, which you can see in this video: https://www.youtube.com/watch?v=U5j8l4_o288 Mainly publishing this because the way it works is pretty bad in my opinion and its almost a year old now.

The basics

You simply need a mesh with TONS of bones (110 in my model) and a pretty simple script. This script can be ran both on server and client, however its not recommended to handle it on server.
(theres better ways to script that)

repeat task.wait(0.1) until game:IsLoaded() == true

local cloth = game:GetService('Workspace'):WaitForChild('Cloth')
local plane = cloth:WaitForChild('Plane')

local bones = {}
local groupsAmount = #plane:GetChildren()

for count = 1, groupsAmount do
	bones[count] = {}
end

local debugMode = true

function bone(bone)
	local physPart = Instance.new('Part')
	local a = 0.4
	physPart.Size = Vector3.new(a,a,a)
	--physPart.Shape = Enum.PartType.Ball
	physPart.Position = bone.WorldPosition
	physPart.Anchored = false
	physPart.Color = Color3.new(1, 0, 0)
	physPart.Parent = cloth.Physics
	if debugMode == false then
		physPart.Transparency = 1
	end
	
	local att = Instance.new('Attachment', physPart)
	att.Name = 'Att'
	
	local info = string.split(bone.Name, '.')
	local group = tonumber(info[2])
	local index = tonumber(info[3])
	
	bones[group][index] = {physPart, bone}
	
	physPart.Name = bone.Name
end

for i, v in pairs(plane:GetDescendants()) do
	if v:IsA('Bone') then
		bone(v)
	end
end
local rows = {}
for count = 1, #plane:GetChildren() do
	rows[count] = {}
end

for i, v in pairs(bones) do --// physPart, bone
	for d, b in pairs(v) do
		if d ~= 1 then
			local rope = Instance.new('RopeConstraint', cloth.Physics)
			rope.Attachment0 = v[d-1][1].Att
			rope.Attachment1 = b[1].Att
			rope.Name = rope.Attachment0.Parent.Name..rope.Attachment1.Parent.Name
			rope.Visible = debugMode
			rope.Color = BrickColor.new('Really blue')
			rope.Length = (v[d-1][1].Position-b[1].Position).Magnitude
		else
			b[1].Anchored = true
		end
		table.insert(rows[d], b[1])
	end
end
for i, v in pairs(rows) do
	for ii, b in pairs(v) do
		if ii ~= 1 then
			local rope = Instance.new('RopeConstraint', cloth.Physics)
			rope.Attachment0 = b.Att
			rope.Attachment1 = rows[i][ii-1].Att
			rope.Name = rope.Attachment0.Parent.Name..rope.Attachment1.Parent.Name
			rope.Visible = debugMode
			rope.Color = BrickColor.new('Really blue')
			rope.Length = (b.Position-rows[i][ii-1].Position).Magnitude
		end
	end
end

game:GetService('RunService').Heartbeat:Connect(function()
	for i, v in pairs(bones) do
		for i, b in pairs(v) do
			b[2].WorldPosition = b[1].Position
		end
	end
end)

What this script does:

  • Splits all the bones into colums, rows
  • Creates a part for each bone
  • Connects those parts with ropes
  • Synces bones with thier physical parts on Heartbeat

Cloth ends up looking like this with visualization:

Play around:

image

Files

Cloth model - Cloth.rbxm (5.6 KB)
Place - Cloth Simulation.rbxl (52.1 KB)
Script - ClothScript.lua (2.2 KB)
( Sorry, cloth mesh file was lost :frowning_face: )

I suck at designing posts
23 Likes

Only thing I would consider is that you could consider using CFrame since it is faster and more accurate. Unless it breaks the function

function bone(bone)
	local physPart = Instance.new('Part')
	local a = 0.4
	physPart.Size = Vector3.new(a,a,a)
	--physPart.Shape = Enum.PartType.Ball
	physPart.Position = bone.WorldPosition

	physPart.Anchored = false
	physPart.Color = Color3.new(1, 0, 0)
	physPart.Parent = cloth.Physics
	if debugMode == false then
		physPart.Transparency = 1
	end
	
	local att = Instance.new('Attachment', physPart)
	att.Name = 'Att'
	
	local info = string.split(bone.Name, '.')
	local group = tonumber(info[2])
	local index = tonumber(info[3])
	
	bones[group][index] = {physPart, bone}
	
	physPart.Name = bone.Name
end
1 Like

Since parts mostly spin like crazy, it will result in mesh deforming. You can try that and see yourself. That’s why I think the method I used is bad too.

You could test CFrame.Position and see if there is any different in performance, if their is any it may be seen in a simulation in scale. I would also reccomend making a template part with the consistent properties that are defined and replicated. Also you should see if your function still works without tonumber
Also one final thing is you can define the plane
plane:GetChildren() as planearray=plane:GetChildren()
Also check out this code I wrote about the cframe of bones

	if v:IsA("BasePart") or v:IsA("Bone") or v:IsA("Attachment") then
			
			local Vcf = v.CFrame
			local _,_,_,C0,C1,C2,c3,c4,c5,c6,c7,c8 = Vcf:components()
			if v:IsA("BasePart") then
				v.Size = v.Size * Scale
				v.CFrame = CFrame.new(Vcf.p * Scale) * CFrame.new(0,0,0,C0,C1,C2,c3,c4,c5,c6,c7,c8)
				v.AssemblyLinearVelocity=Vector3.new(0,0,0)
			else 
				v.CFrame = CFrame.new(Vcf.p * Scale) * CFrame.new(0,0,0,C0,C1,C2,c3,c4,c5,c6,c7,c8)
			end
1 Like

Yeah, this code is definitely possible to improve. I wrote it 10 months ago and haven’t touched it since then. Moments like multiple plane:GetChildren() may occur, I was way worse in Luau.

Also make sure you are putting the cloth script inside an Actor! Super easy to utilize that performance gain by simply placing the script inside of an actor. Another thing is you can always throttle or change the linear velocity. to stop things from getting out of control.

v.AssemblyLinearVelocity=Vector3.new(0,0,0) 

But the Resize function I provided is interesting tool I would reccomend you check out potnetially as well. It has advantages over the ScaleTo API such as working on parts and their descendants. and not changing the initial position of the model, in addition to having a tween function to gradually increase the size of a model. It works in real time on animated rigs without yeeting them out of existance like the scaleto api.

1 Like

Hello thank you for this! I remember seeing your video long time ago showcasing this

Would using the cloth simulation in my game lag my game?

Never tested it in games, you could improve performance by not simulation cloth far away + decreasing the amount of bones. I still wouldn’t recommend to use it.

Can this simulate with Wind Feature too?

why would it
it is possible, but it needs to be implemented
i would recommend adding a constant force equal to the current wind force with a direction vector equal to the wind’s vector to each point in the simulation
this might be slightly inaccurate due to aerodynamics issues, but i have yet to see someone conducting a realtime CFD simulation in Roblox.
if none of what i said makes sense to you, just ask chatgpt lol.

1 Like

You should be able to use fluid forces on the cloth mesh and test from there.

Yeah thats relatively new
I wrote that before being aware of any of the new features

heyo found the cloth mesh!
ClothMesh.obj (44.0 KB)
enjoy

1 Like