diff --git a/modules/intersect.lua b/modules/intersect.lua index 17ae847..2eee4d5 100644 --- a/modules/intersect.lua +++ b/modules/intersect.lua @@ -58,6 +58,40 @@ function intersect.point_aabb(point, aabb) aabb.max.z >= point.z end +-- point is a vec3 +-- frustum.left is a plane { a, b, c, d } +-- frustum.right is a plane { a, b, c, d } +-- frustum.bottom is a plane { a, b, c, d } +-- frustum.top 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.point_frustum(point, frustum) + local x, y, z = point:unpack() + local planes = { + frustum.left, + frustum.right, + frustum.bottom, + frustum.top, + 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 + + local dot + for i = 1, #planes do + dot = planes[i].a * x + planes[i].b * y + planes[i].c * z + planes[i].d + if dot <= 0 then + return false + end + end + + return true +end + -- http://www.lighthouse3d.com/tutorials/maths/ray-triangle-intersection/ -- ray.position is a vec3 -- ray.direction is a vec3 @@ -413,10 +447,10 @@ 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.bottom is a plane { a, b, c, d } +-- frustum.top 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) @@ -428,10 +462,10 @@ function intersect.aabb_frustum(aabb, frustum) -- We have 6 planes defining the frustum, 5 if infinite. local planes = { - frustum.top, - frustum.bottom, frustum.left, frustum.right, + frustum.bottom, + frustum.top, frustum.near, frustum.far or false } @@ -493,20 +527,19 @@ 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.bottom is a plane { a, b, c, d } +-- frustum.top 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, + local planes = { frustum.left, frustum.right, + frustum.bottom, + frustum.top, frustum.near } @@ -515,8 +548,8 @@ function intersect.sphere_frustum(sphere, frustum) end local dot - for p = 1, #planes do - dot = planes[p].a * x + planes[p].b * y + planes[p].c * z + planes[p].d + for i = 1, #planes do + dot = planes[i].a * x + planes[i].b * y + planes[i].c * z + planes[i].d if dot <= -sphere.radius then return false diff --git a/modules/mat4.lua b/modules/mat4.lua index 0cb75d1..d06b394 100644 --- a/modules/mat4.lua +++ b/modules/mat4.lua @@ -520,6 +520,7 @@ function mat4.to_vec4s(a) } end +-- http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/ function mat4.to_quat(a) identity(tmp):transpose(a) @@ -541,34 +542,6 @@ 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] @@ -596,6 +569,34 @@ function mat4.to_frustum(a, infinite) frustum.right.c = frustum.right.c / t frustum.right.d = frustum.right.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 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 NEAR plane frustum.near = {} frustum.near.a = a[4] + a[3] diff --git a/spec/mat4_spec.lua b/spec/mat4_spec.lua index 19dd073..88067dc 100644 --- a/spec/mat4_spec.lua +++ b/spec/mat4_spec.lua @@ -100,8 +100,18 @@ describe("mat4:", function() it("tests multiplication", function() do - local a = mat4 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 } - local b = mat4 { 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16 } + local a = mat4 { + 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12, + 13, 14, 15, 16 + } + local b = mat4 { + 1, 5, 9, 13, + 2, 6, 10, 14, + 3, 7, 11, 15, + 4, 8, 12, 16 + } local c = mat4():mul(a, b) assert.is.equal(c[1], 30) assert.is.equal(c[2], 70) @@ -125,13 +135,18 @@ describe("mat4:", function() end do - local a = mat4 { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 , 13, 14, 15, 16 } + local a = mat4 { + 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12, + 13, 14, 15, 16 + } local b = { 10, 20, 30, 40 } local c = mat4.mul_mat4x1({}, a, b) - assert.is.equal(c[1], 900) - assert.is.equal(c[2], 1000) - assert.is.equal(c[3], 1100) - assert.is.equal(c[4], 1200) + assert.is.equal(c[1], 900) + assert.is.equal(c[2], 1000) + assert.is.equal(c[3], 1100) + assert.is.equal(c[4], 1200) end end) @@ -172,7 +187,12 @@ describe("mat4:", function() end) it("tests transpose", function() - local a = mat4 { 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3 ,3 ,4, 4 ,4 ,4 } + local a = mat4 { + 1, 1, 1, 1, + 2, 2, 2, 2, + 3, 3, 3, 3, + 4, 4, 4, 4 + } local b = mat4():transpose(a) assert.is.equal(b[1], 1) assert.is.equal(b[2], 2) @@ -211,8 +231,6 @@ describe("mat4:", function() it("tests convertions", function() local a = mat4() - local b = mat4 { 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4 } - local v = a:to_vec4s() assert.is_true(type(v) == "table") assert.is_true(type(v[1]) == "table") @@ -236,11 +254,17 @@ describe("mat4:", function() assert.is.equal(v[4][3], 0) assert.is.equal(v[4][4], 1) + local b = mat4 { + 0, 0, 1, 0, + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 0, 0 + } local q = b:to_quat() - --assert.is.equal(q.x, 0) - --assert.is.equal(q.y, 0) - --assert.is.equal(q.z, 0) - --assert.is.equal(q.w, 0) + assert.is.equal(q.x, -0.5) + assert.is.equal(q.y, -0.5) + assert.is.equal(q.z, -0.5) + assert.is.equal(q.w, 0.5) end) end)