Vec3 = { x = 0.0, y = 0.0, z = 0.0 } Vec3.__index = Vec3 Vec3.__name = "Vec3" --- Constructs a new vector ---@param x number ---@param y number ---@param z number ---@return Vec3 function Vec3:new(x, y, z) local v = {} setmetatable(v, Vec3) v.x = x v.y = y v.z = z return v end function Vec3:copy() return Vec3:new(self.x, self.y, self.z) end --- Constructs a vector with all elements as parameter `x`. ---@param x number ---@return Vec3 function Vec3:all(x) return Vec3:new(x, x, x) end --- A unit-length vector pointing alongside the positive X axis. Vec3.X = Vec3:new(1, 0, 0) --- A unit-length vector pointing alongside the positive Y axis. Vec3.Y = Vec3:new(0, 1, 0) --- A unit-length vector pointing alongside the positive Z axis. Vec3.Z = Vec3:new(0, 0, 1) --- A unit-length vector pointing alongside the negative X axis. Vec3.NEG_X = Vec3:new(-1, 0, 0) --- A unit-length vector pointing alongside the negative Y axis. Vec3.NEG_Y = Vec3:new(0, -1, 0) --- A unit-length vector pointing alongside the negative Z axis. Vec3.NEG_Z = Vec3:new(0, 0, -1) --- A vector of all zeros Vec3.ZERO = Vec3:new(0, 0, 0) --- A vector of all ones Vec3.ONE = Vec3:new(1, 1, 1) --- Computes the absolute value of `self`. ---@return Vec3 function Vec3:abs() return Vec3:new(math.abs(self.x), math.abs(self.y), math.abs(self.z)) end --- Computes the length of `self`. ---@return number function Vec3:length() return math.sqrt(self:dot(self)) end --- Computes the dot product of `self` and `rhs`. ---@param rhs Vec3 ---@return number function Vec3:dot(rhs) assert(rhs.__name == "Vec3") return (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z) end --- Returns a vector that has the minimum value of each element of `self` and `rhs` ---@param rhs Vec3 ---@return Vec3 function Vec3:min(rhs) local x = math.min(self.x, rhs.x) local y = math.min(self.y, rhs.y) local z = math.min(self.z, rhs.z) return Vec3:new(x, y, z) end --- Returns `self` normalized to a length 1. ---@return unknown function Vec3:normalize() local len_recip = 1.0 / self:length() return self * len_recip end --- Calculates the linear iterpolation between `self` and `rhs` based on the `alpha`. --- When `alpha` is `0`, the result will be equal to `self`. When `s` is `1`, the result --- will be equal to `rhs` --- @param rhs Vec3 --- @param alpha number --- @return Vec3 function Vec3:lerp(rhs, alpha) -- ensure alpha is [0, 1] local alpha = math.max(0, math.min(1, alpha)) local res = self:copy() res = res + ((rhs - res) * alpha) return res end function Vec3:__add(rhs) return Vec3:new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z) end function Vec3:__sub(rhs) return Vec3:new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z) end function Vec3:__mul(rhs) if type(rhs) == "number" then return Vec3:new(self.x * rhs, self.y * rhs, self.z * rhs) else return Vec3:new(self.x * rhs.x, self.y * rhs.y, self.z * rhs.z) end end function Vec3:__div(rhs) if type(rhs) == "number" then return Vec3:new(self.x / rhs, self.y / rhs, self.z / rhs) else return Vec3:new(self.x / rhs.x, self.y / rhs.y, self.z / rhs.z) end end function Vec3:__idiv(rhs) if type(rhs) == "number" then return Vec3:new(self.x // rhs, self.y // rhs, self.z // rhs) else return Vec3:new(self.x // rhs.x, self.y // rhs.y, self.z // rhs.z) end end function Vec3:__unm() return Vec3:new(-self.x, -self.y, -self.z) end function Vec3:__pow(rhs) if type(rhs) == "number" then return Vec3:new(self.x ^ rhs, self.y ^ rhs, self.z ^ rhs) end end function Vec3:__eq(rhs) return self.x == rhs.x and self.y == rhs.y and self.z == rhs.z end function Vec3:__lt(rhs) return self.x < rhs.x and self.y < rhs.y and self.z < rhs.z end function Vec3:__le(rhs) return self.x <= rhs.x and self.y <= rhs.y and self.z <= rhs.z end function Vec3:__tostring() return "Vec3(" .. self.x .. ", " .. self.y .. ", " .. self.z .. ")" end