From 7d22d13bcaeecff0832ca6e2a918573d725b048a Mon Sep 17 00:00:00 2001 From: Colby Klein Date: Sat, 30 Apr 2022 14:10:51 -0700 Subject: [PATCH] (breaking) simplify mat4.project and unproject the separate view and projection just weren't really useful, might as well pass in your own full transform instead. this also fixes the z range, which should not have been manipulated. this simplifies usage to check something as on screen to just 1 > z > 0 might break the test, but tested working locally --- modules/mat4.lua | 57 ++++++++++++++++------------------------------ spec/mat4_spec.lua | 26 ++++++++++----------- 2 files changed, 32 insertions(+), 51 deletions(-) diff --git a/modules/mat4.lua b/modules/mat4.lua index 8899170..4865cb6 100644 --- a/modules/mat4.lua +++ b/modules/mat4.lua @@ -652,54 +652,37 @@ function mat4.transpose(out, a) return out end --- https://github.com/g-truc/glm/blob/master/glm/gtc/matrix_transform.inl#L518 ---- Project a matrix from world space to screen space. +--- Project a point into screen space -- @tparam vec3 obj Object position in world space --- @tparam mat4 view View matrix --- @tparam mat4 projection Projection matrix +-- @tparam mat4 mvp Projection matrix -- @tparam table viewport XYWH of viewport -- @treturn vec3 win -function mat4.project(obj, view, projection, viewport) - local position = { obj.x, obj.y, obj.z, 1 } - - mat4.mul_vec4(position, view, position) - mat4.mul_vec4(position, projection, position) - - position[1] = position[1] / position[4] * 0.5 + 0.5 - position[2] = position[2] / position[4] * 0.5 + 0.5 - position[3] = position[3] / position[4] * 0.5 + 0.5 - - position[1] = position[1] * viewport[3] + viewport[1] - position[2] = position[2] * viewport[4] + viewport[2] - - return vec3(position[1], position[2], position[3]) +function mat4.project(obj, mvp, viewport) + local point = mat4.mul_vec3_perspective(vec3(), mvp, obj) + point.x = point.x * 0.5 + 0.5 + point.y = point.y * 0.5 + 0.5 + point.x = point.x * viewport[3] + viewport[1] + point.y = point.y * viewport[4] + viewport[2] + return point end --- https://github.com/g-truc/glm/blob/master/glm/gtc/matrix_transform.inl#L544 ---- Unproject a matrix from screen space to world space. +--- Unproject a point from screen space to world space. -- @tparam vec3 win Object position in screen space --- @tparam mat4 view View matrix --- @tparam mat4 projection Projection matrix +-- @tparam mat4 mvp Projection matrix -- @tparam table viewport XYWH of viewport -- @treturn vec3 obj -function mat4.unproject(win, view, projection, viewport) - local position = { win.x, win.y, win.z, 1 } +function mat4.unproject(win, mvp, viewport) + local point = vec3.clone(win) - position[1] = (position[1] - viewport[1]) / viewport[3] - position[2] = (position[2] - viewport[2]) / viewport[4] + -- 0..n -> 0..1 + point.x = (point.x - viewport[1]) / viewport[3] + point.y = (point.y - viewport[2]) / viewport[4] - position[1] = position[1] * 2 - 1 - position[2] = position[2] * 2 - 1 - position[3] = position[3] * 2 - 1 + -- 0..1 -> -1..1 + point.x = point.x * 2 - 1 + point.y = point.y * 2 - 1 - tmp:mul(projection, view):invert(tmp) - mat4.mul_vec4(position, tmp, position) - - position[1] = position[1] / position[4] - position[2] = position[2] / position[4] - position[3] = position[3] / position[4] - - return vec3(position[1], position[2], position[3]) + return mat4.mul_vec3_perspective(point, tmp:invert(mvp), point) end --- Return a boolean showing if a table is or is not a mat4. diff --git a/spec/mat4_spec.lua b/spec/mat4_spec.lua index 5cbd17e..e4174df 100644 --- a/spec/mat4_spec.lua +++ b/spec/mat4_spec.lua @@ -301,27 +301,25 @@ describe("mat4:", function() assert.is.equal(p.z, 5) end) - it("projects a matrix into screen space", function() - local v = vec3(0, 0, 10) - local a = mat4() - local b = mat4.from_perspective(45, 1, 0.1, 1000) + it("projects a point into screen space", function() + local p = vec3(0, 0, 10) + local proj = mat4.from_perspective(45, 1, 0.1, 1000) local vp = { 0, 0, 400, 400 } - local c = mat4.project(v, a, b, vp) + local c = mat4.project(p, proj, vp) assert.is.equal(200, c.x) assert.is.equal(200, c.y) assert.is_true(utils.tolerance(1.0101-c.z, 0.001)) end) - it("unprojects a matrix into world space", function() - local v = vec3(0, 0, 10) - local a = mat4() - local b = mat4.from_perspective(45, 1, 0.1, 1000) + it("unprojects a point into world space", function() + local p = vec3(0, 0, 10) + local proj = mat4.from_perspective(45, 1, 0.1, 1000) local vp = { 0, 0, 400, 400 } - local c = mat4.project(v, a, b, vp) - local d = mat4.unproject(c, a, b, vp) - assert.is_true(utils.tolerance(v.x-d.x, 0.001)) - assert.is_true(utils.tolerance(v.y-d.y, 0.001)) - assert.is_true(utils.tolerance(v.z-d.z, 0.001)) + local c = mat4.project(p, proj, vp) + local d = mat4.unproject(c, proj, vp) + assert.is_true(utils.tolerance(p.x-d.x, 0.001)) + assert.is_true(utils.tolerance(p.y-d.y, 0.001)) + assert.is_true(utils.tolerance(p.z-d.z, 0.001)) end) it("transforms a matrix to look at a point", function()