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