Need help in understanding a mathematical formula in roblox

Hello guys, so i was trying to make my arms point directly at the mouse cursor and trying to look for solution online. I came across this formula which makes me a little bit confused.
This is it:

Neck.C0 = Neck.C0:lerp(NeckOriginC0 * CFrame.Angles(-(math.atan(Difference / Distance) * 0.5), (((HeadPosition - Point).Unit):Cross(TorsoLookVector)).Y * 1, 0), 0.5 / 2)
Waist.C0 = Waist.C0:lerp(WaistOriginC0 * CFrame.Angles(-(math.atan(Difference / Distance) * 0.5), (((HeadPosition - Point).Unit):Cross(TorsoLookVector)).Y * 0.5, 0), 0.5 / 2)

I understand what cross vector is and how to perform them as well as basic trigonometry such as the tan formula even though i will use sin instead of tan in this formula. So the question is if you look at the Y component of CFrame.Angles , (((HeadPosition - Point).Unit):Cross(TorsoLookVector)).Y * 1 it just doesn’t make any sense to me. How does the Y component of a cross vector can be used for angle calculation? i went on youtube to watch how people explained about cross vector and according to Professor Dave on youtube. the formula of cross provides the magnitude of the cross vector. Hope that my understanding is true. If my english is bad, i’m sincerely sorry for this inconvenience

1 Like

This video? The Vector Cross Product - YouTube Damn what a great intro tune! :stuck_out_tongue:

Anyway, your understanding isn’t quite right. Take a look here:

This is taken from the video. It is an example of how to calculate a × b, where a and b are vectors in 3D. As you can see after the equals sign, the result is also a 3D vector. This doesn’t fit with your description that I quoted, because a magnitude is just a simple number, not a vector.

Anyway, if I were you I wouldn’t worry so much about how to compute the cross product. To program games with it, it’s much more important to understand the properties, geometric interpretations and uses of it. The computer is there to compute for us, after all!

You wanted to know how the cross product can be related to angles, and here’s the key to understanding that:

image

Here, θ is the angle between the vectors a and b. This equation can be rearranged however you want, e.g. if you already know the vectors and want to determine their angle, you might use this form of the equation instead:

θ=asin( |a × b| / (|a||b|) )

As for how the cross product is used in the code you posted, that’s hard to figure out just by looking at it. The original programmer didn’t do a very good job of making it readable - or maybe they were just so used to thinking about 3D geometry that they thought it looked perfectly clear. Oh well, let’s break it down. Each version will be the same, unless I note otherwise


--Putting it onto more lines
Neck.C0 = Neck.C0:lerp(
    NeckOriginC0 * CFrame.Angles(-(math.atan(Difference / Distance) * 0.5), (((HeadPosition - Point).Unit):Cross(TorsoLookVector)).Y * 1, 0), 
    0.25 --Simplifying last parameter to lerp()
)

--Simplifying last parameter to lerp
Neck.C0 = Neck.C0:lerp(
    NeckOriginC0 * 
    CFrame.Angles( --Putting it onto more lines
        -(math.atan(Difference / Distance) * 0.5), --Pitch
        (((HeadPosition - Point).Unit):Cross(TorsoLookVector)).Y * 1, --Yaw
        0 --Roll
    ), 
    0.25
)

Okay so now that it’s split onto more lines, we can see that they’re using the version of CFrame.Angles that takes 3 numbers, where each is the X, Y and Z rotation (or pitch yaw roll). The roll one is easiest because it’s just 0. That means the neck joint never ends up rolling - which in this case would be like tilting your head left/right.

The pitch (looking up/down) calculation looks a lot like the basic tan formula but rearranged:

tan(θ) = o/a ⇒ θ=atan(o/a)

If we rearranged the pitch calculation we can see that it’s that but multiplied - or scaled - by a constant:

-0.5 * math.atan(Difference / Distance)

Can’t really tell you which angle it is without knowing what Difference and Distance are. But it seems to be finding half of the angle from the neck joint to some point in 3D space, which makes sense when constructing an angle with the CFrame.Angles call.

The yaw (twisting your neck to look left or right) has the actual cross product. Let’s simplify it:

((HeadPosition - Point).Unit:Cross(TorsoLookVector)).Y --Yaw

and then see what two vectors it’s operating on:
a = (HeadPosition - Point).Unit
b = TorsoLookVector

A LookVector is always a unit vector (magnitude = 1), and a is calculated to always be a unit vector as well. This means that |a|=1 and |b|= 1, so if you look at the first picture formula in this post, it simplifies to

|a × b|=sin(θ)

The LookVector of a character’s torso is usually going to be horizontal, and (HeadPosition - Point) will usually be somewhat horizontal if Point is mouse.Hit.p - again impossible to know without seeing the rest of the code. But if both vectors are horizontal (and not pointing the same direction), then their cross product will always be vertical. That means the X and Z components will always be 0, and all of the magnitude will be “stored in” the Y component of the cross product. So all in all it’s like setting the yaw of the neck C0 joint to the sine of the angle that the head should be yawed at to look towards the mouse. Doesn’t make as much sense as taking the asin of that whole thing to get the actual angle, but this is my best guess as to what the code is supposed to do.

Anyway, hope this helps in showing how code like that can be broken down into an understanding of what it does in 3D space. It’s not what you asked for originally (doesn’t even touch the arms at all), but if you learned something then I guess it’s ok :sweat_smile:

1 Like

This is the topic that i take the code from

ok, so i tried to modify the algorithm in my own way and trying to implement what you posted on the above post but it appears to act ridiculously. Any suggestion to help me fix it? The problem is that it only spins on the right side, it cannot spin to the left. The video demonstrates the issue

local RunService = game:GetService("RunService")

local Player = game.Players.LocalPlayer
local PlayerMouse = Player:GetMouse()

local Camera = workspace.CurrentCamera

local Character = Player.Character or Player.CharacterAdded:Wait()
local Head = Character:WaitForChild("Head")
local Neck = Head:WaitForChild("Neck")

local Torso = Character:WaitForChild("UpperTorso")
local Waist = Torso:WaitForChild("Waist")

local Humanoid = Character:WaitForChild("Humanoid")
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")

local NeckOriginC0 = Neck.C0
local WaistOriginC0 = Waist.C0

Neck.MaxVelocity = 1/3

RunService.RenderStepped:Connect(function() 
	local CameraCFrame = Camera.CoordinateFrame

	if Character:FindFirstChild("UpperTorso") and Character:FindFirstChild("Head") then
		local TorsoLookVector = Torso.CFrame.lookVector
		local HeadPosition = Head.CFrame.p

		if Neck and Waist then
			if Camera.CameraSubject:IsDescendantOf(Character) or Camera.CameraSubject:IsDescendantOf(Player) then
				local Point = PlayerMouse.Hit.p

				local Distance = (Head.CFrame.p - Point).magnitude
				local Difference = Head.CFrame.Y - Point.Y
				Neck.C0 = Neck.C0:lerp(NeckOriginC0 * CFrame.Angles(-(math.atan(Difference / Distance) * 0.5), -math.asin(((HeadPosition - Point).Unit:Cross(TorsoLookVector)).Magnitude), 0), 0.5 / 2)
				Waist.C0 = Waist.C0:lerp(WaistOriginC0 * CFrame.Angles(-(math.atan(Difference / Distance) * 0.5), -math.asin(((HeadPosition - Point).Unit:Cross(TorsoLookVector)).Magnitude) , 0), 0.5 / 2)
			end
		end
	end	
end)
1 Like

Hello, are you there? Sorry if i am bothering you

1 Like

It’s ok, sorry I don’t have time time to post a followup

1 Like

that’s sad, ok i got it. You are busy