Camera Manipulation Relative to Two Points

I am trying to make a slightly complex camera system. The reason it is complex is because the camera will move relative to, not just the player’s CFrame, but an NPC’s as well. I’ll attach some drawings in a dropdown so you see what I mean:

Drawing

Hopefully you see what I’m trying to accomplish. The player will not be able to move the camera with the mouse at all; the camera will move every frame solely on what the positions (and rotations) of these two points are. If you need more clarifying, please let me know.

I have tried to get a vector along that middle line by doing the following:

local vectorInBetween = P1.Position - P2.Position;
vectorInBetween = vectorInBetween / 2; -- I do this so magnitude gets split in half
local part = Instance.new("Part");
part.Parent = Workspace; --The "Workspace" is a variable pointing to the correct way to access Workspace
part.CFrame = CFrame.new(vectorInBetween);

But the part spawns in a completely different area, not in between the two bricks I am testing with.

As stated in the drawing, I got the idea of using CFrame:lerp to get the midpoint in between them but I’m not sure on how to salvage the rotational part so that the camera moves relative to the points.

This is where I left off. I have no idea what to do next.
Also, in your answers, I would appreciate it if you didn’t just spit code and instead explain why and how something works so that I can learn from this experience.

Thank you in advance!

2 Likes
  • Your vectorInBetween variable actually describes the distance between your two points in space. If you want an average between the two points, you have to add them together and then divide by two, like you would any normal average.

Beyond that, the workflow I usually use for finding the camera’s CFrame requires three things: what object the camera points at, what angle the camera points at said object, and how far away the camera will be. So, I always use a formula like this using CFrames to find the camera’s position and orientation:

-- (x,y,z) * (0,xAngle,0) * (yAngle,0,0) * (0,0,distance) 

Camera.CFrame = cameraFocus * cameraAngle * cameraDistance

This works because it is already very simple and extremely easy to understand. You get the three CFrames, and you will get the camera’s position while pointing at your subject at all times.

We already know what the camera points at, vectorInBetween, and the angle will always be variable to the user’s discretion. Therefore, the only variable left to figure out is the camera’s distance.

I would recommend solving for the camera’s field of view through the Vector3:Dot method, which returns the dot product between two vectors,


but, there is no reliable inverse function for dot products, so this will very much be more of an algorithmic problem than a mathematical one.

My best guess would be to use Camera:WorldToViewportPoint or Camera:WorldToScreenPoint, which returns whether a point in space is on-screen or not (without accounting for objects obscuring its view!), and incrementing the camera distance by some amount until both positions are visible.

I hope this helps!

2 Likes

This sounds great! Thank you very much for your time! I will be sure to follow that Camera CFrame blueprint from now on.

I cannot access Studio today unfortunately, so I’ll try your advice when I get the chance and will mark your post as the solution upon reaching a success prototype of camera movement.

Thank you once again!

1 Like

So I was able to try it out and it works for the most part. The only thing is that the rotation remains constant no matter how or where the player moves. This is probably because we get the average vector distance and vectors do not contain rotational data.

I tried to multiply by the HumanoidRootPart’s rotational data (HRP.CFrame - HRP.CFrame.p), but that made it even worse.

My current hacky solution is using CFrame:lerp

-- P1 is just a random part in the Workspace
local cf = Character:WaitForChild("HumanoidRootPart").CFrame:lerp(P1.CFrame, 0.5);
local newCamCF = cf * CFrame.Angles(0, math.rad(330), 0) * CFrame.new(0, 2, 10);
Camera.CFrame = newCamCF;

It works, but it doesn’t give me my desired result. Again, I’m kind of lost.

Enum.CameraType.Scriptable

I forgot to mention, if you are using a scriptable camera system, it is best to change Camera.CameraType to Enum.CameraType.Scriptable so that you have full control over what happens to the camera, and the game does not try to take that control away from you. You probably already knew this.

You are right about saying that the vectors do not contain rotational data. For that, you need to record input so that the player can determine the angle. I usually do this using ContextActionService:BindAction or UserInputService.InputChanged and recording the InputObject.Delta from the argument passed into the function. If you look at the formula I provided in my last reply, I included a comment above it that describes it in a bit more nuanced detail. You might be able to figure it out! :wink:

1 Like