Control Y Rotation Component

I’m using inverse kinematics to solve for the joint locations and then using CFrame.new(mid,jointpos) to set the arm’s CFrames, but as you can see in the following GIF, the arms constantly rotate when the IK updates as you look up and down. How can I prevent it from spinning on the relative Y axis?

I don’t know what method you are using, but I think it’s rotate relatively rather than globally. Not too much of an expert when it comes to CFrames, but have you thought of rotating the body relative to an external part’s rotation? What is your current method?

Currently, every arm is are welded to the UpperTorso. My IK solver returns the position that the joints need to be at in order for the arms to connect from a start position to an end position. I’m iterating through each joint, finding the midpoint between each adjacent joint, and then doing CFrame.new(midpoint,nextjoint) to set the arm CFrames.

Sounds like you want a reference vector to use to lock rotation. You could try making a function that constructs the rotation matrix by hand. The math behind it isn’t too involved so it wouldn’t be hard to do. I have some C++ code lying around that could be converted and repurposed for your needs:

// expects direction and globalUp to be unit vectors
Matrix3& Matrix3::face(const Vector3& position, const Vector3& direction, const Vector3& globalUp)
{
	// normalized because the angle between these vectors isn't guaranteed to be 90, so the sin isn't guaranteed to be 1 (affects outcome length)
	Vector3 right = direction.cross(globalUp).normalize(); 

	// should be a unit vector, but might want to normalize this if floating points become a problem
	Vector3 up = right.cross(direction); 

	// equivalent is the 12 argument CFrame constructor that takes a rotation matrix
	// CFrame.new(position.x, position.y, position.z, right.x, up.x, -direction.x, right.y, up.y, -direction.y, right.z, up.z, -direction.z)
	return setVectors(position, right, up, -direction);
}

Just gotta define some reference vector in your rig and use that for “globalUp”, preferably in object space relative to the rig. Be careful about parallel vectors, though. This function doesn’t like parallel direction & globalUp values.

I might revisit this later and explain what is going on in more detail when I’m not as tired.

Two things:

  1. Do your IK calculations in the local space of your RootPart or equivalent;
  2. Avoid using the lookAt CFrame constructor as you need full control over the components.
2 Likes

I’m taking multivariable calculus at my high school right now and that’s actually what we were just learning about recently. I was thinking about using cross product vectors to do it, but I had no idea how to implement it exactly. I’ll try out your method when I get home. Thank you!

@sircfenner I’m solving for global IK joint locations and then converting it to local space using :toObjectSpace() but I guess I could solve for local IK directly.