I do understand at one point in ROBLOX’s history there was a way to do this with a function, which I believe is still deprecated, but like. How would I go about getting the center of a model?
Weird, they deprecated this feature and is still deprecated today:
Temporary Solution
Use a PrimaryPart that is definition of the center of the model.
The problem with using a center model primary part is that, if I didn’t have one because wasn’t planning ahead, which yea, is my own fault, but still, I don’t have that part to go off of.
Here’s a function you can use. Note: “bounding box” means a box which contains all parts within it. You can ignore the second argument & the second return value.
--[[ @brief Returns the bounding box for a group of parts.
@param model The model to get the bounding box of, or a list of instances.
@param cframe The orientation on which the bounding box should be aligned. If omitted, this will be axis-aligned.
@return center The absolute center of the bounding box.
@return size The size of the bounding box.
--]]
function GetBoundingBox(model, cframe)
if type(model) == "userdata" then
model = model:GetDescendants();
end
if not cframe then
cframe = CFrame.new();
end
local ax, ay, az;
local bx, by, bz;
for i, v in pairs(model) do
if v:IsA("BasePart") then
if not ax then
ax, ay, az = v.Position.X, v.Position.Y, v.Position.Z;
bx, by, bz = ax, ay, az;
end
local x, y, z, r00, r01, r02, r10, r11, r12, r20, r21, r22 = cframe:toObjectSpace(v.CFrame):components();
r00, r01, r02 = math.abs(r00), math.abs(r01), math.abs(r02);
r10, r11, r12 = math.abs(r10), math.abs(r11), math.abs(r12);
r20, r21, r22 = math.abs(r20), math.abs(r21), math.abs(r22);
local sx, sy, sz = v.Size.x, v.Size.y, v.Size.z;
local dx = r00 * sx + r01 * sy + r02 * sz;
local dy = r10 * sx + r11 * sy + r12 * sz;
local dz = r20 * sx + r21 * sy + r22 * sz;
local lx = x - dx; if lx < ax then ax = lx; end
local ly = y - dy; if ly < ay then ay = ly; end
local lz = z - dz; if lz < az then az = lz; end
local hx = x + dx; if hx > bx then bx = hx; end
local hy = y + dy; if hy > by then by = hy; end
local hz = z + dz; if hz > bz then bz = hz; end
end
end
if ax then
local center = cframe:toWorldSpace(CFrame.new((ax + bx) / 2, (ay + by) / 2, (az + bz) / 2));
local size = Vector3.new(bx - ax, by - ay, bz - az);
return center, size;
else
return nil;
end
end
I generally favor a solution like this because:
- I often need the size, too, and:
- Being able to choose the axes on which the bounding box lies is nice.
I don’t know your use case, but based on the title, these things don’t seem to apply to you.
GetModelCFrame works, but as Operatik said, they’re deprecated. If you don’t want to use GetModelCFrame, then your only other option is to iterate through each part in the model to get its bounding box, and then get the center of that bounding box.
A work around I personally do is union the entire model, copy a parts location than paste it into the union’s XYZ. Afterwards I simply just separate the union and regroup.
This method however I believe is only beneficial to a builder, not entirely sure if it’s of any use for scripting.
Model has the function Model:GetBoundingBox()
, which returns the CFrame center (convertible to a Vector3 using CFrame.p
) and the size of the bounding box. To get the center, you will need to use the first return item.
Not quite. These two, with the exact same geometry, will return a different center, depending on what the orientation of the primary part is.
(Green: The center of the model when its primary part is set to the one that is rotated. Red: ditto, but when it’s axis-aligned)
EDIT2: Tbh depending on OP’s usecase (which isn’t really clear yet…) this is probably good enough.
Not exactly sure if this is what you’re looking for.
local function GetCenter(Model)
local Sum = Vector3.new(0, 0, 0)
local Divisor = 0
for _, Descendant in pairs(Model:GetDescendants()) do
if Descendant:IsA("BasePart") then
Sum = Sum + Descendant.Position
Divisor = Divisor + 1
end
end
return Divisor ~= 0 and Sum / Divisor or false
end