ToWorldSpace is the same as *

ToWorldSpace is the same as *

Okay so, I want to add a bit of knowledge to help people understand what ToWorldSpace is and how it works. When running the following code:

-- Function to compute the magnitude of the difference between two CFrames
local function cframeDifferenceMagnitude(cf1, cf2)
	local posDiff = cf1.Position - cf2.Position
	local r1X, r1Y, r1Z = cf1:ToEulerAnglesXYZ()
	local r2X, r2Y, r2Z = cf2:ToEulerAnglesXYZ()
	local rotDiff = Vector3.new(
		math.abs(r1X - r2X),
		math.abs(r1Y - r2Y),
		math.abs(r1Z - r2Z)
	)
	return posDiff.magnitude + rotDiff.magnitude
end

-- Loop to create multiple test cases and check equivalence
for i = 0, 90, 15 do
	for j = 0, 90, 15 do
		for k = 0, 90, 15 do
			-- Generate CF1 with position and rotation
			local CF1 = CFrame.new(i, j, k) * CFrame.Angles(math.rad(i), math.rad(j), math.rad(k))
			-- Generate CF2 with position and rotation
			local CF2 = CFrame.new(k, j, i) * CFrame.Angles(math.rad(k), math.rad(j), math.rad(i))

			-- Calculate results
			local result1 = CF1 * CF2
			local result2 = CF1:ToWorldSpace(CF2)

			-- Check if they are equivalent
			local areEquivalent = result1 == result2
			print("CF1 Pos:", CF1.Position, "CF1 Rot", CF1:ToEulerAnglesXYZ(), "CF2 Pos:", CF2.Position, "CF2 Rot:", CF2:ToEulerAnglesXYZ())
			print("Are Equivalent:", areEquivalent)

			if not areEquivalent then
				-- Compute the magnitude of the difference
				local differenceMagnitude = cframeDifferenceMagnitude(result1, result2)
				print("Difference Magnitude:", differenceMagnitude)

				-- Check if the difference is negligible
				if differenceMagnitude < 1e-6 then
					print("Negligible difference")
				else
					print("Significant difference")
				end
			end
		end
	end
end

I am testing to see if these functions are equivalent:

local result1 = CF1 * CF2
local result2 = CF1:ToWorldSpace(CF2)

For every single instance, the output is “true”

  06:20:53.582  CF1 Pos: 90, 75, 45 CF1 Rot 1.5707963705062866 CF2 Pos: 45, 75, 90 CF2 Rot: 0.7853981852531433 1.3089969158172607 1.5707963705062866  -  Client - LocalScript:67
  06:20:53.582  Are Equivalent: true  -  Client - LocalScript:68
  06:20:53.582  CF1 Pos: 90, 75, 60 CF1 Rot 1.5707963705062866 CF2 Pos: 60, 75, 90 CF2 Rot: 1.0471975803375244 1.3089969158172607 1.5707963705062866  -  Client - LocalScript:67
  06:20:53.583  Are Equivalent: true  -  Client - LocalScript:68
  06:20:53.583  CF1 Pos: 90, 75, 75 CF1 Rot 1.5707963705062866 CF2 Pos: 75, 75, 90 CF2 Rot: 1.3089969158172607 1.3089969158172607 1.5707963705062866  -  Client - LocalScript:67
  06:20:53.583  Are Equivalent: true  -  Client - LocalScript:68
  06:20:53.583  CF1 Pos: 90, 75, 90 CF1 Rot 1.5707963705062866 CF2 Pos: 90, 75, 90 CF2 Rot: 1.5707963705062866 1.3089969158172607 1.5707963705062866  -  Client - LocalScript:67
  06:20:53.583  Are Equivalent: true  -  Client - LocalScript:68
  06:20:53.583  CF1 Pos: 90, 90, 0 CF1 Rot 1.5707963705062866 CF2 Pos: 0, 90, 90 CF2 Rot: 1.5707963705062866 1.5707963705062866 0  -  Client - LocalScript:67
  06:20:53.583  Are Equivalent: true  -  Client - LocalScript:68
  06:20:53.583  CF1 Pos: 90, 90, 15 CF1 Rot 1.832595705986023 CF2 Pos: 15, 90, 90 CF2 Rot: 1.832595705986023 1.5707963705062866 0  -  Client - LocalScript:67
  06:20:53.584  Are Equivalent: true  -  Client - LocalScript:68
  06:20:53.584  CF1 Pos: 90, 90, 30 CF1 Rot 2.094395160675049 CF2 Pos: 30, 90, 90 CF2 Rot: 2.094395160675049 1.5707963705062866 0  -  Client - LocalScript:67
  06:20:53.584  Are Equivalent: true  -  Client - LocalScript:68
  06:20:53.584  CF1 Pos: 90, 90, 45 CF1 Rot 2.356194496154785 CF2 Pos: 45, 90, 90 CF2 Rot: 2.356194496154785 1.5707963705062866 0  -  Client - LocalScript:67
  06:20:53.584  Are Equivalent: true  -  Client - LocalScript:68
  06:20:53.584  CF1 Pos: 90, 90, 60 CF1 Rot 2.6179940700531006 CF2 Pos: 60, 90, 90 CF2 Rot: 2.6179940700531006 1.5707963705062866 0  -  Client - LocalScript:67
  06:20:53.584  Are Equivalent: true  -  Client - LocalScript:68
  06:20:53.584  CF1 Pos: 90, 90, 75 CF1 Rot 2.879793167114258 CF2 Pos: 75, 90, 90 CF2 Rot: 2.879793167114258 1.5707963705062866 0  -  Client - LocalScript:67
  06:20:53.584  Are Equivalent: true  -  Client - LocalScript:68
  06:20:53.585  CF1 Pos: 90, 90, 90 CF1 Rot -3.141592502593994 CF2 Pos: 90, 90, 90 CF2 Rot: -3.141592502593994 1.5707963705062866 0  -  Client - LocalScript:67
  06:20:53.585  Are Equivalent: true  -  Client - LocalScript:68

Therefore, CF = CF1:ToWorldSpace(CF2) is the same exact thing as CF = CF1 * CF2.

You can do the following:

ObjSpace2 = CF1:ToObjectSpace(CF2)

Where ObjSpace2 is the CFrame of CF2 within the local coordinate space of CF1. And then doing:

CF2 = CF1 * ObjSpace2

would completely undo the change and return CF2 in the World Space (of course with very minor discrepencies).
This would hold true as well with:

CF2 = CF1:ToWorldSpace(ObjSpace2)

Therefore, if you do not know ToWorldSpace, you can simply use the overloaded operator * and it would do the same exact thing.

6 Likes

This along with other equivalencies between CFrame methods and CFrame math operations are mentioned in the documentation. The math operations are just matrix math operations. The methods are a way to write the purpose of the operation you are doing.

Using the math operations directly may lead to shorter code depending on operation and variable name lengths while using the methods may result in more easily understandable code.

Additionally, in some situations, it may be useful to write a matrix equation describing what you are trying to achieve and then solve an unknown matrix (CFrame) from that equation. For writing the equation, you need to know what kind of math operations you need to describe the intended result.

1 Like