Let’s say I have Part A. Part A is intersecting with Part B, but not all the way overlapping. Is there a way to figure out the percentage of Part A that part B is touching, or vice versa?
I wasn’t able to find anything on the DevForum or the broader internet about this, and I suck with most CFrame and positional-based stuff, sorry to bother, but it’d be great if anyone knows either how to do this or a way to start working it out!
That’s just an example for illustrative purposes, the sizes and positions of the actual parts are way different. I need to figure it out with a script.
this might be another case of the xy problem
this is like… a super duper complex task… and we need a bit more detail on why you need this in the first place so that we could know if theres something more simple we could do or how precise this needs to be and whether or not rotation and other stuff needs to be accounted for
this is what shows up when you want to know when two rotated cubes even INTERSECT with each other…
i assume that this looks like an alien language to both of us… so detecting whether they overlap or not (without any external API) is pretty hard… LET ALONE getting the percentage of the overlap
so i did a bit of digging cuz I gotta help a sister out and came across this reddit post in the unity subreddit that leads you to this and that
which reminded me that roblox has a similar CSG manipulation thingy thing
this is where we start cooking
looking for a way to find the intersection i dug and found this announcement which actually lets you have the overlap between the two points become its own part
which led me to this function inside the documentation which returns the intersection instance
so…
if you can get the intersection instance
get its size
and somehow compare it to the size of the two parts to get the percentage…
you got this down!
(although, if you need the result fast… this aint the solution for you… the function yields and generally doing cursed CSG stuff like this at runtime goes wrong very easily…)
[only use this method if you fr just want to account for multiple different shapes and rotations]
Establish a bounding volume for each part. If the bounding boxes don’t interact, the parts aren’t touching / inside each other. If it does interact, using Separating Axis Theorem for convex shapes or Gilbert-Johnson-Keerthi algorithm would work. Once the algorithm detects a collision, you can compute the volume of intersection between two parts. To get the percentage, the formula is:
(intersection volume / total volume of part) * 100
Roblox has collision detection by default so, I would use that to minimize computational heavy-lifting.
Here’s a super simple implementation that probably doesn’t work completely but, should get you in the right direction:
-- Bounding box intersection
function checkBoundingBoxIntersection(part1, part2)
local part1Min = part1.Position - part1.Size/2
local part1Max = part1.Position + part1.Size/2
local part2Min = part2.Position - part2.Size/2
local part2Max = part2.Position + part2.Size/2
return (part1Min.X < part2Max.X and part1Max.X > part2Min.X) and
(part1Min.Y < part2Max.Y and part1Max.Y > part2Min.Y) and
(part1Min.Z < part2Max.Z and part1Max.Z > part2Min.Z)
end
-- Intersection Volume via finding overlapping dimensions
function calculateIntersectionVolume(part1, part2)
local overlapX = math.max(0, math.min(part1.Position.X + part1.Size.X/2, part2.Position.X + part2.Size.X/2) - math.max(part1.Position.X - part1.Size.X/2, part2.Position.X - part2.Size.X/2))
local overlapY = math.max(0, math.min(part1.Position.Y + part1.Size.Y/2, part2.Position.Y + part2.Size.Y/2) - math.max(part1.Position.Y - part1.Size.Y/2, part2.Position.Y - part2.Size.Y/2))
local overlapZ = math.max(0, math.min(part1.Position.Z + part1.Size.Z/2, part2.Position.Z + part2.Size.Z/2) - math.max(part1.Position.Z - part1.Size.Z/2, part2.Position.Z - part2.Size.Z/2))
return overlapX * overlapY * overlapZ
end
-- Percentage of part that is touching other part
function calculatePercentage(part, intersectionVolume)
local totalVolume = part.Size.X * part.Size.Y * part.Size.Z
return (intersectionVolume / totalVolume) * 100
end
aaah yeah sorry!! i never realized it was such a complicated task lol, i’m working on trying your :IntersectAsync method (which looks super promising, and i really appreciate the digging!!), but while i do that, i can for sure provide some more information!
i have a building system right now, and i need to be able to stop players from placing a build that’s like too far inside of another part if that makes sense?? like if more than 50% of the part that the player is placing is covered up by other parts placed by other players (or non-player built parts), then the player shouldn’t be able to place it.
this doesn’t need to be too precise, it can probably safely have a margin of error of like 10-15% at the highest.
@sanjay2003 and @2112Jay – y’all’s code would work, but only when rotation isn’t taken into account, which i forgot to mention that I need in my original post! i really do appreciate all of your help, and I’ll update this thread whenever i figure anything out!!!
oops nevermind ignore past me saying that a distance check would work does not account for non equilateral shapes
it definitely looks like there could be a simpler solution though, but thats when some teamwork or someone much smarter than me might need to step in haha
the :IntersectAsync should just be a temporary solution until you can find a simpler one
Are your parts axis aligned? Because that is obviously an easier special case where the intersection volume is also a rectangular prism.
For two arbitrarily-oriented parts (parts rotated any imaginable way), your best option is to find the edge-face intersection points first, which is line-plane intersection with some bounds checks, and then once you have all the points, you can do a convex decomposition of the intersection volume into tetrahedrons by picking a point in the center of the volume and dividing the volume up into tetrahedrons of all the corners and intersection points to that central point. There is an explicit formula for the volume of a tetrahedron. You can Google convex decomposition for more resources; the generalized n-dimensional form of this technique is called simplex decomposition.
ur so good, don’t worry abt it! i was doing some benchmarking, and it looks like :IntersectAsync with two cuboids takes just about 0.01 seconds, so it’s not too bad! there’s gotta be a simpler solution though, i agree! i can’t be the first person with this issue lol
This is not as alien as you think. In your screenshot, h1, h2, h3 are what you know as Part.Size.X, Y, Z. And the basis e1, e2, e3, is just CFrame.RightVector, UpVector, LookVector. The 8 equations are just the cube center plus the diagonal to each corner.
Computational Geometry, from which many subproblems are going to involve linear algebra, but also geometry and trigonometry (and if you start working with more complex meshes, also some topology, graph theory, and measure theory).
this would probably work! it sounds like you know what you’re talking about, but i borderline failed geometry freshman year, so this is definitely above my area of expertise.
it’ll probably help someone smarter than me though, thank you so much!
i made a function that does this! i can’t vouch for the efficiency of it, but from my testing, it works with a margin of error of <0.01%. It should run in under 0.01 seconds aswell, but that might vary.
local function GetOverlapPercents(PartA,PartB)
local Intersection = PartA:IntersectAsync({PartB})
if not Intersection then
-- either parts are 100% perfectly overlapping eachother or the parts aren't touching at all
for _,Part in ipairs(PartA:GetTouchingParts()) do
if Part == PartB then return 100,100 end
end
return 0,0
end
local IntVol = Intersection:GetMass() / PhysicalProperties.new(Intersection.Material).Density
local PartAVol = PartA:GetMass() / PhysicalProperties.new(PartA.Material).Density
local PartBVol = PartB:GetMass() / PhysicalProperties.new(PartB.Material).Density
local PartAIntPercentage = IntVol / PartAVol
local PartBIntPercentage = IntVol/ PartBVol
return PartAIntPercentage * 100, PartBIntPercentage * 100
end
local AOverlap,BOverlap = GetOverlapPercents(workspace.PartA,workspace.PartB)
print(AOverlap.."% of PartA is overlapped by PartB.")
print(BOverlap.."% of PartB is overlapped by PartA.")
thanks @syyIvi for your help!! i wouldn’t have been able to think about that otherwise lol
and thank you to everyone else, really appreciate it!!