I know this is bumping an already answered post, but I’m making a comment b/c there are few things worth noting about TheGamer101’s solution that may cause people some issues (especially in the context of model fitting for a viewport frame)
First off let’s explain the TheGamer101’s method:
Camera’s in Roblox use perspective projection which means you can judge depth. For example, things far away are small and things close are big.
That means your camera’s view bounds look something like this (from a Y & Z axis side profile):
Say you know the height of an object you want the camera to zoomToExtents
to. You can use basic trigonometry to solve for the distance that your camera needs to be away from the object to fully encapsulate it.
-- SOH CAH TOA
-- tan = opposite / adjacent
tan(FOV / 2) = (height / 2) / distance
distance = (height / 2) / (tan(FOV / 2))
So in short, what TheGamer101 is doing is finding the bounding sphere of the model and then using its diameter as the height. The issue here is that when we do this we end up with the following scenario.
As you can see some of the circle is cut off in the process so you don’t actually get a perfectly encapsulated model. Instead, you can still do this with trigonometry, but instead use sin
instead of tan
.
sin = opposite / hypotenuse
sin(fov2) = radius / distance
distance = radius / sin(fov2)
Now you might think “That’s it, it’s completely solved!”. Unfortunately no, all we’ve focused on so far is the distance for the vertical height of our viewport frame size. We also have to take into account the horizontal width. Otherwise, we may end up in a situation like so:
It fit’s vertically, but not horizontally!
Luckily, the fix is easy we do the same calculation as above, but instead figure out the horizontal field of view and then we pick the minimum between the two.
local function getModelFitDistance(model, vpf, camera)
local modelCFrame, modelSize = model:GetBoundingBox()
local vpfSize = vpf.AbsoluteSize
-- clamped b/c we only want to scale the xfov2 if width < height
-- otherwise if width > height then xfov2 == yfov2
local wh = math.min(1, vpfSize.X / vpfSize.Y)
local yfov2 = math.rad(camera.FieldOfView / 2)
local xfov2 = math.atan(math.tan(yfov2) * wh)
local radius = modelSize.Magnitude / 2
return radius / math.sin(xfov2)
end
Checkout this post if you want a nice module that does this and a few other things for you!