Added frustum and other intersect functions
This commit is contained in:
parent
f83b60e1e5
commit
a57673dcaf
@ -1,24 +1,159 @@
|
||||
--- Various geometric intersections
|
||||
-- @module intersect
|
||||
|
||||
local current_folder = (...):gsub('%.[^%.]+$', '') .. "."
|
||||
local modules = (...):gsub('%.[^%.]+$', '') .. "."
|
||||
local constants = require(modules .. "constants")
|
||||
local vec3 = require(modules .. "vec3")
|
||||
local mat4 = require(modules .. "mat4")
|
||||
local DBL_EPSILON = constants.DBL_EPSILON
|
||||
local sqrt = math.sqrt
|
||||
local abs = math.abs
|
||||
local min = math.min
|
||||
local max = math.max
|
||||
local intersect = {}
|
||||
|
||||
local constants = require(current_folder .. "constants")
|
||||
local vec3 = require(current_folder .. "vec3")
|
||||
-- http://www.peroxide.dk/papers/collision/collision.pdf
|
||||
-- point is a vec3
|
||||
-- triangle[1] is a vec3
|
||||
-- triangle[2] is a vec3
|
||||
-- triangle[3] is a vec3
|
||||
function intersect.point_triangle(point, triangle)
|
||||
local t21 = triangle[2] - triangle[1]
|
||||
local t31 = triangle[3] - triangle[1]
|
||||
|
||||
local abs, min, max = math.abs, math.min, math.max
|
||||
local FLT_EPSILON = constants.FLT_EPSILON
|
||||
local a = t21:dot(t21)
|
||||
local b = t21:dot(t31)
|
||||
local c = t31:dot(t31)
|
||||
local ac_bb = a * c - b * b
|
||||
|
||||
local intersect = {}
|
||||
local v = vec3(
|
||||
point.x - triangle[1].x,
|
||||
point.y - triangle[1].y,
|
||||
point.z - triangle[1].z
|
||||
)
|
||||
|
||||
local d = v:dot(t21)
|
||||
local e = v:dot(t31)
|
||||
|
||||
-- ray.position is a vec3
|
||||
-- ray.direction is a vec3
|
||||
local x = d * c - e * b
|
||||
local y = e * a - d * b
|
||||
local z = x + y - ac_bb
|
||||
|
||||
return
|
||||
x >= 0 and
|
||||
y >= 0 and
|
||||
z < 0
|
||||
end
|
||||
|
||||
-- point is a vec3
|
||||
-- aabb.min is a vec3
|
||||
-- aabb.max is a vec3
|
||||
function intersect.point_aabb(point, aabb)
|
||||
return
|
||||
aabb.min.x <= point.x and
|
||||
aabb.max.x >= point.x and
|
||||
aabb.min.y <= point.y and
|
||||
aabb.max.y >= point.y and
|
||||
aabb.min.z <= point.z and
|
||||
aabb.max.z >= point.z
|
||||
end
|
||||
|
||||
-- http://www.lighthouse3d.com/tutorials/maths/ray-triangle-intersection/
|
||||
-- ray.position is a vec3
|
||||
-- ray.direction is a vec3
|
||||
-- triangle[1] is a vec3
|
||||
-- triangle[2] is a vec3
|
||||
-- triangle[3] is a vec3
|
||||
local h, s, q, e1, e2 = vec3(), vec3(), vec3(), vec3(), vec3()
|
||||
function intersect.ray_triangle(ray, triangle)
|
||||
e1:sub(triangle[2], triangle[1])
|
||||
e2:sub(triangle[3], triangle[1])
|
||||
h:cross(ray.direction, e2)
|
||||
|
||||
local a = h:dot(e1)
|
||||
|
||||
-- if a is too close to 0, ray does not intersect triangle
|
||||
if abs(a) <= DBL_EPSILON then
|
||||
return false
|
||||
end
|
||||
|
||||
local f = 1 / a
|
||||
s:sub(ray.position, triangle[1])
|
||||
local u = s:dot(h) * f
|
||||
|
||||
-- ray does not intersect triangle
|
||||
if u < 0 or u > 1 then
|
||||
return false
|
||||
end
|
||||
|
||||
q:cross(s, e1)
|
||||
local v = ray.direction:dot(q) * f
|
||||
|
||||
-- ray does not intersect triangle
|
||||
if v < 0 or u + v > 1 then
|
||||
return false
|
||||
end
|
||||
|
||||
-- at this stage we can compute t to find out where
|
||||
-- the intersection point is on the line
|
||||
local t = q:dot(e2) * f
|
||||
|
||||
-- return position of intersection
|
||||
if t >= DBL_EPSILON then
|
||||
local out = vec3()
|
||||
:mul(ray.direction, t)
|
||||
:add(ray.position, out)
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
-- ray does not intersect triangle
|
||||
return false
|
||||
end
|
||||
|
||||
-- https://gamedev.stackexchange.com/questions/96459/fast-ray-sphere-collision-code
|
||||
-- ray.position is a vec3
|
||||
-- ray.direction is a vec3
|
||||
-- sphere.position is a vec3
|
||||
-- sphere.radius is a number
|
||||
function intersect.ray_sphere(ray, sphere)
|
||||
local offset = ray.position - sphere.position
|
||||
local b = offset:dot(ray.direction)
|
||||
local c = offset:dot(offset) - sphere.radius * sphere.radius
|
||||
|
||||
-- ray's position outside sphere (c > 0)
|
||||
-- ray's direction pointing away from sphere (b > 0)
|
||||
if c > 0 and b > 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
local discr = b * b - c
|
||||
|
||||
-- negative discriminant
|
||||
if discr < 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
local t = -b - sqrt(discr)
|
||||
|
||||
-- Clamp t to 0
|
||||
t = t < 0 and 0 or t
|
||||
|
||||
local out = vec3()
|
||||
:add(ray.position, ray.direction)
|
||||
:mul(out, t)
|
||||
|
||||
-- Return collision point and distance from ray origin
|
||||
return out, t
|
||||
end
|
||||
|
||||
-- ray.position is a vec3
|
||||
-- ray.direction is a vec3
|
||||
-- aabb.min is a vec3
|
||||
-- aabb.max is a vec3
|
||||
local dir, dirfrac = vec3(), vec3()
|
||||
function intersect.ray_aabb(ray, aabb)
|
||||
vec3.normalize(dir, ray.direction)
|
||||
dir:normalize(ray.direction)
|
||||
dirfrac.x = 1 / dir.x
|
||||
dirfrac.y = 1 / dir.y
|
||||
dirfrac.z = 1 / dir.z
|
||||
@ -47,14 +182,14 @@ function intersect.ray_aabb(ray, aabb)
|
||||
return tmin
|
||||
end
|
||||
|
||||
-- ray.position is a vec3
|
||||
-- ray.direction is a vec3
|
||||
-- plane.position is a vec3
|
||||
-- plane.normal is a vec3
|
||||
-- https://www.cs.princeton.edu/courses/archive/fall00/cs426/lectures/raycast/sld017.htm
|
||||
-- ray.position is a vec3
|
||||
-- ray.direction is a vec3
|
||||
-- plane.position is a vec3
|
||||
-- plane.normal is a vec3
|
||||
function intersect.ray_plane(ray, plane)
|
||||
local d = vec3.dist(ray.position, plane.position)
|
||||
local r = vec3.dot(ray.direction, plane.normal)
|
||||
local d = ray.position:dist(plane.position)
|
||||
local r = ray.direction:dot(plane.normal)
|
||||
|
||||
-- ray does not intersect plane
|
||||
if r <= 0 then
|
||||
@ -62,13 +197,13 @@ function intersect.ray_plane(ray, plane)
|
||||
end
|
||||
|
||||
-- distance of direction
|
||||
local t = -(vec3.dot(ray.position, plane.normal) + d) / r
|
||||
local t = -(ray.position:dot(plane.normal) + d) / r
|
||||
local out = vec3()
|
||||
vec3.mul(out, ray.direction, t)
|
||||
vec3.add(out, ray.position, out)
|
||||
:mul(ray.direction, t)
|
||||
:add(ray.position, out)
|
||||
|
||||
-- return position of intersection
|
||||
if vec3.dot(out, plane.normal) + d < FLT_EPSILON then
|
||||
if out:dot(plane.normal) + d < DBL_EPSILON then
|
||||
return out
|
||||
end
|
||||
|
||||
@ -76,87 +211,35 @@ function intersect.ray_plane(ray, plane)
|
||||
return false
|
||||
end
|
||||
|
||||
-- ray.position is a vec3
|
||||
-- ray.direction is a vec3
|
||||
-- triangle[1] is a vec3
|
||||
-- triangle[2] is a vec3
|
||||
-- triangle[3] is a vec3
|
||||
-- http://www.lighthouse3d.com/tutorials/maths/ray-triangle-intersection/
|
||||
local h, s, q, e1, e2 = vec3(), vec3(), vec3(), vec3(), vec3()
|
||||
function intersect.ray_triangle(ray, triangle)
|
||||
vec3.sub(e1, triangle[2], triangle[1])
|
||||
vec3.sub(e2, triangle[3], triangle[1])
|
||||
|
||||
vec3.cross(h, ray.direction, e2)
|
||||
local a = vec3.dot(h, e1)
|
||||
|
||||
-- if a is too close to 0, ray does not intersect triangle
|
||||
if abs(a) <= FLT_EPSILON then
|
||||
return false
|
||||
end
|
||||
|
||||
local f = 1 / a
|
||||
vec3.sub(s, ray.position, triangle[1])
|
||||
local u = vec3.dot(s, h) * f
|
||||
|
||||
-- ray does not intersect triangle
|
||||
if u < 0 or u > 1 then
|
||||
return false
|
||||
end
|
||||
|
||||
vec3.cross(q, s, e1)
|
||||
local v = vec3.dot(ray.direction, q) * f
|
||||
|
||||
-- ray does not intersect triangle
|
||||
if v < 0 or u + v > 1 then
|
||||
return false
|
||||
end
|
||||
|
||||
-- at this stage we can compute t to find out where
|
||||
-- the intersection point is on the line
|
||||
local t = vec3.dot(q, e2) * f
|
||||
|
||||
-- return position of intersection
|
||||
if t >= FLT_EPSILON then
|
||||
local out = vec3()
|
||||
vec3.mul(out, ray.direction, t)
|
||||
vec3.add(out, ray.position, out)
|
||||
return out
|
||||
end
|
||||
|
||||
-- ray does not intersect triangle
|
||||
return false
|
||||
end
|
||||
|
||||
-- Algorithm is ported from the C algorithm of
|
||||
-- Paul Bourke at http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline3d/
|
||||
-- Archive.org am hero \o/
|
||||
-- a[1] is a vec3
|
||||
-- a[2] is a vec3
|
||||
-- b[1] is a vec3
|
||||
-- b[2] is a vec3
|
||||
-- Algorithm is ported from the C algorithm of
|
||||
-- Paul Bourke at http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline3d/
|
||||
-- Archive.org am hero \o/
|
||||
local p13, p43, p21, out1, out2 = vec3(), vec3(), vec3(), vec3(), vec3()
|
||||
function intersect.line_line(a, b)
|
||||
-- new points
|
||||
vec3.sub(p13, a[1], b[1])
|
||||
vec3.sub(p43, b[2], b[1])
|
||||
vec3.sub(p21, a[2], a[1])
|
||||
p13:sub(a[1], b[1])
|
||||
p43:sub(b[2], b[1])
|
||||
p21:sub(a[2], a[1])
|
||||
|
||||
-- if lengths are negative or too close to 0, lines do not intersect
|
||||
if vec3.len2(p43) < FLT_EPSILON or vec3.len2(p21) < FLT_EPSILON then
|
||||
if p43:len2() < DBL_EPSILON or p21:len2() < DBL_EPSILON then
|
||||
return false
|
||||
end
|
||||
|
||||
-- dot products
|
||||
local d1343 = vec3.dot(p13, p43)
|
||||
local d4321 = vec3.dot(p43, p21)
|
||||
local d1321 = vec3.dot(p13, p21)
|
||||
local d4343 = vec3.dot(p43, p43)
|
||||
local d2121 = vec3.dot(p21, p21)
|
||||
local d1343 = p13:dot(p43)
|
||||
local d4321 = p43:dot(p21)
|
||||
local d1321 = p13:dot(p21)
|
||||
local d4343 = p43:dot(p43)
|
||||
local d2121 = p21:dot(p21)
|
||||
local denom = d2121 * d4343 - d4321 * d4321
|
||||
|
||||
-- if denom is too close to 0, lines do not intersect
|
||||
if abs(denom) < FLT_EPSILON then
|
||||
if abs(denom) < DBL_EPSILON then
|
||||
return false
|
||||
end
|
||||
|
||||
@ -165,10 +248,10 @@ function intersect.line_line(a, b)
|
||||
local mub = (d1343 + d4321 * (mua)) / d4343
|
||||
|
||||
-- return positions of intersection on each line
|
||||
vec3.mul(out1, mua, p21)
|
||||
vec3.add(out1, a[1], out)
|
||||
vec3.mul(out2, mub, p43)
|
||||
vec3.add(out2, b[1], out2)
|
||||
out1:mul(mua, p21)
|
||||
out1:add(a[1], out1)
|
||||
out2:mul(mub, p43)
|
||||
out2:add(b[1], out2)
|
||||
|
||||
return out1, out2
|
||||
end
|
||||
@ -192,19 +275,6 @@ function intersect.segment_segment(a, b)
|
||||
return false
|
||||
end
|
||||
|
||||
-- point is a vec3
|
||||
-- aabb.min is a vec3
|
||||
-- aabb.max is a vec3
|
||||
function intersect.point_aabb(point, aabb)
|
||||
return
|
||||
aabb.min.x <= point.x and
|
||||
aabb.max.x >= point.x and
|
||||
aabb.min.y <= point.y and
|
||||
aabb.max.y >= point.y and
|
||||
aabb.min.z <= point.z and
|
||||
aabb.max.z >= point.z
|
||||
end
|
||||
|
||||
-- a.min is a vec3
|
||||
-- a.max is a vec3
|
||||
-- b.min is a vec3
|
||||
@ -219,6 +289,184 @@ function intersect.aabb_aabb(a, b)
|
||||
a.max.z >= b.min.z
|
||||
end
|
||||
|
||||
-- aabb.position is a vec3
|
||||
-- aabb.extent is a vec3 (half-size)
|
||||
-- obb.position is a vec3
|
||||
-- obb.extent is a vec3 (half-size)
|
||||
-- obb.rotation is a mat4
|
||||
function intersect.aabb_obb(aabb, obb)
|
||||
local a = aabb.extent
|
||||
local b = obb.extent
|
||||
local T = obb.position - aabb.position
|
||||
local rot = mat4():transpose(obb.rotation)
|
||||
local reps = 1e-6
|
||||
local B = {}
|
||||
|
||||
for i = 1, 3 do
|
||||
B[i] = {}
|
||||
for j = 1, 3 do
|
||||
assert((i - 1) * 4 + j < 16 and (i - 1) * 4 + j > 0)
|
||||
B[i][j] = abs(rot[(i - 1) * 4 + j]) + reps
|
||||
end
|
||||
end
|
||||
|
||||
local t, s
|
||||
local r = 1
|
||||
|
||||
t = abs(T.x)
|
||||
if not (t <= (b.x + a.x * B[1][1] + b.y * B[1][2] + b.z * B[1][3])) then return false end
|
||||
|
||||
s = T.x * B[1][1] + T.y*B[2][1] + T.z*B[3][1]
|
||||
t = abs(s)
|
||||
if not (t <= (b.x + a.x * B[1][1] + a.y * B[2][1] + a.z * B[3][1])) then return false end
|
||||
|
||||
t = abs(T.y)
|
||||
if not (t <= (a.y + b.x * B[2][1] + b.y * B[2][2] + b.z * B[2][3])) then return false end
|
||||
|
||||
t = abs(T.z)
|
||||
if not (t <= (a.z + b.x * B[3][1] + b.y * B[3][2] + b.z * B[3][3])) then return false end
|
||||
|
||||
s = T.x * B[1][2] + T.y * B[2][2] + T.z * B[3][2]
|
||||
t = abs(s)
|
||||
if not (t <= (b.y + a.x * B[1][2] + a.y * B[2][2] + a.z * B[3][2])) then return false end
|
||||
|
||||
s = T.x * B[1][3] + T.y * B[2][3] + T.z * B[3][3]
|
||||
t = abs(s)
|
||||
if not (t <= (b.z + a.x * B[1][3] + a.y * B[2][3] + a.z * B[3][3])) then return false end
|
||||
|
||||
s = T.z * B[2][1] - T.y * B[3][1]
|
||||
t = abs(s)
|
||||
if not (t <= (a.y * B[3][1] + a.z * B[2][1] + b.y * B[1][3] + b.z * B[1][2])) then return false end
|
||||
|
||||
s = T.z * B[2][2] - T.y * B[3][2]
|
||||
t = abs(s)
|
||||
if not (t <= (a.y * B[3][2] + a.z * B[2][2] + b.x * B[1][3] + b.z * B[1][1])) then return false end
|
||||
|
||||
s = T.z * B[2][3] - T.y * B[3][3]
|
||||
t = abs(s)
|
||||
if not (t <= (a.y * B[3][3] + a.z * B[2][3] + b.x * B[1][2] + b.y * B[1][1])) then return false end
|
||||
|
||||
s = T.x * B[3][1] - T.z * B[1][1]
|
||||
t = abs(s)
|
||||
if not (t <= (a.x * B[3][1] + a.z * B[1][1] + b.y * B[2][3] + b.z * B[2][2])) then return false end
|
||||
|
||||
s = T.x * B[3][2] - T.z * B[1][2]
|
||||
t = abs(s)
|
||||
if not (t <= (a.x * B[3][2] + a.z * B[1][2] + b.x * B[2][3] + b.z * B[2][1])) then return false end
|
||||
|
||||
s = T.x * B[3][3] - T.z * B[1][3]
|
||||
t = abs(s)
|
||||
if not (t <= (a.x * B[3][3] + a.z * B[1][3] + b.x * B[2][2] + b.y * B[2][1])) then return false end
|
||||
|
||||
s = T.y * B[1][1] - T.x * B[2][1]
|
||||
t = abs(s)
|
||||
if not (t <= (a.x * B[2][1] + a.y * B[1][1] + b.y * B[3][3] + b.z * B[3][2])) then return false end
|
||||
|
||||
s = T.y * B[1][2] - T.x * B[2][2]
|
||||
t = abs(s)
|
||||
if not (t <= (a.x * B[2][2] + a.y * B[1][2] + b.x * B[3][3] + b.z * B[3][1])) then return false end
|
||||
|
||||
s = T.y * B[1][3] - T.x * B[2][3]
|
||||
t = abs(s)
|
||||
if not (t <= (a.x * B[2][3] + a.y * B[1][3] + b.x * B[3][2] + b.y * B[3][1])) then return false end
|
||||
|
||||
-- https://gamedev.stackexchange.com/questions/24078/which-side-was-hit
|
||||
-- Minkowski Sum
|
||||
local wy = (aabb.extent * 2 + obb.extent * 2) * (aabb.position.y - obb.position.y)
|
||||
local hx = (aabb.extent * 2 + obb.extent * 2) * (aabb.position.x - obb.position.x)
|
||||
|
||||
if wy > hx then
|
||||
if wy > -hx then
|
||||
return vec3(mat4.mul_mat4x1(obb.rotation, { 0, -1, 0, 1 }))
|
||||
else
|
||||
return vec3(mat4.mul_mat4x1(obb.rotation, { -1, 0, 0, 1 }))
|
||||
end
|
||||
else
|
||||
if wy > -hx then
|
||||
return vec3(mat4.mul_mat4x1(obb.rotation, { 1, 0, 0, 1 }))
|
||||
else
|
||||
return vec3(mat4.mul_mat4x1(obb.rotation, { 0, 1, 0, 1 }))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- aabb.min is a vec3
|
||||
-- aabb.max is a vec3
|
||||
-- sphere.position is a vec3
|
||||
-- sphere.radius is a number
|
||||
local axes = { "x", "y", "z" }
|
||||
function intersect.aabb_sphere(aabb, sphere) -- { position, radius }
|
||||
local dmin = 0
|
||||
|
||||
for _, axis in ipairs(axes) do
|
||||
local pos = sphere.position[axis]
|
||||
local min = box.min[axis]
|
||||
local max = box.max[axis]
|
||||
|
||||
if pos < min then
|
||||
dmin = dmin + (pos - min) ^ 2
|
||||
elseif pos > max then
|
||||
dmin = dmin + (pos - max) ^ 2
|
||||
end
|
||||
end
|
||||
|
||||
return dmin <= radius ^ 2
|
||||
end
|
||||
|
||||
-- aabb.min is a vec3
|
||||
-- aabb.max is a vec3
|
||||
-- frustum.top is a plane { a, b, c, d }
|
||||
-- frustum.bottom is a plane { a, b, c, d }
|
||||
-- frustum.left is a plane { a, b, c, d }
|
||||
-- frustum.right is a plane { a, b, c, d }
|
||||
-- frustum.near is a plane { a, b, c, d }
|
||||
-- frustum.far is a plane { a, b, c, d }
|
||||
function intersect.aabb_frustum(aabb, frustum)
|
||||
-- Indexed for the 'index trick' later
|
||||
local box = {
|
||||
aabb.min,
|
||||
aabb.max
|
||||
}
|
||||
|
||||
-- We have 6 planes defining the frustum, 5 if infinite.
|
||||
local planes = {
|
||||
frustum.top,
|
||||
frustum.bottom,
|
||||
frustum.left,
|
||||
frustum.right,
|
||||
frustum.near,
|
||||
frustum.far or false
|
||||
}
|
||||
|
||||
-- Skip the last test for infinite projections, it'll never fail.
|
||||
if not planes[6] then
|
||||
table.remove(planes)
|
||||
end
|
||||
|
||||
for i = 1, #planes do
|
||||
-- This is the current plane
|
||||
local p = planes[i]
|
||||
|
||||
-- p-vertex selection (with the index trick)
|
||||
-- According to the plane normal we can know the
|
||||
-- indices of the positive vertex
|
||||
local px = p.a > 0.0 and 2 or 1
|
||||
local py = p.b > 0.0 and 2 or 1
|
||||
local pz = (.c > 0.0 and 2 or 1
|
||||
|
||||
-- project p-vertex on plane normal
|
||||
-- (How far is p-vertex from the origin)
|
||||
local dot = (p.a * box[px].x) + (p.b * box[py].y) + (p.c * box[pz].z)
|
||||
|
||||
-- Doesn't intersect if it is behind the plane
|
||||
if dot < -p.d then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
-- outer.min is a vec3
|
||||
-- outer.max is a vec3
|
||||
-- inner.min is a vec3
|
||||
@ -230,11 +478,56 @@ function intersect.encapsulate_aabb(outer, inner)
|
||||
end
|
||||
|
||||
-- a.position is a vec3
|
||||
-- a.radius is a number
|
||||
-- a.radius is a number
|
||||
-- b.position is a vec3
|
||||
-- b.radius is a number
|
||||
-- b.radius is a number
|
||||
function intersect.circle_circle(a, b)
|
||||
return vec3.dist(a.position, b.position) <= a.radius + b.radius
|
||||
return a.position:dist(b.position) <= a.radius + b.radius
|
||||
end
|
||||
|
||||
-- a.position is a vec3
|
||||
-- a.radius is a number
|
||||
-- b.position is a vec3
|
||||
-- b.radius is a number
|
||||
function intersect.sphere_sphere(a, b)
|
||||
return intersect.circle_circle(a, b)
|
||||
end
|
||||
|
||||
-- sphere.position is a vec3
|
||||
-- sphere.radius is a number
|
||||
-- frustum.top is a plane { a, b, c, d }
|
||||
-- frustum.bottom is a plane { a, b, c, d }
|
||||
-- frustum.left is a plane { a, b, c, d }
|
||||
-- frustum.right is a plane { a, b, c, d }
|
||||
-- frustum.near is a plane { a, b, c, d }
|
||||
-- frustum.far is a plane { a, b, c, d }
|
||||
function intersect.sphere_frustum(sphere, frustum)
|
||||
local x, y, z = sphere.position:unpack()
|
||||
|
||||
local planes = {
|
||||
frustum.top,
|
||||
frustum.bottom,
|
||||
frustum.left,
|
||||
frustum.right,
|
||||
frustum.near
|
||||
}
|
||||
|
||||
if frustum.far then
|
||||
table.insert(planes, frustum.far, 5)
|
||||
end
|
||||
|
||||
local dot
|
||||
for p = 1, #planes do
|
||||
dot = planes[p].a * x + planes[p].b * y + planes[p].c * z + planes[p].d
|
||||
|
||||
if dot <= -sphere.radius then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- dot + radius is the distance of the object from the near plane.
|
||||
-- make sure that the near plane is the last test!
|
||||
return dot + radius
|
||||
end
|
||||
|
||||
return intersect
|
||||
|
@ -529,6 +529,100 @@ function mat4.to_quat(a)
|
||||
return q:normalize(q)
|
||||
end
|
||||
|
||||
-- frustum = (proj * view):to_frustum(infinite)
|
||||
-- http://www.crownandcutlass.com/features/technicaldetails/frustum.html
|
||||
function mat4.to_frustum(a, infinite)
|
||||
local t
|
||||
local frustum = {}
|
||||
|
||||
-- Extract the TOP plane
|
||||
frustum.top = {}
|
||||
frustum.top.a = a[ 4] - a[ 2]
|
||||
frustum.top.b = a[ 8] - a[ 6]
|
||||
frustum.top.c = a[12] - a[10]
|
||||
frustum.top.d = a[16] - a[14]
|
||||
|
||||
-- Normalize the result
|
||||
t = sqrt(frustum.top.a * frustum.top.a + frustum.top.b * frustum.top.b + frustum.top.c * frustum.top.c)
|
||||
frustum.top.a = frustum.top.a / t
|
||||
frustum.top.b = frustum.top.b / t
|
||||
frustum.top.c = frustum.top.c / t
|
||||
frustum.top.d = frustum.top.d / t
|
||||
|
||||
-- Extract the BOTTOM plane
|
||||
frustum.bottom = {}
|
||||
frustum.bottom.a = a[ 4] + a[ 2]
|
||||
frustum.bottom.b = a[ 8] + a[ 6]
|
||||
frustum.bottom.c = a[12] + a[10]
|
||||
frustum.bottom.d = a[16] + a[14]
|
||||
|
||||
-- Normalize the result
|
||||
t = sqrt(frustum.bottom.a * frustum.bottom.a + frustum.bottom.b * frustum.bottom.b + frustum.bottom.c * frustum.bottom.c)
|
||||
frustum.bottom.a = frustum.bottom.a / t
|
||||
frustum.bottom.b = frustum.bottom.b / t
|
||||
frustum.bottom.c = frustum.bottom.c / t
|
||||
frustum.bottom.d = frustum.bottom.d / t
|
||||
|
||||
-- Extract the LEFT plane
|
||||
frustum.left.a = a[ 4] + a[ 1]
|
||||
frustum.left.b = a[ 8] + a[ 5]
|
||||
frustum.left.c = a[12] + a[ 9]
|
||||
frustum.left.d = a[16] + a[13]
|
||||
|
||||
-- Normalize the result
|
||||
t = sqrt(frustum.left.a * frustum.left.a + frustum.left.b * frustum.left.b + frustum.left.c * frustum.left.c)
|
||||
frustum.left.a = frustum.left.a / t
|
||||
frustum.left.b = frustum.left.b / t
|
||||
frustum.left.c = frustum.left.c / t
|
||||
frustum.left.d = frustum.left.d / t
|
||||
|
||||
-- Extract the RIGHT plane
|
||||
frustum.right = {}
|
||||
frustum.right.a = a[ 4] - a[ 1]
|
||||
frustum.right.b = a[ 8] - a[ 5]
|
||||
frustum.right.c = a[12] - a[ 9]
|
||||
frustum.right.d = a[16] - a[13]
|
||||
|
||||
-- Normalize the result
|
||||
t = sqrt(frustum.right.a * frustum.right.a + frustum.right.b * frustum.right.b + frustum.right.c * frustum.right.c)
|
||||
frustum.right.a = frustum.right.a / t
|
||||
frustum.right.b = frustum.right.b / t
|
||||
frustum.right.c = frustum.right.c / t
|
||||
frustum.right.d = frustum.right.d / t
|
||||
|
||||
-- Extract the NEAR plane
|
||||
frustum.near = {}
|
||||
frustum.near.a = a[ 4] + a[ 3]
|
||||
frustum.near.b = a[ 8] + a[ 7]
|
||||
frustum.near.c = a[12] + a[11]
|
||||
frustum.near.d = a[16] + a[15]
|
||||
|
||||
-- Normalize the result
|
||||
t = sqrt(frustum.near.a * frustum.near.a + frustum.near.b * frustum.near.b + frustum.near.c * frustum.near.c)
|
||||
frustum.near.a = frustum.near.a / t
|
||||
frustum.near.b = frustum.near.b / t
|
||||
frustum.near.c = frustum.near.c / t
|
||||
frustum.near.d = frustum.near.d / t
|
||||
|
||||
if not infinite then
|
||||
-- Extract the FAR plane
|
||||
frustum.far = {}
|
||||
frustum.far.a = a[ 4] - a[ 3]
|
||||
frustum.far.b = a[ 8] - a[ 7]
|
||||
frustum.far.c = a[12] - a[11]
|
||||
frustum.far.d = a[16] - a[15]
|
||||
|
||||
-- Normalize the result
|
||||
t = sqrt(frustum.far.a * frustum.far.a + frustum.far.b * frustum.far.b + frustum.far.c * frustum.far.c)
|
||||
frustum.far.a = frustum.far.a / t
|
||||
frustum.far.b = frustum.far.b / t
|
||||
frustum.far.c = frustum.far.c / t
|
||||
frustum.far.d = frustum.far.d / t
|
||||
end
|
||||
|
||||
return frustum
|
||||
end
|
||||
|
||||
local mat4_mt = {}
|
||||
mat4_mt.__index = mat4
|
||||
mat4_mt.__tostring = mat4.to_string
|
||||
|
Loading…
x
Reference in New Issue
Block a user