How to get the lowest point of a part

Quick question:

Whats the easiest and most efficient way to find the lowest point of a part?

Position - Size/2
(size is for the Y axis and it may change the if ur part is rotated)
this should be it

3 Likes

I think the position represents the center of the part, so if you would subtract half of the part’s height from the Y axis it would move to the bottom of it.

Tried this solution and definitely isn’t giving the lowest point (red part representing the position found from your equation)

@C0lvy123 I know for a fact that won’t work.

local Part = Instance.new("Part")
Part.BrickColor = BrickColor.new("Really red")
Part.Anchored  = true
Part.Parent = game.Workspace

Part.Size = Vector3.new(.1,.1,.1)
Part.Position = game.Workspace.Part.Position - (game.Workspace.Part.Size * Vector3.new(0.5,0.5,0.5))

I tried positioning a part underneath another part my way and it worked perfectly.

local Pos = game.Workspace.Part.Position
local Size = workspace.Part.Size
game.Workspace.Part2.Position = Vector3.new(Pos.X, Pos.Y - Size.Y/2, Pos.Z)

Screen Shot 2020-06-11 at 16.14.50

local Part = Instance.new("Part")
Part.BrickColor = BrickColor.new("Really red")
Part.Anchored  = true
Part.Parent = game.Workspace

local Pos = game.Workspace.Part.Position
local Size = workspace.Part.Size
Part.Size = Vector3.new(.1,.1,.1)
Part.Position = Vector3.new(Pos.X, Pos.Y - Size.Y/2, Pos.Z)

It probably isn’t working because that part is rotated. Maybe try subtracting half the size on the X or Z axis instead of Y?

I need a formula that will work regardless of the part, your solution gives me the southernmost point from the part position assuming its rotated at 0,0,0, not the lowest point on the part.

1 Like
local part = workspace.Part

local point = part.CFrame * CFrame.new(0, -part.Size.Y / 2, 0)

-- to get xyz only
local position = point.p

I feel this is the same as what people have already said?

Using part.Size.Y gets messed up the second you start messing with rotations.

No. CFrames have rotational components whereas Vectors do not

Could there be a more optimal answer, maybe. This is how I solved it.

Let’s break down the problem, you have a part which has the following:

  • Position, our base point
  • CFrame, which tells us about the rotation
  • Our size, which tells us the offset from the base point

Now, a cframe has 3 vectors we can look at, the right/up/look vectors. These vectors tell us the direction of the right/top/front faces, which give us our offset relative to the rotation in the x/y/z axes respectively, neat.

If we break it down and look at an individual vector, say the lookvector, it “defaults” to <0, 0, -1>. As stated before, this should be expected considering the lookvector is the direction relative on the z axis, however, the direction forward is “negative”. This means though, that the back face is <0, 0, 1>. We now have 2 faces, this can be applied to all 3 vectors, for a total of 6 faces.

How do we select the proper faces? Well, remember, these directions are relative, if a face is pointing up it will be positive on the Y axis, we want it to be negative on the Y. So, all we must do is check if the Y component is greater than 0, if so, flip it.

There is one special case, what if the Y component is 0? You may want to just handle it as any other case, or you could just return no offset. This way, the point falls in the middle of the plane.

Do this process with all 3 vectors, scale them with the distance (size/2), and combine them with the base position. That’s all it takes to find the lowest point.

local function getDir(v)
	return (
		((v.Y == 0) and Vector3.new()) or -- flat
		((v.Y > 0) and -v) or -- flip
		v -- perfect
	)
end

local function computeLowestPoint(part)
	
	local cf = part.CFrame
	local dist = part.Size/2
	
	local xVec = getDir(cf.RightVector) * dist.X
	local yVec = getDir(cf.UpVector) * dist.Y
	local zVec = getDir(cf.LookVector) * dist.Z
	
	return (cf + xVec + yVec + zVec).p
	
end

local track = Instance.new("Part")
track.Name = "Track"
track.Size = Vector3.new(math.random(3, 6), math.random(3, 6), math.random(3, 6))
track.Position = Vector3.new(0, 10, 0)
track.Transparency = 0.5
track.Anchored = true

local marker = Instance.new("Part")
marker.Name = "Marker"
marker.Size = Vector3.new(0.5, 0.5, 0.5)
marker.BrickColor = BrickColor.new("Bright red")
marker.Anchored = true

track.Parent = workspace
marker.Parent = workspace

while wait() do
	marker.CFrame = CFrame.new(computeLowestPoint(track))
end
9 Likes


https://gyazo.com/69095d8073a0d78a74c68b85ee021e5d
Bingo, thanks!

If you do think of anything more optimised do let me know.

You can get the position of all of the brick’s corners and pick the one with the lowest Y component.

local v = 1
print(math.floor((v - 1) / 13) + 1)
print(((v - 1) % 13) + 1)


local part = workspace.Part
local dim = part.Size / 2
local corners = {
	part.CFrame * CFrame.new(dim.X, dim.Y, dim.Z),
	part.CFrame * CFrame.new(dim.X, dim.Y, -dim.Z),
	part.CFrame * CFrame.new(dim.X, -dim.Y, dim.Z),
	part.CFrame * CFrame.new(dim.X, -dim.Y, -dim.Z),
	part.CFrame * CFrame.new(-dim.X, dim.Y, dim.Z),
	part.CFrame * CFrame.new(-dim.X, dim.Y, -dim.Z),
	part.CFrame * CFrame.new(-dim.X, -dim.Y, dim.Z),
	part.CFrame * CFrame.new(-dim.X, -dim.Y, -dim.Z)
}

local lowestPoint = corners[1].Position

for _, corner in ipairs(corners) do
	if (corner.Position.Y < lowestPoint.Y) then
		lowestPoint = corner.Position
	end
end

local marker = Instance.new("Part")
marker.BrickColor = BrickColor.new("Really red")
marker.Anchored  = true
marker.Parent = game.Workspace
marker.CFrame = CFrame.new(lowestPoint)
2 Likes