of     1   

ArbiterOfDeath
#122305175Sunday, January 05, 2014 3:20 AM GMT

For a pathfinder I'm building, I need the ability to test two parts for collision, that do not exist in the workspace yet. Putting them into the Workspace and waiting for a hit event would take to much time, so I rolled my own OBB-OBB collision detection program. But I'm have a problem with it. I used the SAT (Separating Axis Theorem) to test. It works by trying to find a separating plane between the two parts. To do this, you test a few normals. you can tell if two parts cross the plane by seeing if their point's projections onto the normal overlap. To find out more, search google. The code should be commented enough for you to find out the rest. The peps in SH had no idea what SAT was.... My issue is that sometimes parts that are close, but not touching, are reported as touching and rarely parts that are touching are reported at not touching. There is two functions. part_part_collision is the main function. local i = Vector3.new(1, 0, 0) local j = Vector3.new(0, 1, 0) local k = Vector3.new(0, 0, 1) local function get_points(part) --The rotation and position of the part local rot = part.CFrame local pos = part.Position --Positions is in the center, so offset in each --direction by half of the size. local size = part.Size * 0.5 --The parts axises local i = rot:vectorToWorldSpace(i) local j = rot:vectorToWorldSpace(j) local k = rot:vectorToWorldSpace(k) --Scale by size local x, y, z = size.x, size.y, size.z --return dem points! return { -x*i + -y*j + -z*k + pos, -x*i + -y*j + z*k + pos, -x*i + y*j + -z*k + pos, -x*i + y*j + z*k + pos, x*i + -y*j + -z*k + pos, x*i + -y*j + z*k + pos, x*i + y*j + -z*k + pos, x*i + y*j + z*k + pos, } end local function part_part_collision(p1, p2) --A list of the part's points, and their CFrames local p1_points = get_points(p1) local p2_points = get_points(p2) local p1_cf = p1.CFrame local p2_cf = p2.CFrame --All the normals that must be tested. 3 axises from --part1, 3 axises from part2, and the 9 cross products --of those axises. local n = { p1_cf:vectorToObjectSpace(i); p1_cf:vectorToObjectSpace(j); p1_cf:vectorToObjectSpace(k); p2_cf:vectorToObjectSpace(i); p2_cf:vectorToObjectSpace(j); p2_cf:vectorToObjectSpace(k); } n[7] = n[1]:Cross(n[4]) n[8] = n[1]:Cross(n[5]) n[9] = n[1]:Cross(n[6]) n[10] = n[2]:Cross(n[4]) n[11] = n[2]:Cross(n[5]) n[12] = n[2]:Cross(n[6]) n[13] = n[3]:Cross(n[4]) n[14] = n[3]:Cross(n[5]) n[15] = n[3]:Cross(n[6]) --The projection of a onto the normal is really the --a:Dot(normal)/normal.magnitude, but sense we are --only testing for overlap in the numorator, we drop --the denominator of normal.magnitude for speed. for _, normal in next, n do --The range for part1 projections on the normal local p1_min = p1_points[1]:Dot(normal) local p1_max = p1_min for i = 2, #p1_points do local scalar = p1_points[i]:Dot(normal) if scalar < p1_min then p1_min = scalar elseif scalar > p1_max then p1_max = scalar end end --The range for part2 projections on the normal local p2_min = p2_points[2]:Dot(normal) local p2_max = p2_min for i = 2, #p2_points do local scalar = p2_points[i]:Dot(normal) if scalar < p2_min then p2_min = scalar elseif scalar > p2_max then p2_max = scalar end end --if the ranges don't overlap, then the parts don't intersect. if p2_max p1_max then return false end end --There must be a collision, we haven't found a gap. return true end
ArbiterOfDeath
#122312864Sunday, January 05, 2014 4:37 AM GMT

Discovered the issue. For all who want a working part-part intersection test, the lines that read p1_cf:vectorToObjectSpace(i); p1_cf:vectorToObjectSpace(j); p1_cf:vectorToObjectSpace(k); p2_cf:vectorToObjectSpace(i); p2_cf:vectorToObjectSpace(j); p2_cf:vectorToObjectSpace(k); should be p1_cf:vectorToWorldSpace(i); p1_cf:vectorToWorldSpace(j); p1_cf:vectorToWorldSpace(k); p2_cf:vectorToWorldSpace(i); p2_cf:vectorToWorldSpace(j); p2_cf:vectorToWorldSpace(k); Such a small difference... I knew it was something simple!
appropriations
#122334635Sunday, January 05, 2014 10:02 AM GMT

Wait... So you can use this to detect touches on parts that don't exist? Keyboard not found. Press F1 to continue.
ArbiterOfDeath
#123442629Saturday, January 18, 2014 10:14 PM GMT

Yup, that's right.
TheNickmaster21
#123444183Saturday, January 18, 2014 10:31 PM GMT

Impressive ._.
suremark
#123446327Saturday, January 18, 2014 10:57 PM GMT

I haven't dabbled much into collision detection. What is the math behind this? What do you mean by "normals"?
celestala
#123448597Saturday, January 18, 2014 11:24 PM GMT

That's insane. Could you provide some more explanation on the math behind this, though?
VoidShredder
#123451193Saturday, January 18, 2014 11:55 PM GMT

Calculus~ level math x.x
Aerideyn
#123464979Sunday, January 19, 2014 2:31 AM GMT

The concept is easy enough once you get it and the math is easy - but you won't be able to understand how the math actually works without some reading and experimenting. Play around with the dot product of 2 vectors first and read about it until you understand what it does (projects one vector onto another, it sounds pretty intense until it all clicks in your head and then suddenly it is one of the most elegant concepts..) once you have that down then try searching for "separating axis theorem" personally i found the 3rd and the 4th result to be the most helpful - the 3rd one is probably where you want to start.
celestala
#123466634Sunday, January 19, 2014 2:48 AM GMT

^ I'll do that, thanks for the help.
ArbiterOfDeath
#123474616Sunday, January 19, 2014 4:11 AM GMT

Sorry I didn't see your posts, guys. Basically what this does is look at the both part's points from 15 different views. For every view, it creates a line that runs through both of the parts, straight across the view. It then projects the points onto that line, meaning that if something it above the line, then it is now "projected" onto that line. From the view, it just looks like the height of the point changed, but it didn't move left or right. Basically that this does, is it allows us to check if any of the points look like they are intersecting, by testing their positions on this line. If the line created by the minimum and maximum points for a part intersect the line for the other part, then from the view that we are looking at, the parts intersect. You have to check all 15 views to be sure that the parts do not intersect, even if it is likely that they are after 6 views. The other 9 views are basically special cases to make sure that two edges are not intersecting. Btw, I also made a (ray/line/line segment)cast function as well. You should check out my collision detection library here: http://www.roblox.com/Collision-Detection-item?id=132752078 as a side note, you might be interested in my lua bytecode reader as well. Note that there is a couple bugs with it if you try to view more than one script, and that I haven't worked on it in a long time. Here it is: http://www.roblox.com/Byte-Spy-item?id=127231254

    of     1