How to position model in a ViewportFrame

I am trying to create a function that can adjust the ViewportFrame.CurrentCamera according to the CFrame and Size of a given Model, so that the entire Model will show in the ViewportFrame.


The camera’s FOV should be 30 and should be pointing at the Models from roughly the angle shown in the image.

In this image I manually set the camera of the Viewports, but essentially I want to have a function where I can put it any Model of any Size (and CFrame) and have the results look similar to this.

Thanks.

1 Like

I have a module that does this, though it sometimes works weird if the PrimaryPart CFrame is at an angle:

local module = {}

local bips = {
	Vector3.new(-1,-1,-1),
	Vector3.new(-1,-1, 1),
	Vector3.new(-1, 1,-1),
	Vector3.new(-1, 1, 1),
	Vector3.new( 1,-1,-1),
	Vector3.new( 1,-1, 1),
	Vector3.new( 1, 1,-1),
	Vector3.new( 1, 1, 1),
}

function module.GenerateBuildingThumbnail(model : Model)
	local vp = Instance.new("ViewportFrame")
	vp.BackgroundColor3 = Color3.fromRGB(0, 85, 125)
	vp.LightDirection = -Vector3.yAxis
	vp.LightColor = Color3.fromRGB(255, 255, 255)


	local cam = Instance.new("Camera", vp.Parent)

	vp.CurrentCamera = cam

	local building = model:Clone()
	building.Parent = vp

	--Make sure building is centered in the viewport frame
	local cf, size = model:GetBoundingBox()
	
	if building.PrimaryPart == nil then
		warn(model.Name.. " has no PrimaryPart set, can't generate thumbnail.")
		return vp
	end
	
	local boundingBoxOffset = building.PrimaryPart.Position - cf.Position
	building:PivotTo(building.PrimaryPart.CFrame - building.PrimaryPart.CFrame.Position + boundingBoxOffset)

	--Zoom camera appropriately
	local viewDistance = size.Magnitude * 0.6
	cam.CFrame = CFrame.lookAt(Vector3.one * viewDistance, Vector3.zero, Vector3.yAxis)

	--Optional grid floor
	local grid = Instance.new("Part", vp)
	grid.Color = Color3.fromRGB(0, 85, 125)
	grid.Size = (size - Vector3.yAxis * size.Y) + Vector3.xAxis * 8 + Vector3.zAxis * 8
	grid.TopSurface = Enum.SurfaceType.Smooth

	local furthest = nil

	for _, v in bips do
		local lv = cf:VectorToWorldSpace(v) * size / 2
		local height = lv:Dot(-Vector3.yAxis)

		if furthest == nil or height > furthest then
			furthest = height
		end
	end

	--Set grid position
	grid.Position = Vector3.new(0, -furthest, 0)

	local texture = Instance.new("Texture", grid)
	texture.Texture = "rbxassetid://6372755229"
	texture.StudsPerTileU = 8
	texture.StudsPerTileV = 8
	texture.Face = Enum.NormalId.Top
	texture.Transparency = 0.9
	texture.Color3 = Color3.fromRGB(255, 255, 255)

	--Building name label
	local label = Instance.new("TextLabel", vp)
	label.TextColor3 = Color3.fromRGB(255, 255, 255)
	label.TextXAlignment = Enum.TextXAlignment.Left
	label.TextYAlignment = Enum.TextYAlignment.Top
	label.TextSize = 12
	label.RichText = true
	label.TextWrapped = true
	label.BackgroundTransparency = 1
	label.BorderSizePixel = 0
	label.Size = UDim2.new(1, 0, 0.5, 0)
	label.Position = UDim2.new(0, 2, 0, 2) --Top left padding from thumbnail edge
	label.BorderSizePixel = 0
	label.Text = "<b>" ..model.Name.. "</b>"
	
	return vp
end

return module
3 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.