mirror of
https://github.com/tanema/light_world.lua.git
synced 2024-12-11 01:14:26 +00:00
made better shadow body calculations so that the z coordinate of the light effects the cast light
This commit is contained in:
parent
64d8613549
commit
7db34a4a02
@ -134,7 +134,7 @@ function love.update(dt)
|
||||
|
||||
mx, my = (love.mouse.getX() - offsetX)/scale, (love.mouse.getY() - offsetY)/scale
|
||||
|
||||
mouseLight:setPosition(mx, my, 16.0 + (math.sin(lightDirection) + 1.0) * 64.0)
|
||||
mouseLight:setPosition(mx, my, 1 + (math.sin(lightDirection) + 1.0) * 64.0)
|
||||
|
||||
lightDirection = lightDirection + dt
|
||||
colorAberration = math.max(0.0, colorAberration - dt * 10.0)
|
||||
|
@ -5,6 +5,7 @@ function love.load()
|
||||
testShader = 0
|
||||
x = 0
|
||||
y = 0
|
||||
z = 1
|
||||
scale = 1
|
||||
colorAberration = 0.0
|
||||
-- load images
|
||||
@ -116,7 +117,15 @@ function love.update(dt)
|
||||
lightWorld.post_shader:removeEffect("chromatic_aberration")
|
||||
end
|
||||
|
||||
lightMouse:setPosition((love.mouse.getX() - x)/scale, (love.mouse.getY() - y)/scale)
|
||||
lightMouse:setPosition((love.mouse.getX() - x)/scale, (love.mouse.getY() - y)/scale, z)
|
||||
end
|
||||
|
||||
function love.mousepressed(x, y, c)
|
||||
if c == "wu" then
|
||||
z = z + 1
|
||||
elseif c == "wd" then
|
||||
z = z - 1
|
||||
end
|
||||
end
|
||||
|
||||
function love.draw()
|
||||
@ -131,6 +140,7 @@ function love.draw()
|
||||
love.graphics.rectangle("fill", 0, 0, love.graphics.getWidth(), 24)
|
||||
love.graphics.setColor(0, 255, 0)
|
||||
love.graphics.print("To toggle postshaders, use 0-9 and q->y, to scale use - and =, and to translate use arrows")
|
||||
love.graphics.print("light z: " .. lightMouse.z, 0, 50)
|
||||
end
|
||||
|
||||
function drawBackground(l,t,w,h)
|
||||
|
148
lib/body.lua
148
lib/body.lua
@ -1,9 +1,8 @@
|
||||
local _PACKAGE = (...):match("^(.+)[%./][^%./]+") or ""
|
||||
local class = require(_PACKAGE.."/class")
|
||||
local normal_map = require(_PACKAGE..'/normal_map')
|
||||
local vector = require(_PACKAGE..'/vector')
|
||||
local shadowLength = 100000
|
||||
|
||||
local vec2 = require(_PACKAGE..'/vec2')
|
||||
local vec3 = require(_PACKAGE..'/vec3')
|
||||
local body = class()
|
||||
|
||||
body.glowShader = love.graphics.newShader(_PACKAGE.."/shaders/glow.glsl")
|
||||
@ -24,6 +23,7 @@ function body:init(id, type, ...)
|
||||
self.glowStrength = 0.0
|
||||
self.tileX = 0
|
||||
self.tileY = 0
|
||||
self.zheight = 1
|
||||
|
||||
if self.type == "circle" then
|
||||
self.x = args[1] or 0
|
||||
@ -88,14 +88,10 @@ end
|
||||
function body:refresh()
|
||||
if self.x and self.y and self.width and self.height and self.ox and self.oy then
|
||||
self.data = {
|
||||
self.x - self.ox,
|
||||
self.y - self.oy,
|
||||
self.x - self.ox + self.width,
|
||||
self.y - self.oy,
|
||||
self.x - self.ox + self.width,
|
||||
self.y - self.oy + self.height,
|
||||
self.x - self.ox,
|
||||
self.y - self.oy + self.height
|
||||
self.x - self.ox, self.y - self.oy,
|
||||
self.x - self.ox + self.width, self.y - self.oy,
|
||||
self.x - self.ox + self.width, self.y - self.oy + self.height,
|
||||
self.x - self.ox, self.y - self.oy + self.height
|
||||
}
|
||||
end
|
||||
end
|
||||
@ -452,7 +448,7 @@ function body:drawShadow(light)
|
||||
end
|
||||
|
||||
function body:drawPixelShadow()
|
||||
if self.normalMesh then
|
||||
if self.type == "image" and self.normalMesh then
|
||||
love.graphics.setColor(255, 255, 255)
|
||||
love.graphics.draw(self.normalMesh, self.x - self.nx, self.y - self.ny)
|
||||
end
|
||||
@ -546,56 +542,57 @@ function body:calculateShadow(light)
|
||||
end
|
||||
end
|
||||
|
||||
--using shadow point calculations from this article
|
||||
--http://web.cs.wpi.edu/~matt/courses/cs563/talks/shadow/shadow.html
|
||||
function body:calculatePolyShadow(light)
|
||||
if self.castsNoShadow then
|
||||
if self.castsNoShadow or (self.zheight - light.z) > 0 then
|
||||
return nil
|
||||
end
|
||||
|
||||
local curPolygon = self.data
|
||||
local edgeFacingTo = {}
|
||||
for k = 1, #curPolygon, 2 do
|
||||
local indexOfNextVertex = (k + 2) % #curPolygon
|
||||
local normal = {-curPolygon[indexOfNextVertex+1] + curPolygon[k + 1], curPolygon[indexOfNextVertex] - curPolygon[k]}
|
||||
local lightToPoint = {curPolygon[k] - light.x, curPolygon[k + 1] - light.y}
|
||||
for k = 1, #self.data, 2 do
|
||||
local indexOfNextVertex = (k + 2) % #self.data
|
||||
local normal = vec2(-self.data[indexOfNextVertex+1] + self.data[k + 1], self.data[indexOfNextVertex] - self.data[k]):normalize()
|
||||
local lightToPoint = vec2(self.data[k] - light.x, self.data[k + 1] - light.y):normalize()
|
||||
|
||||
normal = vector.normalize(normal)
|
||||
lightToPoint = vector.normalize(lightToPoint)
|
||||
|
||||
local dotProduct = vector.dot(normal, lightToPoint)
|
||||
if dotProduct > 0 then table.insert(edgeFacingTo, true)
|
||||
else table.insert(edgeFacingTo, false) end
|
||||
local dotProduct = normal:dot(lightToPoint)
|
||||
if dotProduct > 0 then
|
||||
table.insert(edgeFacingTo, true)
|
||||
else
|
||||
table.insert(edgeFacingTo, false)
|
||||
end
|
||||
end
|
||||
|
||||
local curShadowGeometry = {}
|
||||
local lxh = (light.x * self.zheight)
|
||||
local lyh = (light.y * self.zheight)
|
||||
local height_diff = (self.zheight - light.z)
|
||||
if height_diff == 0 then -- prevent inf
|
||||
height_diff = -0.001
|
||||
end
|
||||
for k = 1, #edgeFacingTo do
|
||||
local nextIndex = (k + 1) % #edgeFacingTo
|
||||
if nextIndex == 0 then nextIndex = #edgeFacingTo end
|
||||
|
||||
local x, y = self.data[nextIndex*2-1], self.data[nextIndex*2]
|
||||
local xs, ys = (lxh - (x * light.z))/height_diff, (lyh - (y * light.z))/height_diff
|
||||
|
||||
if edgeFacingTo[k] and not edgeFacingTo[nextIndex] then
|
||||
curShadowGeometry[1] = curPolygon[nextIndex*2-1]
|
||||
curShadowGeometry[2] = curPolygon[nextIndex*2]
|
||||
|
||||
local lightVecFrontBack = vector.normalize({curPolygon[nextIndex*2-1] - light.x, curPolygon[nextIndex*2] - light.y})
|
||||
curShadowGeometry[3] = curShadowGeometry[1] + lightVecFrontBack[1] * shadowLength
|
||||
curShadowGeometry[4] = curShadowGeometry[2] + lightVecFrontBack[2] * shadowLength
|
||||
|
||||
curShadowGeometry[#curShadowGeometry+1] = x
|
||||
curShadowGeometry[#curShadowGeometry+1] = y
|
||||
curShadowGeometry[#curShadowGeometry+1] = xs
|
||||
curShadowGeometry[#curShadowGeometry+1] = ys
|
||||
elseif not edgeFacingTo[k] and not edgeFacingTo[nextIndex] then
|
||||
curShadowGeometry[#curShadowGeometry+1] = xs
|
||||
curShadowGeometry[#curShadowGeometry+1] = ys
|
||||
elseif not edgeFacingTo[k] and edgeFacingTo[nextIndex] then
|
||||
curShadowGeometry[7] = curPolygon[nextIndex*2-1]
|
||||
curShadowGeometry[8] = curPolygon[nextIndex*2]
|
||||
|
||||
local lightVecBackFront = vector.normalize({curPolygon[nextIndex*2-1] - light.x, curPolygon[nextIndex*2] - light.y})
|
||||
curShadowGeometry[5] = curShadowGeometry[7] + lightVecBackFront[1] * shadowLength
|
||||
curShadowGeometry[6] = curShadowGeometry[8] + lightVecBackFront[2] * shadowLength
|
||||
curShadowGeometry[#curShadowGeometry+1] = xs
|
||||
curShadowGeometry[#curShadowGeometry+1] = ys
|
||||
curShadowGeometry[#curShadowGeometry+1] = x
|
||||
curShadowGeometry[#curShadowGeometry+1] = y
|
||||
end
|
||||
end
|
||||
if curShadowGeometry[1]
|
||||
and curShadowGeometry[2]
|
||||
and curShadowGeometry[3]
|
||||
and curShadowGeometry[4]
|
||||
and curShadowGeometry[5]
|
||||
and curShadowGeometry[6]
|
||||
and curShadowGeometry[7]
|
||||
and curShadowGeometry[8]
|
||||
then
|
||||
if #curShadowGeometry >= 6 then
|
||||
curShadowGeometry.alpha = self.alpha
|
||||
curShadowGeometry.red = self.red
|
||||
curShadowGeometry.green = self.green
|
||||
@ -606,38 +603,47 @@ function body:calculatePolyShadow(light)
|
||||
end
|
||||
end
|
||||
|
||||
--using shadow point calculations from this article
|
||||
--http://web.cs.wpi.edu/~matt/courses/cs563/talks/shadow/shadow.html
|
||||
function body:calculateCircleShadow(light)
|
||||
if self.castsNoShadow then
|
||||
if self.castsNoShadow or (self.zheight - light.z) > 0 then
|
||||
return nil
|
||||
end
|
||||
local length = math.sqrt(math.pow(light.x - (self.x - self.ox), 2) + math.pow(light.y - (self.y - self.oy), 2))
|
||||
if length >= self.radius and length <= light.range then
|
||||
local curShadowGeometry = {}
|
||||
local angle = math.atan2(light.x - (self.x - self.ox), (self.y - self.oy) - light.y) + math.pi / 2
|
||||
local x2 = ((self.x - self.ox) + math.sin(angle) * self.radius)
|
||||
local y2 = ((self.y - self.oy) - math.cos(angle) * self.radius)
|
||||
local x3 = ((self.x - self.ox) - math.sin(angle) * self.radius)
|
||||
local y3 = ((self.y - self.oy) + math.cos(angle) * self.radius)
|
||||
|
||||
curShadowGeometry[1] = x2
|
||||
curShadowGeometry[2] = y2
|
||||
curShadowGeometry[3] = x3
|
||||
curShadowGeometry[4] = y3
|
||||
local curShadowGeometry = {}
|
||||
local angle = math.atan2(light.x - (self.x - self.ox), (self.y - self.oy) - light.y) + math.pi / 2
|
||||
local x2 = ((self.x - self.ox) + math.sin(angle) * self.radius)
|
||||
local y2 = ((self.y - self.oy) - math.cos(angle) * self.radius)
|
||||
local x3 = ((self.x - self.ox) - math.sin(angle) * self.radius)
|
||||
local y3 = ((self.y - self.oy) + math.cos(angle) * self.radius)
|
||||
|
||||
curShadowGeometry[5] = x3 - (light.x - x3) * shadowLength
|
||||
curShadowGeometry[6] = y3 - (light.y - y3) * shadowLength
|
||||
curShadowGeometry[7] = x2 - (light.x - x2) * shadowLength
|
||||
curShadowGeometry[8] = y2 - (light.y - y2) * shadowLength
|
||||
curShadowGeometry[1] = x2
|
||||
curShadowGeometry[2] = y2
|
||||
curShadowGeometry[3] = x3
|
||||
curShadowGeometry[4] = y3
|
||||
|
||||
curShadowGeometry.red = self.red
|
||||
curShadowGeometry.green = self.green
|
||||
curShadowGeometry.blue = self.blue
|
||||
curShadowGeometry.alpha = self.alpha
|
||||
|
||||
return curShadowGeometry
|
||||
else
|
||||
return nil
|
||||
local lxh = (light.x * self.zheight)
|
||||
local lyh = (light.y * self.zheight)
|
||||
local height_diff = (self.zheight - light.z)
|
||||
if height_diff == 0 then -- prevent inf
|
||||
height_diff = -0.001
|
||||
end
|
||||
|
||||
curShadowGeometry[5] = (lxh - (x3 * light.z))/height_diff
|
||||
curShadowGeometry[6] = (lyh - (y3 * light.z))/height_diff
|
||||
curShadowGeometry[7] = (lxh - (x2 * light.z))/height_diff
|
||||
curShadowGeometry[8] = (lyh - (y2 * light.z))/height_diff
|
||||
|
||||
local radius = math.sqrt(math.pow(curShadowGeometry[7] - curShadowGeometry[5], 2) + math.pow(curShadowGeometry[8]-curShadowGeometry[6], 2)) / 2
|
||||
local cx, cy = (curShadowGeometry[5] + curShadowGeometry[7])/2, (curShadowGeometry[6] + curShadowGeometry[8])/2
|
||||
curShadowGeometry.circle = {cx, cy, radius}
|
||||
|
||||
curShadowGeometry.red = self.red
|
||||
curShadowGeometry.green = self.green
|
||||
curShadowGeometry.blue = self.blue
|
||||
curShadowGeometry.alpha = self.alpha
|
||||
|
||||
return curShadowGeometry
|
||||
end
|
||||
|
||||
return body
|
||||
|
@ -7,7 +7,6 @@ local light = class()
|
||||
|
||||
light.shader = love.graphics.newShader(_PACKAGE.."/shaders/poly_shadow.glsl")
|
||||
light.normalShader = love.graphics.newShader(_PACKAGE.."/shaders/normal.glsl")
|
||||
light.normalInvertShader = love.graphics.newShader(_PACKAGE.."/shaders/normal_invert.glsl")
|
||||
|
||||
function light:init(x, y, r, g, b, range)
|
||||
self.direction = 0
|
||||
@ -15,7 +14,7 @@ function light:init(x, y, r, g, b, range)
|
||||
self.range = 0
|
||||
self.x = x or 0
|
||||
self.y = y or 0
|
||||
self.z = 15
|
||||
self.z = 1
|
||||
self.red = r or 255
|
||||
self.green = g or 255
|
||||
self.blue = b or 255
|
||||
@ -32,7 +31,6 @@ function light:refresh(w, h)
|
||||
|
||||
self.shadow = love.graphics.newCanvas(w, h)
|
||||
self.shine = love.graphics.newCanvas(w, h)
|
||||
self.normalInvertShader:send('screenResolution', {w, h})
|
||||
self.normalShader:send('screenResolution', {w, h})
|
||||
end
|
||||
|
||||
@ -199,23 +197,14 @@ end
|
||||
|
||||
function light:drawPixelShadow(l,t,w,h,s, normalMap, canvas)
|
||||
if self.visible and self:inRange(l,t,w,h,s) then
|
||||
if self.normalInvert then
|
||||
self.normalInvertShader:send('lightColor', {self.red / 255.0, self.green / 255.0, self.blue / 255.0})
|
||||
self.normalInvertShader:send("lightPosition", {(self.x + l/s) * s, (h/s - (self.y + t/s)) * s, self.z / 255.0})
|
||||
self.normalInvertShader:send('lightRange',{self.range})
|
||||
self.normalInvertShader:send("lightSmooth", self.smooth)
|
||||
self.normalInvertShader:send("lightAngle", math.pi - self.angle / 2.0)
|
||||
self.normalInvertShader:send("lightDirection", self.direction)
|
||||
util.drawCanvasToCanvas(normalMap, canvas, {shader = self.normalInvertShader})
|
||||
else
|
||||
self.normalShader:send('lightColor', {self.red / 255.0, self.green / 255.0, self.blue / 255.0})
|
||||
self.normalShader:send("lightPosition", {(self.x + l/s) * s, (h/s - (self.y + t/s)) * s, self.z / 255.0})
|
||||
self.normalShader:send('lightRange',{self.range})
|
||||
self.normalShader:send("lightSmooth", self.smooth)
|
||||
self.normalShader:send("lightAngle", math.pi - self.angle / 2.0)
|
||||
self.normalShader:send("lightDirection", self.direction)
|
||||
util.drawCanvasToCanvas(normalMap, canvas, {shader = self.normalShader})
|
||||
end
|
||||
self.normalShader:send('lightColor', {self.red / 255.0, self.green / 255.0, self.blue / 255.0})
|
||||
self.normalShader:send("lightPosition", {(self.x + l/s) * s, (h/s - (self.y + t/s)) * s, self.z / 255.0})
|
||||
self.normalShader:send('lightRange',{self.range})
|
||||
self.normalShader:send("lightSmooth", self.smooth)
|
||||
self.normalShader:send("lightAngle", math.pi - self.angle / 2.0)
|
||||
self.normalShader:send("lightDirection", self.direction)
|
||||
self.normalShader:send("invert_normal", self.normalInvert == true)
|
||||
util.drawCanvasToCanvas(normalMap, canvas, {shader = self.normalShader})
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -7,6 +7,7 @@ extern float lightRange;
|
||||
extern float lightSmooth;
|
||||
extern float lightDirection;
|
||||
extern float lightAngle;
|
||||
extern bool invert_normal;
|
||||
|
||||
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
|
||||
vec4 pixelColor = Texel(texture, texture_coords);
|
||||
@ -25,7 +26,12 @@ vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
|
||||
}
|
||||
}
|
||||
|
||||
vec3 normal = pixelColor.rgb;
|
||||
vec3 normal;
|
||||
if(invert_normal == true) {
|
||||
normal = vec3(pixelColor.r, 1 - pixelColor.g, pixelColor.b);
|
||||
} else {
|
||||
normal = pixelColor.rgb;
|
||||
}
|
||||
float dist = distance(lightPosition, vec3(pixel_coords, normal.b));
|
||||
|
||||
if(dist < lightRange) {
|
||||
@ -47,4 +53,4 @@ vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
|
||||
} else {
|
||||
return vec4(0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,50 +0,0 @@
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
|
||||
extern vec2 screenResolution;
|
||||
extern vec3 lightPosition;
|
||||
extern vec3 lightColor;
|
||||
extern float lightRange;
|
||||
extern float lightSmooth;
|
||||
extern float lightDirection;
|
||||
extern float lightAngle;
|
||||
|
||||
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
|
||||
vec4 pixelColor = Texel(texture, texture_coords);
|
||||
|
||||
if(pixelColor.a > 0.0) {
|
||||
if(lightAngle > 0.0) {
|
||||
float angle2 = atan(lightPosition.x - pixel_coords.x, pixel_coords.y - lightPosition.y) + PI;
|
||||
if(lightDirection - lightAngle > 0 && lightDirection + lightAngle < PI * 2) {
|
||||
if(angle2 < mod(lightDirection + lightAngle, PI * 2) && angle2 > mod(lightDirection - lightAngle, PI * 2)) {
|
||||
return vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
} else {
|
||||
if(angle2 < mod(lightDirection + lightAngle, PI * 2) || angle2 > mod(lightDirection - lightAngle, PI * 2)) {
|
||||
return vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vec3 normal = vec3(pixelColor.r, 1 - pixelColor.g, pixelColor.b);
|
||||
float dist = distance(lightPosition, vec3(pixel_coords, normal.b));
|
||||
|
||||
if(dist < lightRange) {
|
||||
vec3 dir = vec3((lightPosition.xy - pixel_coords.xy) / screenResolution.xy, lightPosition.z);
|
||||
|
||||
dir.x *= screenResolution.x / screenResolution.y;
|
||||
|
||||
vec3 N = normalize(normal * 2.0 - 1.0);
|
||||
vec3 L = normalize(dir);
|
||||
|
||||
vec3 diff = lightColor * max(dot(N, L), 0.0);
|
||||
|
||||
float att = clamp((1.0 - dist / lightRange) / lightSmooth, 0.0, 1.0);
|
||||
|
||||
return vec4(diff * att, 1.0);
|
||||
} else {
|
||||
return vec4(0.0, 0.0, 0.0, 1.0);
|
||||
}
|
||||
} else {
|
||||
return vec4(0.0);
|
||||
}
|
||||
}
|
@ -6,6 +6,9 @@ function stencils.shadow(geometry, bodies)
|
||||
for i = 1,#geometry do
|
||||
if geometry[i].alpha == 1.0 then
|
||||
love.graphics.polygon("fill", unpack(geometry[i]))
|
||||
if geometry[i].circle then
|
||||
love.graphics.circle("fill", unpack(geometry[i].circle))
|
||||
end
|
||||
end
|
||||
end
|
||||
-- underneath shadows
|
||||
|
27
lib/vec2.lua
Normal file
27
lib/vec2.lua
Normal file
@ -0,0 +1,27 @@
|
||||
local _PACKAGE = (...):match("^(.+)[%./][^%./]+") or ""
|
||||
local class = require(_PACKAGE.."/class")
|
||||
|
||||
local vec2 = class()
|
||||
|
||||
function vec2:init(x, y)
|
||||
self.x, self.y = x, y
|
||||
end
|
||||
|
||||
function vec2:normalize()
|
||||
local len = self:length()
|
||||
return vec2(self.x / len, self.y / len)
|
||||
end
|
||||
|
||||
function vec2:dot(v2)
|
||||
return (self.x * v2.x) + (self.y * v2.y)
|
||||
end
|
||||
|
||||
function vec2:cross(v2)
|
||||
return ((self.x * v2.y) - (self.y * v2.x))
|
||||
end
|
||||
|
||||
function vec2:length()
|
||||
return math.sqrt(self:dot(self))
|
||||
end
|
||||
|
||||
return vec2
|
30
lib/vec3.lua
Normal file
30
lib/vec3.lua
Normal file
@ -0,0 +1,30 @@
|
||||
local _PACKAGE = (...):match("^(.+)[%./][^%./]+") or ""
|
||||
local class = require(_PACKAGE.."/class")
|
||||
|
||||
local vec3 = class()
|
||||
|
||||
function vec3:init(x, y, z)
|
||||
self.x, self.y, self.z = x, y, z
|
||||
end
|
||||
|
||||
function vec3:normalize()
|
||||
local len = self:length()
|
||||
return vec3((self.x / len), (self.y / len), (self.z / len))
|
||||
end
|
||||
|
||||
function vec3:dot(v2)
|
||||
return (self.x * v2.x) + (self.y * v2.y) + (self.z * v2.z)
|
||||
end
|
||||
|
||||
function vec3:cross(v2)
|
||||
return ((self.y * v2.z) - (self.z * v2.y)),
|
||||
((self.z * v2.x) - (self.x * v2.z)),
|
||||
((self.x * v2.y) - (self.y * v2.x))
|
||||
end
|
||||
|
||||
function vec3:length()
|
||||
return math.sqrt(self:dot(self))
|
||||
end
|
||||
|
||||
return vec3
|
||||
|
@ -1,21 +0,0 @@
|
||||
local vector = {}
|
||||
-- vector functions
|
||||
function vector.normalize(v)
|
||||
local len = math.sqrt(math.pow(v[1], 2) + math.pow(v[2], 2))
|
||||
local normalizedv = {v[1] / len, v[2] / len}
|
||||
return normalizedv
|
||||
end
|
||||
|
||||
function vector.dot(v1, v2)
|
||||
return v1[1] * v2[1] + v1[2] * v2[2]
|
||||
end
|
||||
|
||||
function vector.lengthSqr(v)
|
||||
return v[1] * v[1] + v[2] * v[2]
|
||||
end
|
||||
|
||||
function vector.length(v)
|
||||
return math.sqrt(lengthSqr(v))
|
||||
end
|
||||
|
||||
return vector
|
Loading…
Reference in New Issue
Block a user