Skip to content

Instantly share code, notes, and snippets.

@estama
Last active March 31, 2021 11:30
Show Gist options
  • Save estama/27a84874fd7e1ae9169228b6eb141d5a to your computer and use it in GitHub Desktop.
Save estama/27a84874fd7e1ae9169228b6eb141d5a to your computer and use it in GitHub Desktop.
function overlapsOBB_OBB(c1, x1, y1, z1, c2, x2, y2, z2)
local cc = c1 - c2
local d11, d12, d13 = abs(x1:dot(x2)), abs(x1:dot(y2)), abs(x1:dot(z2))
local d21, d22, d23 = abs(y1:dot(x2)), abs(y1:dot(y2)), abs(y1:dot(z2))
local d31, d32, d33 = abs(z1:dot(x2)), abs(z1:dot(y2)), abs(z1:dot(z2))
return abs(cc:dot(x1))-d11-d12-d13<=x1:squaredLength() and abs(cc:dot(y1))-d21-d22-d23<=y1:squaredLength()
and abs(cc:dot(z1))-d31-d32-d33<=z1:squaredLength() and abs(cc:dot(x2))-d11-d21-d31<=x2:squaredLength()
and abs(cc:dot(y2))-d12-d22-d32<=y2:squaredLength() and abs(cc:dot(z2))-d13-d23-d33<=z2:squaredLength()
end
-- untested
function containsOBB_OBB(c1, x1, y1, z1, c2, x2, y2, z2)
local cc = c1 - c2
return abs(cc:dot(x1))+abs(x1:dot(x2))+abs(x1:dot(y2))+abs(x1:dot(z2))<=x1:squaredLength()
and abs(cc:dot(y1))+abs(y1:dot(x2))+abs(y1:dot(y2))+abs(y1:dot(z2))<=y1:squaredLength()
and abs(cc:dot(z1))+abs(z1:dot(x2))+abs(z1:dot(y2))+abs(z1:dot(z2))<=z1:squaredLength()
end
function overlapsOBB_Sphere(c1, x1, y1, z1, c2, r2)
local cc = c1 - c2
local x1len, y1len, z1len = x1:length(), y1:length(), z1:length()
local ccx, ccy, ccz = abs(cc:dot(x1)), abs(cc:dot(y1)), abs(cc:dot(z1))
return ccx<=x1len*(x1len+r2) and ccy<=y1len*(y1len+r2) and ccz<=z1len*(z1len+r2)
and (ccx<=x1len*x1len or ccy<=y1len*y1len or ccz<=z1len*z1len or
square(ccx/(x1len+1e-30)-x1len)+square(ccy/(y1len+1e-30)-y1len)+square(ccz/(z1len+1e-30)-z1len)<=r2*r2)
end
function overlapsOBB_Plane(c1, x1, y1, z1, plpos, pln)
return abs((c1 - plpos):dot(pln))<=abs(x1:dot(pln))+abs(y1:dot(pln))+abs(z1:dot(pln))
end
function containsOBB_Sphere(c1, x1, y1, z1, c2, r2)
local cc = c1 - c2
local x1len, y1len, z1len = x1:length(), y1:length(), z1:length()
return abs(cc:dot(x1))<=x1len*(x1len-r2) and abs(cc:dot(y1))<=y1len*(y1len-r2) and abs(cc:dot(z1))<=z1len*(z1len-r2)
end
function containsSphere_OBB(c1, r1, c2, x2, y2, z2)
local cc = c1 - c2
local ccx1, cc_x2, y2z2, y2_z2 = cc+x2, cc-x2, y2+z2, y2-z2
return max((ccx1+y2z2):squaredLength(), (ccx1+y2_z2):squaredLength(), (ccx1-y2_z2):squaredLength(), (ccx1-y2z2):squaredLength(),
(cc_x2+y2z2):squaredLength(), (cc_x2+y2_z2):squaredLength(), (cc_x2-y2_z2):squaredLength(), (cc_x2-y2z2):squaredLength())<=r1*r1
end
function containsOBB_point(c1, x1, y1, z1, p)
local cc = c1 - p
return abs(cc:dot(x1))<=x1:squaredLength() and abs(cc:dot(y1))<=y1:squaredLength() and abs(cc:dot(z1))<=z1:squaredLength()
end
function containsEllipsoid_Point(c1, x1, y1, z1, p)
local cc = p - c1
local x, y, z = cc:dot(x1), cc:dot(y1), cc:dot(z1)
local a2, b2, c2 = x1:squaredLength(), y1:squaredLength(), z1:squaredLength()
a2, b2, c2 = a2*a2, b2*b2, c2*c2
local b2c2 = b2*c2
return x*x*b2c2 + a2*(y*y*c2 + z*z*b2) <= a2*b2c2
end
function constainsCylinder_Point(cposa, cposb, cR, p)
local xnorm, r2 = p:xnormSquaredDistanceToLineSegment(cposa, cposb)
return xnorm >=0 and xnorm <= 1 and r2 <= cR*cR
end
function altitudeOBB_Plane(c1, x1, y1, z1, plpos, pln)
return (c1 - plpos):dot(pln)+abs(x1:dot(pln))+abs(y1:dot(pln))+abs(z1:dot(pln))
end
-- returns signed distance of plane on the ray
function intersectsRay_Plane(rpos, rdir, plpos, pln)
return min((plpos - rpos):dot(pln) / rdir:dot(pln), math.huge)
end
-- hit: minhit < maxhit, inside: minhit < 0
function intersectsRay_Sphere(rpos, rdir, cpos, cr)
local rcpos = cpos - rpos
local dcr = rdir:dot(rcpos)
local s = dcr*dcr - rcpos:squaredLength() + cr*cr
if s < 0 then return math.huge, math.huge end
s = sqrt(s)
return dcr - s, dcr + s
end
function intersectsRay_Ellipsoid(rpos, rdir, c1, x1, y1, z1)
local invx1, invy1, invz1 = 1 / (x1:squaredLength() + 1e-30), 1 / (y1:squaredLength() + 1e-30), 1 / (z1:squaredLength() + 1e-30)
local cc = rpos - c1
local pM = vec3(cc:dot(x1)*invx1, cc:dot(y1)*invy1, cc:dot(z1)*invz1)
local dirM = vec3(rdir:dot(x1)*invx1, rdir:dot(y1)*invy1, rdir:dot(z1)*invz1)
local a, b, c = dirM:squaredLength(), 2*pM:dot(dirM), pM:squaredLength() - 1
local d = b*b - 4*a*c
if d < 0 then return math.huge, math.huge end
d = -b -sign(b)*sqrt(d)
local r1, r2 = 0.5*d / a, 2*c / d
return min(r1, r2), max(r1,r2)
end
function intersectsRay_Cylinder(rpos, rdir, cposa, cposb, cR)
local rca, cba = cposa - rpos, cposb - cposa
local cpnorm = cba:normalized()
local cp = rca:projectToOriginPlane(cpnorm)
local rdp = rdir:projectToOriginPlane(cpnorm)
local minhit, maxhit = intersectsRay_Sphere(vec3(0,0,0), rdp:normalized(), cp, cR)
local invrdplen = 1 / (rdp:length() + 1e-30)
minhit, maxhit = minhit * invrdplen, maxhit * invrdplen
local plhita, plhitb = intersectsRay_Plane(rpos, rdir, cposa, cpnorm), intersectsRay_Plane(rpos, rdir, cposb, cpnorm)
minhit, maxhit = max(minhit, min(plhita, plhitb)), min(maxhit, max(plhita, plhitb))
return (minhit <= maxhit and minhit or math.huge), maxhit
end
function intersectsRay_OBB(rpos, rdir, c1, x1, y1, z1)
local rposc1 = c1 - rpos
local rposc1x1, x1sq, invrdirx1 = rposc1:dot(x1), x1:squaredLength(), 1 / rdir:dot(x1)
local dx1, dx2 = (rposc1x1 - x1sq) * invrdirx1, min((rposc1x1 + x1sq) * invrdirx1, math.huge)
local rposc1y1, y1sq, invrdiry1 = rposc1:dot(y1), y1:squaredLength(), 1 / rdir:dot(y1)
local dy1, dy2 = (rposc1y1 - y1sq) * invrdiry1, min((rposc1y1 + y1sq) * invrdiry1, math.huge)
local rposc1z1, z1sq, invrdirz1 = rposc1:dot(z1), z1:squaredLength(), 1 / rdir:dot(z1)
local dz1, dz2 = (rposc1z1 - z1sq) * invrdirz1, min((rposc1z1 + z1sq) * invrdirz1, math.huge)
local minhit, maxhit = max(min(dx1, dx2), min(dy1, dy2), min(dz1, dz2)), min(max(dx1, dx2), max(dy1, dy2), max(dz1, dz2))
return (minhit <= maxhit and minhit or math.huge), maxhit
end
-- returns hit distance, barycentric x, y
function intersectsRay_triangle(rpos, rdir, a, b, c)
local ca, bc = c - a, b - c
local norm = ca:cross(bc)
local rposc = rpos - c
local pOnTri = rposc:dot(norm) / rdir:dot(norm)
if pOnTri <= 0 then
local pacnorm = (rposc - rdir * pOnTri):cross(norm)
local bx, by = bc:dot(pacnorm), ca:dot(pacnorm)
local normSq = norm:squaredLength() + 1e-30
if min(bx, by) >= 0 and bx + by <= normSq then
return -pOnTri, bx / normSq, by / normSq
end
end
return math.huge, -1, -1
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment