diff --git a/modules/mat4.lua b/modules/mat4.lua index 25b8a39..f80144a 100644 --- a/modules/mat4.lua +++ b/modules/mat4.lua @@ -160,23 +160,29 @@ end -- @tparam vec3 scale Scale vector -- @treturn mat4 out function mat4.from_transform(trans, rot, scale) - local angle, axis = rot:to_angle_axis() - local l = axis:len() + local rx, ry, rz, rw = rot.x, rot.y, rot.z, rot.w - if l == 0 then - return new() - end - - local x, y, z = axis.x / l, axis.y / l, axis.z / l - local c = cos(angle) - local s = sin(angle) - - return new { - x*x*(1-c)+c, y*x*(1-c)+z*s, x*z*(1-c)-y*s, 0, - x*y*(1-c)-z*s, y*y*(1-c)+c, y*z*(1-c)+x*s, 0, - x*z*(1-c)+y*s, y*z*(1-c)-x*s, z*z*(1-c)+c, 0, - trans.x, trans.y, trans.z, 1 + local sm = new { + scale.x, 0, 0, 0, + 0, scale.y, 0, 0, + 0, 0, scale.z, 0, + 0, 0, 0, 1, } + + local rm = new { + 1-2*(ry*ry+rz*rz), 2*(rx*ry-rz*rw), 2*(rx*rz+ry*rw), 0, + 2*(rx*ry+rz*rw), 1-2*(rx*rx+rz*rz), 2*(ry*rz-rx*rw), 0, + 2*(rx*rz-ry*rw), 2*(ry*rz+rx*rw), 1-2*(rx*rx+ry*ry), 0, + 0, 0, 0, 1 + } + + local rsm = rm * sm + + rsm[13] = trans.x + rsm[14] = trans.y + rsm[15] = trans.z + + return rsm end --- Create matrix from orthogonal. diff --git a/spec/mat4_spec.lua b/spec/mat4_spec.lua index 5473fcd..c1fa2dd 100644 --- a/spec/mat4_spec.lua +++ b/spec/mat4_spec.lua @@ -1,6 +1,8 @@ -local mat4 = require "modules.mat4" -local vec3 = require "modules.vec3" -local utils = require "modules.utils" +local mat4 = require "modules.mat4" +local vec3 = require "modules.vec3" +local quat = require "modules.quat" +local utils = require "modules.utils" +local FLT_EPSILON = require("modules.constants").FLT_EPSILON describe("mat4:", function() it("creates an identity matrix", function() @@ -484,6 +486,26 @@ describe("mat4:", function() ) assert.is.equal(s, a) end) + + it("creates a matrix out of transform values", function() + local scale = vec3(1, 2, 3) + local rot = quat.from_angle_axis(math.pi * 0.5, vec3(0, 1, 0)) + local trans = vec3(3, 4, 5) + local a = mat4.from_transform(trans, rot, scale) + + local v = vec3(-2, 3, 4) + -- scaled, rotated, then translated + -- v * mT * mR * mS + + local result = a * v + local expected = vec3(-9, 10, 3) + + -- float margin is considered + assert.is_true(math.abs(expected.x - result.x) < FLT_EPSILON) + assert.is_true(math.abs(expected.y - result.y) < FLT_EPSILON) + assert.is_true(math.abs(expected.z - result.z) < FLT_EPSILON) + end) + end) --[[