CFrame.lookAt(), but prevent twisting and breaking?

I’m trying to figure out how to make CFrame.lookAt() to stop twisting. Something like a Ball-And-Socket constraint, but the swinging part stays facing forward. I was making this for a practice IK thing, but I have disabled the IK itself for now.

Normal results should have the decal still on the “front”. The leg should not improperly twist, nor break my dummy’s hip or thigh joint. I would apply proper twisting later.

Expected (Natural):
image
image
image

Reality:

I’ve tried fiddling with CFrame functions, ordering of operations, changing the optional UpVector parameter, and restricting axes, but to no avail.

If it helps, I am applying the CFrame to the LeftHip.Transform property.

This is the current condition of my code’s snippet, the part of irritation for me:

	local Look_At = CFrame.lookAt(Vector3.zero, Hip1.WorldCFrame:ToObjectSpace(Effector_Attachment.WorldCFrame).Position, Hip1.WorldCFrame.LookVector)
	local OX, OY, OZ = Look_At:ToOrientation()
	
	Look_At = CFrame.fromOrientation(OX, 0, 0) * CFrame.Angles(math.rad(90), 0, 0) * CFrame.fromOrientation(0, 0, OZ)
	
	local Additional_Rotation = CFrame.Angles(0, -Hip1.WorldCFrame:ToObjectSpace(Effector_Attachment.WorldCFrame).LookVector.X, 0)
	local Main_Angle = Look_At --[[* CFrame.Angles(Limb.Angles[1] + math.rad(15), 0, 0)]] * Additional_Rotation 
	
	Main_Angle -= Main_Angle.Position

Sorry if it’s a mess, I’m still a noob with CFrames.

The default Up-vector of CFrame.lookAt is (0,1,0), which is, facing directly at cardinal-up. Instead, what you probably want is an Up-vector that takes lower priority in being formed, than the right-vector. You can accomplish that by creating a temporary right-vector, then making your up-vector from that temporary right-vector, and passing it in as the third argument to lookAt:

local ZVector = -- I think this was your " Hip1.WorldCFrame:ToObjectSpace(Effector_Attachment.WorldCFrame).Position"
local TempraryXVector = ZVector:Cross(Vector3.new(0,1,0))
local YVector = TemporaryXVector:Cross(ZVector)

local LookAt = CFrame.lookAt(Vector3.zero,ZVector,YVector) -- If the result is upside-down, change YVector to "ZVector:Cross(TemporaryXVector)"

I’ve tried your solution, but unfortunately, the leg is now twisting its hip joint just to have its front face looking at the block. I want the leg’s foot to look at the brick, whilst not twisting.
image

Can you take a video of what you’re seeing now? Or show it to me in the same poses as your “expected” images in your post?

Here you go. I may have found a temporary workaround, although I’d still like to know how else would I approach this problem, as I believe my current solution is still somewhat inaccurate and, whilst simple, is kind of terrible.

Take the CFrame you’re getting in that solution, and multiply it by CFrame.Angles(math.pi/2,0,0) You might need to do -math.pi/2, if it’s facing the wrong way.

I think that solution is pretty close, it’s just 90* off. The CFrame.Angles I gave is a 90* rotation, and multiplication is how you do addition with CFrames.

Well, that seemed to be the same as when I tried using the CFrame.lookAt() before I started this question. I was expecting something like this I hastily made in the Animation Editor:

EDIT: The previous video paused for a second somewhere. The better version was uploaded.

Can you share a video of what it’s doing after the 90* rotation, as well as you code in the current state? I would expect it to resemble that video right now, so I might need to see it, to see what’s wrong.

Edit: ooh, nevermind, I think I see where I went wrong. Give me a minute to think

I think you might be wanting this:

local ZVector = -- I think this was your " Hip1.WorldCFrame:ToObjectSpace(Effector_Attachment.WorldCFrame).Position"

local LookAt = CFrame.lookAt(Vector3.zero,ZVector,Torso.LookVector)

The results were close. It only starts to twist 180 again when I lift the leg up past 90 degrees:

image

Doesn’t the animation editor also twist like that? Though I imagine you don’t really notice, because you’re just dragging sliders, and an individual slider drag isn’t going to look obvious, because the pole is centered around that axis, keeping you from actually crossing it, outside of going around it.

Mathematically, it’s sounding like what you’re wanting is more like an algorithm that switches methods based on best visual appearance, than a formula, that solves in a consistent straightforward way. I’m guessing you could probably break the values down into quadrants, to try and define how you want each space to be treated, and have the quadrants be your transitions between the methods, as it sounds like the change you want is to modify how it looks once the leg raises above horizontal.

I do not think the lookAt’s behaviour is apparent in the Animation Editor, as I don’t see that it would actually behave like lookAt(). And the quadrant thing sounds a bit more complex to set up, considering I have to use it for four limbs.

Oh well, I’ll stick with my less accurate solution. Thanks for trying to help though.