Created
February 2, 2019 09:56
-
-
Save spotco/a245903185623abac7ce105beb90c50c to your computer and use it in GitHub Desktop.
LCFrameOpt.ModuleScript.lua
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- dependancies | |
| local LVector3 = require(game.ReplicatedStorage.Shared.LVector3) | |
| -- CFrame class | |
| local TYPE_LCFRAME = "LCFrame" | |
| local LCFrame = { | |
| __type = TYPE_LCFRAME, | |
| TYPE_LCFRAME = TYPE_LCFRAME | |
| }; | |
| local mt = {__index = LCFrame}; | |
| local prettyPrint = true; -- mainly for debug (not a feature in real CFrames) | |
| local function update_lookvector(v) | |
| v.lookVector = LVector3.new(-v.m13, -v.m23, -v.m33); | |
| end | |
| -- built-in functions | |
| local pi = math.pi; | |
| local max = math.max; | |
| local cos = math.cos; | |
| local sin = math.sin; | |
| local acos = math.acos; | |
| local asin = math.asin; | |
| local sqrt = math.sqrt; | |
| local atan2 = math.atan2; | |
| local unpack = unpack; | |
| local concat = table.concat; | |
| -- some variables | |
| local IDENTITY_MATRIX = { | |
| m11 = 1, m12 = 0, m13 = 0, | |
| m21 = 0, m22 = 1, m23 = 0, | |
| m31 = 0, m32 = 0, m33 = 1 | |
| }; | |
| local M41, M42, M43, M44 = 0, 0, 0, 1; | |
| local IDENTITY_CFRAME = { | |
| 0, 0, 0, 1, | |
| 0, 0, 0, 1, | |
| 0, 0, 0, 1 | |
| }; | |
| local RIGHT_UNIT = LVector3.new(1, 0, 0); | |
| local TOP_UNIT = LVector3.new(0, 1, 0); | |
| local BACK_UNIT = LVector3.new(0, 0, 1); | |
| -- private functions | |
| local function fromAxisAngle(aaxis, vector, theta) | |
| -- http://wiki.roblox.com/index.php?title=User:EgoMoose/Articles/Quaternions_and_slerping#Rodriguez_Rotation_formula:_Axis-angle_rotations | |
| local laxis = aaxis:Unit(); | |
| return vector * cos(theta) + vector:Dot(laxis) * laxis * (1 - cos(theta)) + laxis:Cross(vector) * sin(theta); | |
| end; | |
| local function cfTimesv3(cf, v3) | |
| local _, _, _, m11, m12, m13, m21, m22, m23, m31, m32, m33 = cf:components(); | |
| local right = LVector3.new(m11, m21, m31); | |
| local top = LVector3.new(m12, m22, m32); | |
| local back = LVector3.new(m13, m23, m33); | |
| return cf.p + v3.X * right + v3.Y * top + v3.Z * back; | |
| end; | |
| local function fourByfour(a, b) | |
| local a11, a12, a13, a14, a21, a22, a23, a24, a31, a32, a33, a34, a41, a42, a43, a44 = unpack(a); | |
| local b11, b12, b13, b14, b21, b22, b23, b24, b31, b32, b33, b34, b41, b42, b43, b44 = unpack(b); | |
| -- 4x4 matrix multiplication | |
| local m11 = a11*b11 + a12*b21 + a13*b31 + a14*b41; | |
| local m12 = a11*b12 + a12*b22 + a13*b32 + a14*b42; | |
| local m13 = a11*b13 + a12*b23 + a13*b33 + a14*b43; | |
| local m14 = a11*b14 + a12*b24 + a13*b34 + a14*b44; | |
| local m21 = a21*b11 + a22*b21 + a23*b31 + a24*b41; | |
| local m22 = a21*b12 + a22*b22 + a23*b32 + a24*b42; | |
| local m23 = a21*b13 + a22*b23 + a23*b33 + a24*b43; | |
| local m24 = a21*b14 + a22*b24 + a23*b34 + a24*b44; | |
| local m31 = a31*b11 + a32*b21 + a33*b31 + a34*b41; | |
| local m32 = a31*b12 + a32*b22 + a33*b32 + a34*b42; | |
| local m33 = a31*b13 + a32*b23 + a33*b33 + a34*b43; | |
| local m34 = a31*b14 + a32*b24 + a33*b34 + a34*b44; | |
| local m41 = a41*b11 + a42*b21 + a43*b31 + a44*b41; | |
| local m42 = a41*b12 + a42*b22 + a43*b32 + a44*b42; | |
| local m43 = a41*b13 + a42*b23 + a43*b33 + a44*b43; | |
| local m44 = a41*b14 + a42*b24 + a43*b34 + a44*b44; | |
| -- return the components | |
| return m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44; | |
| end; | |
| local _cfTimescf_outcf_a = {} | |
| local _cfTimescf_outcf_b = {} | |
| local function cfTimescf_outcf(cf1, cf2, outcf) | |
| local a14, a24, a34, a11, a12, a13, a21, a22, a23, a31, a32, a33 = cf1:components(); | |
| local b14, b24, b34, b11, b12, b13, b21, b22, b23, b31, b32, b33 = cf2:components(); | |
| _cfTimescf_outcf_a[1] = a11 | |
| _cfTimescf_outcf_a[2] = a12 | |
| _cfTimescf_outcf_a[3] = a13 | |
| _cfTimescf_outcf_a[4] = a14 | |
| _cfTimescf_outcf_a[5] = a21 | |
| _cfTimescf_outcf_a[6] = a22 | |
| _cfTimescf_outcf_a[7] = a23 | |
| _cfTimescf_outcf_a[8] = a24 | |
| _cfTimescf_outcf_a[9] = a31 | |
| _cfTimescf_outcf_a[10] = a32 | |
| _cfTimescf_outcf_a[11] = a33 | |
| _cfTimescf_outcf_a[12] = a34 | |
| _cfTimescf_outcf_a[13] = M41 | |
| _cfTimescf_outcf_a[14] = M42 | |
| _cfTimescf_outcf_a[15] = M43 | |
| _cfTimescf_outcf_a[16] = M44 | |
| _cfTimescf_outcf_b[1] = b11 | |
| _cfTimescf_outcf_b[2] = b12 | |
| _cfTimescf_outcf_b[3] = b13 | |
| _cfTimescf_outcf_b[4] = b14 | |
| _cfTimescf_outcf_b[5] = b21 | |
| _cfTimescf_outcf_b[6] = b22 | |
| _cfTimescf_outcf_b[7] = b23 | |
| _cfTimescf_outcf_b[8] = b24 | |
| _cfTimescf_outcf_b[9] = b31 | |
| _cfTimescf_outcf_b[10] = b32 | |
| _cfTimescf_outcf_b[11] = b33 | |
| _cfTimescf_outcf_b[12] = b34 | |
| _cfTimescf_outcf_b[13] = M41 | |
| _cfTimescf_outcf_b[14] = M42 | |
| _cfTimescf_outcf_b[15] = M43 | |
| _cfTimescf_outcf_b[16] = M44 | |
| local m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44 = fourByfour( | |
| _cfTimescf_outcf_a, | |
| _cfTimescf_outcf_b | |
| ); | |
| return outcf:set_components(m14, m24, m34, m11, m12, m13, m21, m22, m23, m31, m32, m33); | |
| end | |
| local function cfTimescf(cf1, cf2) | |
| local rtv = LCFrame.new() | |
| return cfTimescf_outcf(cf1, cf2, rtv) | |
| end; | |
| local function getDeterminant(cf) | |
| local a14, a24, a34, a11, a12, a13, a21, a22, a23, a31, a32, a33 = cf:components(); | |
| local m41, m42, m43, m44 = 0, 0, 0, 1; | |
| local det = a11*a22*a33*m44 + a11*a23*a34*m42 + a11*a24*a32*m43 | |
| + a12*a21*a34*m43 + a12*a23*a31*m44 + a12*a24*a33*m41 | |
| + a13*a21*a32*m44 + a13*a22*a34*m41 + a13*a24*a31*m42 | |
| + a14*a21*a33*m42 + a14*a22*a31*m43 + a14*a23*a32*m41 | |
| - a11*a22*a34*m43 - a11*a23*a32*m44 - a11*a24*a33*m42 | |
| - a12*a21*a33*m44 - a12*a23*a34*m41 - a12*a24*a31*m43 | |
| - a13*a21*a34*m42 - a13*a22*a31*m44 - a13*a24*a32*m41 | |
| - a14*a21*a32*m43 - a14*a22*a33*m41 - a14*a23*a31*m42; | |
| return det; | |
| end; | |
| local function invert4x4(cf) | |
| -- this is linear algebra. We're inverting a 4x4 matrix | |
| -- see: http://www.cg.info.hiroshima-cu.ac.jp/~miyazaki/knowledge/teche23.html | |
| -- it is very possible that the built-in CFrame class does not use this method as computers tend to use elimination methods | |
| -- regardless, both functions should return the same answer | |
| local a14, a24, a34, a11, a12, a13, a21, a22, a23, a31, a32, a33 = cf:components(); | |
| local det = getDeterminant(cf); | |
| if (det == 0) then return cf; end; | |
| local b11 = (a22*a33*M44 + a23*a34*M42 + a24*a32*M43 - a22*a34*M43 - a23*a32*M44 - a24*a33*M42) / det; | |
| local b12 = (a12*a34*M43 + a13*a32*M44 + a14*a33*M42 - a12*a33*M44 - a13*a34*M42 - a14*a32*M43) / det; | |
| local b13 = (a12*a23*M44 + a13*a24*M42 + a14*a22*M43 - a12*a24*M43 - a13*a22*M44 - a14*a23*M42) / det; | |
| local b14 = (a12*a24*a33 + a13*a22*a34 + a14*a23*a32 - a12*a23*a34 - a13*a24*a32 - a14*a22*a33) / det; | |
| local b21 = (a21*a34*M43 + a23*a31*M44 + a24*a33*M41 - a21*a33*M44 - a23*a34*M41 - a24*a31*M43) / det; | |
| local b22 = (a11*a33*M44 + a13*a34*M41 + a14*a31*M43 - a11*a34*M43 - a13*a31*M44 - a14*a33*M41) / det; | |
| local b23 = (a11*a24*M43 + a13*a21*M44 + a14*a23*M41 - a11*a23*M44 - a13*a24*M41 - a14*a21*M43) / det; | |
| local b24 = (a11*a23*a34 + a13*a24*a31 + a14*a21*a33 - a11*a24*a33 - a13*a21*a34 - a14*a23*a31) / det; | |
| local b31 = (a21*a32*M44 + a22*a34*M41 + a24*a31*M42 - a21*a34*M42 - a22*a31*M44 - a24*a32*M41) / det; | |
| local b32 = (a11*a34*M42 + a12*a31*M44 + a14*a32*M41 - a11*a32*M44 - a12*a34*M41 - a14*a31*M42) / det; | |
| local b33 = (a11*a22*M44 + a12*a24*M41 + a14*a21*M42 - a11*a24*M42 - a12*a21*M44 - a14*a22*M41) / det; | |
| local b34 = (a11*a24*a32 + a12*a21*a34 + a14*a22*a31 - a11*a22*a34 - a12*a24*a31 - a14*a21*a32) / det; | |
| local b41 = (a21*a33*M42 + a22*a31*M43 + a23*a32*M41 - a21*a32*M43 - a22*a33*M41 - a23*a31*M42) / det; | |
| local b42 = (a11*a32*M43 + a12*a33*M41 + a13*a31*M42 - a11*a33*M42 - a12*a31*M43 - a13*a32*M41) / det; | |
| local b43 = (a11*a23*M42 + a12*a21*M43 + a13*a22*M41 - a11*a22*M43 - a12*a23*M41 - a13*a21*M42) / det; | |
| local b44 = (a11*a22*a33 + a12*a23*a31 + a13*a21*a32 - a11*a23*a32 - a12*a21*a33 - a13*a22*a31) / det; | |
| return LCFrame.new(b14, b24, b34, b11, b12, b13, b21, b22, b23, b31, b32, b33); | |
| end; | |
| local function quaternionToMatrix(i, j, k, w) | |
| local m11 = 1 - 2*j^2 - 2*k^2; | |
| local m12 = 2*(i*j - k*w); | |
| local m13 = 2*(i*k + j*w); | |
| local m21 = 2*(i*j + k*w); | |
| local m22 = 1 - 2*i^2 - 2*k^2; | |
| local m23 = 2*(j*k - i*w); | |
| local m31 = 2*(i*k - j*w); | |
| local m32 = 2*(j*k + i*w); | |
| local m33 = 1 - 2*i^2 - 2*j^2; | |
| return {0, 0, 0, m11, m12, m13, m21, m22, m23, m31, m32, m33}; | |
| end; | |
| local function quaternionFromCFrame(cf) | |
| -- taken from: http://wiki.roblox.com/index.php?title=Quaternions_for_rotation#Quaternion_from_a_Rotation_Matrix | |
| local mx, my, mz, m11, m12, m13, m21, m22, m23, m31, m32, m33 = cf:components(); | |
| local trace = m11 + m22 + m33; | |
| if (trace > 0) then | |
| local s = sqrt(1 + trace); | |
| local r = 0.5 / s; | |
| return s * 0.5, LVector3.new((m32 - m23) * r, (m13 - m31) * r, (m21 - m12) * r); | |
| else -- find the largest diagonal element | |
| local big = max(m11, m22, m33); | |
| if big == m11 then | |
| local s = sqrt(1 + m11 - m22 - m33); | |
| local r = 0.5 / s; | |
| return (m32 - m23) * r, LVector3.new(0.5 * s, (m21 + m12) * r, (m13 + m31) * r); | |
| elseif big == m22 then | |
| local s = sqrt(1 - m11 + m22 - m33); | |
| local r = 0.5 / s; | |
| return (m13 - m31) * r, LVector3.new((m21 + m12) * r, 0.5 * s, (m32 + m23) * r); | |
| elseif big == m33 then | |
| local s = sqrt(1 - m11 - m22 + m33); | |
| local r = 0.5 / s; | |
| return (m21 - m12) * r, LVector3.new((m13 + m31) * r, (m32 + m23) * r, 0.5 * s); | |
| end; | |
| end; | |
| end; | |
| local function lerp(a, b, t) | |
| -- I have no idea what the internal implemenation is | |
| -- get the difference in CFrames, convert to quaternion, convert to axis angle, slerp | |
| local cf = a:inverse() * b; | |
| local w, v = quaternionFromCFrame(cf); | |
| local theta = acos(w) * 2; | |
| local p = a.p:Lerp(b.p, t); | |
| if theta ~= 0 then | |
| local rot = a * LCFrame.fromAxisAngle(v, theta * t); | |
| local _, _, _, m11, m12, m13, m21, m22, m23, m31, m32, m33 = rot:components(); | |
| return LCFrame.new(p.X, p.Y, p.Z, m11, m12, m13, m21, m22, m23, m31, m32, m33); | |
| else | |
| local _, _, _, m11, m12, m13, m21, m22, m23, m31, m32, m33 = a:components(); | |
| return LCFrame.new(p.X, p.Y, p.Z, m11, m12, m13, m21, m22, m23, m31, m32, m33); | |
| end; | |
| end; | |
| -- meta-methods | |
| function mt.__add(a, b) | |
| local x, y, z, m11, m12, m13, m21, m22, m23, m31, m32, m33 = a:components(); | |
| return LCFrame.new(x + b.X, y + b.Y, z + b.Z, m11, m12, m13, m21, m22, m23, m31, m32, m33); | |
| end; | |
| function mt.__sub(a, b) | |
| local x, y, z, m11, m12, m13, m21, m22, m23, m31, m32, m33 = a:components(); | |
| return LCFrame.new(x - b.X, y - b.Y, z - b.Z, m11, m12, m13, m21, m22, m23, m31, m32, m33); | |
| end; | |
| function mt.__mul(a, b) | |
| local aIsCFrame = type(a) == "table" and a.__type and a.__type == TYPE_LCFRAME; | |
| local bIsCFrame = type(b) == "table" and b.__type and b.__type == TYPE_LCFRAME; | |
| local aIsVector = type(a) == "table" and a.__type and a.__type == LVector3.TYPE_LVECTOR3; | |
| local bIsVector = type(b) == "table" and b.__type and b.__type == LVector3.TYPE_LVECTOR3; | |
| if (aIsCFrame and bIsVector) then | |
| return cfTimesv3(a, b); | |
| elseif (aIsCFrame and bIsCFrame) then | |
| return cfTimescf(a, b); | |
| elseif (aIsCFrame) then | |
| local t = type(a); | |
| local cust = t == "table" and a.__type or t; | |
| error("bad argument #2 to '?' (LVector expected, got " .. cust .. " )"); | |
| elseif (bIsCFrame) then | |
| local t = type(a); | |
| local cust = t == "table" and a.__type or t; | |
| error("bad argument #1 to '?' (CFrame expected, got " .. cust .. " )"); | |
| end; | |
| end; | |
| function mt.__tostring(t) | |
| local components = {t:components()}; | |
| if prettyPrint then | |
| local s = ""; | |
| for i = 1, 12 do | |
| s = s .. ((i > 1 and i % 3 == 1 and "\n") or "") .. components[i] .. (i < 12 and ", " or ""); | |
| end; | |
| return s; | |
| else | |
| return concat(components, ", "); | |
| end; | |
| end; | |
| mt.__metatable = false; | |
| -- public class | |
| function LCFrame.new(...) | |
| local self = {}; | |
| self.p = LVector3.new(0, 0, 0); | |
| for k, v in next, IDENTITY_MATRIX do | |
| self[k] = v; | |
| end; | |
| -- most of this function is error handling from bad userinput | |
| local t = {...}; | |
| local length = #t; | |
| if length > 12 then | |
| error("Invalid number of arguments: " .. length); | |
| elseif (length == 1) then -- single LVector case | |
| local v = t[1]; | |
| local isVector = type(v) == "table" and v.__type and v.__type == LVector3.TYPE_LVECTOR3; | |
| if (not isVector) then | |
| local pt = type(v); | |
| local cust = pt == "table" and v.__type or pt; | |
| error("bad argument #1 to 'new' (LVector3 expected, got" .. cust .. ")"); | |
| end; | |
| -- make a copy to avoid user changing the original vector | |
| self.p = LVector3.new(v.X, v.Y, v.Z); | |
| elseif (length == 2) then -- two LVector3 case, we much build a lookAt matrix | |
| local eye, look = t[1], t[2]; | |
| local eyeIsVector = type(eye) == "table" and eye.__type and eye.__type == LVector3.TYPE_LVECTOR3; | |
| local lookIsVector = type(look) == "table" and look.__type and look.__type == LVector3.TYPE_LVECTOR3; | |
| if (not eyeIsVector and not lookIsVector) then | |
| local pt = type(eye); | |
| local cust = pt == "table" and eye.__type or pt; | |
| error("bad argument #1 to 'new' (LVector3 expected, got" .. cust .. ")"); | |
| end; | |
| local zaxis = (eye - look):Unit(); | |
| local xaxis = TOP_UNIT:Cross(zaxis):Unit(); | |
| local yaxis = zaxis:Cross(xaxis):Unit(); | |
| if (xaxis:Magnitude() == 0) then -- edge cases | |
| if zaxis.Y < 0 then | |
| xaxis = LVector3.new(0, 0, -1); | |
| yaxis = LVector3.new(1, 0, 0); | |
| zaxis = LVector3.new(0, -1, 0); | |
| else | |
| xaxis = LVector3.new(0, 0, 1); | |
| yaxis = LVector3.new(1, 0, 0); | |
| zaxis = LVector3.new(0, 1, 0); | |
| end; | |
| end; | |
| self.p = LVector3.new(eye.X, eye.Y, eye.Z); | |
| self.m11, self.m12, self.m13 = xaxis.X, yaxis.X, zaxis.X; | |
| self.m21, self.m22, self.m23 = xaxis.Y, yaxis.Y, zaxis.Y; | |
| self.m31, self.m32, self.m33 = xaxis.Z, yaxis.Z, zaxis.Z; | |
| elseif (length == 3) then -- x, y, z | |
| for i = 1, length do | |
| local pt = type(t[i]); | |
| local cust = pt; | |
| if cust ~= "number" then error("bad argument #" .. i .. " to 'new' (Number expected, got " .. cust .. ")"); end; | |
| end; | |
| self.p = LVector3.new(t[1], t[2], t[3]); | |
| elseif (length == 7) then -- x, y, z, quaternion | |
| for i = 1, length do | |
| local pt = type(t[i]); | |
| local cust = pt; | |
| if cust ~= "number" then error("bad argument #" .. i .. " to 'new' (Number expected, got " .. cust .. ")"); end; | |
| end; | |
| local m = quaternionToMatrix(t[4], t[5], t[6], t[7]); | |
| self.p = LVector3.new(t[1], t[2], t[3]); | |
| self.m11, self.m12, self.m13 = m[4], m[5], m[6]; | |
| self.m21, self.m22, self.m23 = m[7], m[8], m[9]; | |
| self.m31, self.m32, self.m33 = m[10], m[11], m[12]; | |
| elseif (length == 12) then -- all components provided | |
| for i = 1, length do | |
| local pt = type(t[i]); | |
| local cust = pt; | |
| if cust ~= "number" then error("bad argument #" .. i .. " to 'new' (Number expected, got " .. cust .. ")"); end; | |
| end; | |
| self.p = LVector3.new(t[1], t[2], t[3]); | |
| self.m11, self.m12, self.m13 = t[4], t[5], t[6]; | |
| self.m21, self.m22, self.m23 = t[7], t[8], t[9]; | |
| self.m31, self.m32, self.m33 = t[10], t[11], t[12]; | |
| elseif length > 0 then -- more than zero components | |
| for i = 1, length do | |
| local pt = type(t[i]); | |
| local cust = pt; | |
| if cust ~= "number" then error("bad argument #" .. i .. " to 'new' (Number expected, got " .. cust .. ")"); end; | |
| end; | |
| error("bad argument #" .. (length + 1) .. " to 'new' (Number expected, got nil)"); | |
| end; | |
| update_lookvector(self) | |
| return setmetatable(self, mt); | |
| end; | |
| --SPCHANGE (new methods) | |
| function LCFrame:set_identity() | |
| self.p:set(0,0,0) | |
| for key, value in next, IDENTITY_MATRIX do | |
| self[key] = value; | |
| end; | |
| update_lookvector(self); | |
| return self; | |
| end | |
| function LCFrame:set_components(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) | |
| self.p:set(a1, a2, a3); | |
| self.m11, self.m12, self.m13 = a4, a5, a6; | |
| self.m21, self.m22, self.m23 = a7, a8, a9; | |
| self.m31, self.m32, self.m33 = a10, a11, a12; | |
| update_lookvector(self); | |
| return self; | |
| end | |
| function LCFrame:from_cframe(rcf) | |
| local a_x, a_y, a_z, a_r00, a_r01, a_r02, a_r10, a_r11, a_r12, a_r20, a_r21, a_r22 = rcf:components(); | |
| self:set_components(a_x, a_y, a_z, a_r00, a_r01, a_r02, a_r10, a_r11, a_r12, a_r20, a_r21, a_r22); | |
| return self | |
| end | |
| function LCFrame:to_cframe() | |
| return CFrame.new( | |
| self.p.X, self.p.Y, self.p.Z, | |
| self.m11, self.m12, self.m13, | |
| self.m21, self.m22, self.m23, | |
| self.m31, self.m32, self.m33 | |
| ) | |
| end | |
| function LCFrame:store_mul_result(a,b) | |
| cfTimescf_outcf(a, b, self); | |
| update_lookvector(self); | |
| return self; | |
| end | |
| function LCFrame:set_angles(x,y,z) | |
| local m11 = cos(y) * cos(z); | |
| local m12 = -cos(y) * sin(z); | |
| local m13 = sin(y); | |
| local m21 = cos(z) * sin(x) * sin(y) + cos(x) * sin(z); | |
| local m22 = cos(x) * cos(z) - sin(x) * sin(y) * sin(z); | |
| local m23 = -cos(y) * sin(x); | |
| local m31 = sin(x) * sin(z) - cos(x) * cos(z) * sin(y); | |
| local m32 = cos(z) * sin(x) + cos(x) * sin(y) * sin(z); | |
| local m33 = cos(x) * cos(y); | |
| self:set_components(0, 0, 0, m11, m12, m13, m21, m22, m23, m31, m32, m33); | |
| update_lookvector(self); | |
| return self; | |
| end | |
| local _cached_set_eye_look_zaxis = LVector3.new() | |
| local _cached_set_eye_look_xaxis = LVector3.new() | |
| local _cached_set_eye_look_yaxis = LVector3.new() | |
| function LCFrame:set_eye_look(eye, look) | |
| local eyeIsVector = type(eye) == "table" and eye.__type and eye.__type == LVector3.TYPE_LVECTOR3; | |
| local lookIsVector = type(look) == "table" and look.__type and look.__type == LVector3.TYPE_LVECTOR3; | |
| if (not eyeIsVector and not lookIsVector) then | |
| local t = type(eye); | |
| local cust = t == "table" and eye.__type or t; | |
| error("bad argument #1 to 'new' (LVector3 expected, got" .. cust .. ")"); | |
| end; | |
| _cached_set_eye_look_zaxis:store_sub_result(eye, look); | |
| _cached_set_eye_look_zaxis:store_normalized(_cached_set_eye_look_zaxis); | |
| _cached_set_eye_look_xaxis:store_cross_result(TOP_UNIT, _cached_set_eye_look_zaxis); | |
| _cached_set_eye_look_xaxis:store_normalized(_cached_set_eye_look_xaxis); | |
| _cached_set_eye_look_yaxis:store_cross_result(_cached_set_eye_look_zaxis, _cached_set_eye_look_xaxis); | |
| _cached_set_eye_look_yaxis:store_normalized(_cached_set_eye_look_yaxis); | |
| if _cached_set_eye_look_xaxis:Magnitude() == 0 then | |
| if _cached_set_eye_look_zaxis.Y < 0 then | |
| _cached_set_eye_look_xaxis:set(0, 0, -1); | |
| _cached_set_eye_look_yaxis:set(1, 0, 0); | |
| _cached_set_eye_look_zaxis:set(0, -1, 0); | |
| else | |
| _cached_set_eye_look_xaxis:set(0, 0, 1); | |
| _cached_set_eye_look_yaxis:set(1, 0, 0); | |
| _cached_set_eye_look_zaxis:set(0, 1, 0); | |
| end; | |
| end | |
| self.p:set(eye.X, eye.Y, eye.Z); | |
| self.m11, self.m12, self.m13 = _cached_set_eye_look_xaxis.X, _cached_set_eye_look_yaxis.X, _cached_set_eye_look_zaxis.X; | |
| self.m21, self.m22, self.m23 = _cached_set_eye_look_xaxis.Y, _cached_set_eye_look_yaxis.Y, _cached_set_eye_look_zaxis.Y; | |
| self.m31, self.m32, self.m33 = _cached_set_eye_look_xaxis.Z, _cached_set_eye_look_yaxis.Z, _cached_set_eye_look_zaxis.Z; | |
| update_lookvector(self); | |
| return self | |
| end | |
| --END SPCHANGE | |
| function LCFrame.fromAxisAngle(aaxis, theta) | |
| local axis = aaxis:Unit(); | |
| local r = fromAxisAngle(axis, RIGHT_UNIT, theta); | |
| local t = fromAxisAngle(axis, TOP_UNIT, theta); | |
| local b = fromAxisAngle(axis, BACK_UNIT, theta); | |
| return LCFrame.new( | |
| 0, 0, 0, | |
| r.X, t.X, b.X, | |
| r.Y, t.Y, b.Y, | |
| r.Z, t.Z, b.Z | |
| ); | |
| end; | |
| function LCFrame.Angles(x, y, z) | |
| -- two implemenations possible. The commented one is what is what is used in the real CFrame constructor (to my knowledge) | |
| -- the uncommented implemenation is easier for me to keep track of and I think makes more sense, but you can use either | |
| -- the method (presumably) used in the real constructor | |
| -- How to find this matrix: http://i.imgur.com/IWDMw0m.png | |
| -- https://en.wikipedia.org/wiki/Rotation_matrix#In_three_dimensions | |
| --[[ | |
| local m11 = cos(y) * cos(z); | |
| local m12 = -cos(y) * sin(z); | |
| local m13 = sin(y); | |
| local m21 = cos(z) * sin(x) * sin(y) + cos(x) * sin(z); | |
| local m22 = cos(x) * cos(z) - sin(x) * sin(y) * sin(z); | |
| local m23 = -cos(y) * sin(x); | |
| local m31 = sin(x) * sin(z) - cos(x) * cos(z) * sin(y); | |
| local m32 = cos(z) * sin(x) + cos(x) * sin(y) * sin(z); | |
| local m33 = cos(x) * cos(y); | |
| return cframe.new(0, 0, 0, m11, m12, m13, m21, m22, m23, m31, m32, m33); | |
| --]] | |
| -- the method I prefer | |
| local cfx = LCFrame.fromAxisAngle(RIGHT_UNIT, x); | |
| local cfy = LCFrame.fromAxisAngle(TOP_UNIT, y); | |
| local cfz = LCFrame.fromAxisAngle(BACK_UNIT, z); | |
| return cfx * cfy * cfz; | |
| end; | |
| function LCFrame.fromEulerAnglesXYZ(x, y, z) | |
| return LCFrame.Angles(x, y, z); | |
| end; | |
| function LCFrame:inverse() | |
| return invert4x4(self); | |
| end; | |
| function LCFrame:lerp(self2, t) | |
| return lerp(self, self2, t); | |
| end; | |
| function LCFrame:toWorldSpace(self2) | |
| return self * self2; | |
| end; | |
| function LCFrame:toWorldSpace(self2) | |
| return self * self2; | |
| end; | |
| function LCFrame:toObjectSpace(self2) | |
| return self:inverse() * self2; | |
| end; | |
| function LCFrame:pointToWorldSpace(v3) | |
| return self * v3; | |
| end; | |
| function LCFrame:pointToObjectSpace(v3) | |
| return self:inverse() * v3; | |
| end; | |
| function LCFrame:vectorToWorldSpace(v3) | |
| return (self - self.p) * v3; | |
| end; | |
| function LCFrame:vectorToObjectSpace(v3) | |
| return (self - self.p):inverse() * v3; | |
| end; | |
| function LCFrame:components() | |
| return self.p.X, self.p.Y, self.p.Z, self.m11, self.m12, self.m13, self.m21, self.m22, self.m23, self.m31, self.m32, self.m33; | |
| end; | |
| function LCFrame:toEulerAnglesXYZ() | |
| -- based off the method (presumably) used in the real constructor for cframe.Angles | |
| local _, _, _, m11, m12, m13, m21, m22, m23, m31, m32, m33 = self:components(); | |
| local x = atan2(-m23, m33); | |
| local y = asin(m13); | |
| local z = atan2(-m12, m11); | |
| return x, y, z; | |
| end; | |
| return LCFrame; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment