diff --git a/light.lua b/light.lua index 2dce32a647d040c7cba52f079953062ccc8a3c98..a5308182d61ab06e7cab8a6ffb7e1ac10b76466a 100644 --- a/light.lua +++ b/light.lua @@ -11,7 +11,7 @@ light.__index = light -- Creates a new light with transform t and RGB value diff and spec function light.new(t, diff, spec) - local l = {transform = t, diffuse = diff or {255, 255, 255}, specular = spec or {255, 255, 255}} + local l = {transform = t, diffuse = diff or vector.new(3, {255, 255, 255}), specular = spec or vector.new(3, {255, 255, 255})} setmetatable(l, light) return l end diff --git a/shape.lua b/shape.lua index c6f09c0cc0550964b875b3e1b145583a81f7ed8e..7ac113806206722b5c88b3b3aa37d91f25cd3554 100644 --- a/shape.lua +++ b/shape.lua @@ -2,7 +2,7 @@ require("kara3d.vector") require("kara3d.matrix") require("kara3d.quaternion") require("kara3d.transform") -require("kara3d.lights") +require("kara3d.light") require("kara3d.camera") require("utils") re = require("re") @@ -20,11 +20,12 @@ material.__index = material -function material.new(a, d, sp, sh) - local m = {ambient = a or vector.new(3, {1, 1, 1}), - diffuse = d or vector.new(3, {1, 1, 1}), - specular = sp or vector.new(3, {1, 1, 1}), - shininess = sh or 1} +function material.new(amb, diff, spec, sh, al) + local m = {ambient = vector.new(3, amb) or vector.new(3, {1, 1, 1}), + diffuse = vector.new(3, diff) or vector.new(3, {1, 1, 1}), + specular = vector.new(3, spec) or vector.new(3, {1, 1, 1}), + shininess = sh or 1, + alpha = al or 0} setmetatable(m, material) return m end @@ -38,46 +39,37 @@ function face.new(v, n, t) return f end -function face:mean() - sum = vector.zero(3) - for i = 1, #self.vertices do - sum = sum + self.vertices[i] - end - return (1/(#self.vertices)) * sum -end -function face:shade(mat, lights, ambient) +function face.shade(N, P, mat, lights, ambient, cam) local Ka = mat.ambient local Kd = mat.diffuse local Ks = mat.specular local shine = mat.shininess - - local N = self.normal:normalized() - local P = self:mean():normalized() - local V = vector.new(3, {0, 0, -1}) + + local V = (cam.transform:position(true) - P):normalized() local I = Ka * ambient for i = 1, #lights do local l = lights[i] - local L = (light.transform:position(true) - P):normalized() - local R = 2 * vector.dot(L, N) * N - L + local L = (l.transform:position(true) - P):normalized() + local R = 2 * math.max(vector.dot(L, N), 0) * N - L -- Diffuse component - I = I + Kd * vector.dot(L, N) * l.diffuse + I = I + Kd * math.max(vector.dot(L, N), 0) * l.diffuse -- Specular component - I = I + Ks * math.pow(vector.dot(R, V), shine) * l.specular + I = I + Ks * math.pow(math.max(vector.dot(R, V), 0), shine) * l.specular end - return I + return I:clamp(0, 255) end -- Creates a new shape with transform t and faces f -function shape.new(t, f) - local s = {transform = t, faces = f or {}} +function shape.new(t, f, mat) + local s = {transform = t, faces = f or {}, material = mat or material.new()} setmetatable(s, shape) return s end @@ -90,10 +82,17 @@ end -- ********** INSTANCE FUNCTIONS ********** +function shape:set_material(mat) + self.material = mat + return self +end + + + -- Generates a line for each face of this shape, with the indicated tags -- The boolean cull determines if the faces facing away from the screen are -- drawn or not -function shape:draw(subs, line, tags, cull, cam) +function shape:draw(subs, line, tags, cull, cam, ambient, lights) local l = table.copy(line) local p = self.transform:position(true) local r = self.transform:rotation(true) @@ -108,8 +107,8 @@ function shape:draw(subs, line, tags, cull, cam) for i = 1, #self.faces do local face = self.faces[i] - local n = quaternion.mul_vector(r, face.normal) - n = quaternion.mul_vector(cam_inv_rot, n) + local norm = quaternion.mul_vector(r, face.normal) + local n = quaternion.mul_vector(cam_inv_rot, norm) if not (cull and n:z() > 0) then local vs = face.vertices @@ -129,7 +128,16 @@ function shape:draw(subs, line, tags, cull, cam) str = str .. "l " .. v:x() .. " " .. v:y() .. " " end - l.text = str + local P = (p + sum) * (1/#vs) + + + local color = face.shade(n, P, self.material, lights, ambient, cam) + local colorstr = string.format("{\\c%s\\alpha%s}", + ass_color(color:x(), color:y(), color:z()), + ass_alpha(self.material.alpha) + ) + + l.text = colorstr .. str -- layers must be between 0 and 9999999999 l.layer = 500000000 + math.floor((p + sum):z() / #vs) l.effect = "fx" diff --git a/vector.lua b/vector.lua index 60a4e6749c588be863a4b92549fce9d5a327257d..316bdfbb37ba9b7c12d4766a8e5bc53d0beadd02 100644 --- a/vector.lua +++ b/vector.lua @@ -139,6 +139,12 @@ function vector:y() return self.values[2] end function vector:z() return self.values[3] end function vector:w() return self.values[4] end +-- Clamp vector values +function vector:clamp(min, max) + for i = 1, self.size do self:set(i, clamp(self:get(i), min, max)) end + return self +end + -- ********** OPERATOR OVERLOADING ********** -- + binary operator overload