Hello,
I was doing some manipulations on the camera when I experienced a more unexpected “bug”.
The idea was for the camera to look more like: Watch ref | Streamable, and for some reason, it is not possible to do a 360 degree “turn” at a specific angle of the camera (the X angle, which is up and down).
When it reaches the 90+ degrees at the X camera angle, it somehow, manages to add 90/180 degrees on the Y axis? That’s weird.
local Plane_Center = self.Center -- This is an part (referential)
local Mouse_Delta = UserInputService:GetMouseDelta() * MOUSE_SENSITIVITY
self.YRot -= Mouse_Delta.Y
local XRot, YRot = math.rad(self.XRot), math.rad(self.YRot)
local Next_Angles = CURR_DISTANCE * Vector3.new(
math.sin(XRot) * math.cos(YRot),
math.sin(YRot),
math.cos(XRot) * math.cos(YRot)
)
local Starter_Position = Plane_Center.Position
local Next_Direction = Starter_Position + Next_Angles
local Current_CFrame = CFrame.new(Starter_Position, Next_Direction)
local Sight_CFrame = Current_CFrame * CFrame.new(0, 0, -SIGHT_DISTANCE) -- This is for the "custom" mouse position, and all it does in the end is to set a part position into this cframe position, so the ring moves.
local Sight_Position = Sight_CFrame.Position
local Origin = Starter_Position + Next_Angles
local Direction = Starter_Position
Camera.CFrame = CFrame.lookAt(Origin, Direction)
If anybody knows how to fix it, it would be great, at the same time, I’d learn from it. Cameras isn’t the type of thing that I’m so “familiar” with, however, I never experienced something like this before.
I’m using the scriptable camera type, so this way I could set the camera cframe and manipulate it (cause I’m thinking on first person view option also)
The CFrame.lookAt function would work something like this:
local function lookAt(origin: Vector3, target: Vector3)
local zVector = origin - target
local xVector = Vector3.yAxis:Cross(zVector)
local yVector = zVector:Cross(xVector)
return CFrame.fromMatrix(origin, xVector, yVector, zVector)
end
part.CFrame = lookAt(part.Position, target.Position)
If we setup a scene where the origin - target end up parallel to Vector3.new(0, 1, 0) we’ll see the result flip. Understanding why is mostly just about understanding how the cross product and the right hand rule work.
To fix this we can change the code slightly to support an arbitrary up vector
local function lookAt(origin: Vector3, target: Vector3, up: Vector3)
local zVector = origin - target
local xVector = up:Cross(zVector)
local yVector = zVector:Cross(xVector)
return CFrame.fromMatrix(origin, xVector, yVector, zVector)
end
part.CFrame = lookAt(part.Position, target.Position, part.CFrame.YVector)
This time we pass in the part’s current up vector which in the context of micro adjustments being made every frame results in a smooth “somersault” as opposed to a sudden flip.
Lucky for you CFrame.lookAt already supports an additional third parameter for defining the up vector.