Physics simulate before Weld Constraints can take effect, causing random offsets

While creating a weld script for a friends project, I’ve had a script run through a list of objects inside of a ship and create a weld between neighbouring parts.

This is the outcome of said module with all the parts anchored which is expected.


as you can see the welds have all be connected but none of them are active because the parts are anchored.

Now adding an extra function to set the Anchored value to false for all the parts except a core part after they have been welded causes some offset issues

Unless I’m being oblivious to a mistake I’m making or welds don’t quite work how I understand them I’m going to say that this is a bug with how the engine is running a physics step before actually welding the parts, as my assumption is once they are unachored they shouldn’t move.

Place Repo:
Weld_Test.rbxl (29.9 KB)

At the bottom of the WeldShip module (screenshot slightly modified from repro), consider the following:

image

  • (Uncomment Line 123) When the blocks are unanchored before the model re-enters workspace, parts are significantly offset. In this case, it looks like physics get simulated before constraints can take effect.
    image

  • (Comment line 120 + Uncomment line 123) If the model never leaves workspace, the part offset is significantly less but still visible. It looks like by the time physics simulates on the now unanchored blocks, the weld constraints nearly haven’t taken effect; the delay between constraints activating and the model being unanchored appears shorter than the previous case since the offset is less.
    image

  • (Uncomment Line 126) When the blocks are unanchored after the model re-enters workspace, there is also minimal part offset. Constraints took effect nearly before physics were simulated.
    image

This possibly points to a race condition with physics step vs. (weld) constraints.

5 Likes

Why can’t you weld the model in Studio at edit time before you throw it into storage and get rid of the weld script at runtime? That way the weld offsets will be serialized with the weld instead of created first at runtime.

The issue still seems to persist if you run it while editing.

using the repro run the following in the cmd line and you still get similar results.
require(game.ServerScriptService.WeldShip)(game.Workspace:FindFirstChild('The Black Pearl'))

Yeah I did notice that playing with it myself. It’s definitely not simulation. Something to do with when the WeldConstraint is grabbing or updating it’s internal offsets.

I also tried disabling the script, selecting all the parts, unachoring them, and selecting the Weld tool to automatically join any touching parts.

That got me the best case behavior but there was still some visible sparkle at the seams.

WeldConstraint internally does the equivalent of of a Weld with:

weld.C0 = weld.Part0.CFrame:Inverse()
weld.C1 = weld.Part1.CFrame:Inverse()

If I change your script to do the currently equivalent:

function CreateWeld(part0,part1, parent)
	local weld = Instance.new('Weld')
	weld.Parent = parent
	weld.Part0 = part0
	weld.Part1 = part1
	weld.C0 = part0.CFrame:Inverse()
	weld.C1 = part1.CFrame:Inverse()
	return weld
end

I get the same result:

If I then change it to the algebraically equivalent:

function CreateWeld(part0,part1, parent)
	local weld = Instance.new('Weld')
	weld.Parent = parent
	weld.Part0 = part0
	weld.Part1 = part1
	weld.C0 = part0.CFrame:Inverse() * part1.CFrame
	return weld
end

It’s somehow (!?!?) slightly better, but still not perfect:

And I think this is as good as it can possibly get when welding this many blocks to adjacent blocks.

If these objects are never blown apart into pieces at runtime you could also try welding all parts to a common core (creating a flat tree) which should lead to less accumulated error coming from the successive CFrame multiplies down whatever long branching tree of welds gets selected internally.

If this isn’t destructed you should also try to combine adjacent squares and use less parts. Along with less welds, and less accumulated error, this would also have a performance benefit because the broad-phase collision detection cost of a moving object is per-part. Less parts, less work.

The high glossiness of the parts is also helping make the seams more visible by creating a more dramatic color difference between the two faces of the blocks.

I don’t understand why some of the different orders with WeldConstraints lead to such dramatic visible gaps. This isn’t the first time we’ve seen this type of issue… We’ll have to investigate that more.

I also had an idea to improve replication efficiency of WeldConstraints by replacing the two internal C0/C1 CFrames with a single Part0-to-Part1 CFrame, which should have the additional side-effect of improving accuracy too. Not sure when I’ll find time for that yet though.

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.