I’m trying to recreate the official Roblox thumbnail for profile pictures they provide via Players:GetUserThumbnailAsync
But I believe they are making some modifications to a lot of different attributes of the Camera depending on the clothes/parameters of the character.
I’ll show a simple code of straight ahead “front” shot of the icon
local character = player.Character
local humanoid = character:WaitForChild("Humanoid")
local humanoidDescription = humanoid:GetAppliedDescription()
local model = Players:CreateHumanoidModelFromDescriptionAsync(
humanoidDescription,
Enum.HumanoidRigType.R15,
Enum.AssetTypeVerification.Always
)
local animate = model:FindFirstChild("Animate")
animate:Destroy()
local worldModel = iconPreviewViewport:WaitForChild("WorldModel")
model.Parent = worldModel
model:PivotTo(CFrame.new(0, 0, -2) * CFrame.Angles(0, math.pi, 0))
local head = model:FindFirstChild("Head") :: BasePart?
local camera = Instance.new("Camera")
iconPreviewViewport.CurrentCamera = camera
camera.Parent = iconPreviewViewport
local focus = head.Position
local distance = head.Size.Y * 2.5
local lookVector = model:GetPivot().LookVector
camera.CFrame = CFrame.new(focus + (lookVector * distance), focus)
But you can clearly see from original Roblox thumbnails that they change at least the FOV parameter, and I want to get it working same as they do in ViewportFrame.
What we did to get it perfectly on the mesh tool thumbnails we did back then was trial and error, we downloaded a thumbnail image, slapped it over the viewport and edited the properties until it worked.
You may want to slightly adjust the camera Y offset for “eye-level” framing like Roblox does.
Use 420 × 420 for your ViewportFrame size to match the standard thumbnail.
This could be totally wrong, but this is what I could gather from Thumbnails/ThumbnailUtils.js in js.rbxcdn.com (the source for 3D thumbnails)
Camera Setup and FOV
The camera uses a PerspectiveCamera with a FOV that is often 70 degrees, though sometimes it’s read from the JSON (json.camera.fov).
Aspect ratio is container width / height.
Near/far planes are something like 0.1 (min) and calculated maxRenderDistance (max), which in Roblox terms could be model:GetExtentsSize().Magnitude * factor.
Camera Positioning
The camera is positioned relative to the bounding box of the model (json.aabb) so the whole character fits in the frame.
Look-at point is the center of the model.
Distance from the model is typically 4× the model bounding box length, but you could adjust this based on head size for a front-facing portrait.
Roblox sometimes flips the model so it faces the camera: CFrame.Angles(0, math.pi, 0) in Lua is equivalent.
Lighting
There are two modes: dynamic and static.
Static lighting is simpler: an ambient light plus two directional lights (sun and backlight).
Dynamic lighting adds three lights: ambient, keylight, fill light, rim light.
Colors are soft grays: 0xd4d4d4, 0xacacac, 0x444444.
So it might look something like this:
local model = Players:CreateHumanoidModelFromDescriptionAsync(
humanoidDescription,
Enum.HumanoidRigType.R15,
Enum.AssetTypeVerification.Always
)-- your model
local head = model:FindFirstChild("Head")
local camera = Instance.new("Camera")
iconPreviewViewport.CurrentCamera = camera
camera.Parent = iconPreviewViewport
local size = model:GetExtentsSize()
local center = model:GetPivot().Position
local distance = size.Magnitude * 2 -- adjust factor
local lookVector = (center - (center + Vector3.new(0,0,distance))).Unit
camera.CFrame = CFrame.new(center + Vector3.new(0,0,distance), center)
camera.FieldOfView = 70
I can try to dig more into the file, but so far this seems to be correct just by running the javascript through an analysis. The best thing you can do is just read over the .js files that are used to create the character image, and reversing them. You can do this easily by going to your profile and running Ctrl + Shift + I and inspecting Sources