diff --git a/lib/body.lua b/lib/body.lua index c243fad..61f4fc4 100644 --- a/lib/body.lua +++ b/lib/body.lua @@ -1,6 +1,6 @@ local _PACKAGE = (...):match("^(.+)[%./][^%./]+") or "" local class = require(_PACKAGE.."/class") -local height_map_conv = require(_PACKAGE..'/height_map_conv') +local normal_map = require(_PACKAGE..'/normal_map') local vector = require(_PACKAGE..'/vector') local shadowLength = 100000 @@ -299,83 +299,22 @@ end -- set height map function body:setHeightMap(heightMap, strength) - self:setNormalMap(height_map_conv.toNormalMap(heightMap, strength)) + self:setNormalMap(normal_map.fromHeightMap(heightMap, strength)) end -- generate flat normal map function body:generateNormalMapFlat(mode) - local imgData = self.img:getData() - local imgNormalData = love.image.newImageData(self.imgWidth, self.imgHeight) - local color - - if mode == "top" then - color = {127, 127, 255} - elseif mode == "front" then - color = {127, 0, 127} - elseif mode == "back" then - color = {127, 255, 127} - elseif mode == "left" then - color = {31, 0, 223} - elseif mode == "right" then - color = {223, 0, 127} - end - - for i = 0, self.imgHeight - 1 do - for k = 0, self.imgWidth - 1 do - local r, g, b, a = imgData:getPixel(k, i) - if a > 0 then - imgNormalData:setPixel(k, i, color[1], color[2], color[3], 255) - end - end - end - - self:setNormalMap(love.graphics.newImage(imgNormalData)) + self:setNormalMap(normal_map.generateFlat(self.img, mode)) end -- generate faded normal map function body:generateNormalMapGradient(horizontalGradient, verticalGradient) - local imgData = self.img:getData() - local imgNormalData = love.image.newImageData(self.imgWidth, self.imgHeight) - local dx = 255.0 / self.imgWidth - local dy = 255.0 / self.imgHeight - local nx - local ny - local nz - - for i = 0, self.imgWidth - 1 do - for k = 0, self.imgHeight - 1 do - local r, g, b, a = imgData:getPixel(i, k) - if a > 0 then - if horizontalGradient == "gradient" then - nx = i * dx - elseif horizontalGradient == "inverse" then - nx = 255 - i * dx - else - nx = 127 - end - - if verticalGradient == "gradient" then - ny = 127 - k * dy * 0.5 - nz = 255 - k * dy * 0.5 - elseif verticalGradient == "inverse" then - ny = 127 + k * dy * 0.5 - nz = 127 - k * dy * 0.25 - else - ny = 255 - nz = 127 - end - - imgNormalData:setPixel(i, k, nx, ny, nz, 255) - end - end - end - - self:setNormalMap(love.graphics.newImage(imgNormalData)) + self:setNormalMap(normal_map.generateGradient(self.img, horizontalGradient, verticalGradient)) end -- generate normal map function body:generateNormalMap(strength) - self:setNormalMap(height_map_conv.toNormalMap(self.img, strength)) + self:setNormalMap(normal_map.fromHeightMap(self.img, strength)) end -- set material diff --git a/lib/height_map_conv.lua b/lib/height_map_conv.lua deleted file mode 100644 index 0b5eea0..0000000 --- a/lib/height_map_conv.lua +++ /dev/null @@ -1,50 +0,0 @@ -height_map = {} - -function height_map.toNormalMap(heightMap, strength) - local imgData = heightMap:getData() - local imgData2 = love.image.newImageData(heightMap:getWidth(), heightMap:getHeight()) - local red, green, blue, alpha - local x, y - local matrix = {} - matrix[1] = {} - matrix[2] = {} - matrix[3] = {} - strength = strength or 1.0 - - for i = 0, heightMap:getHeight() - 1 do - for k = 0, heightMap:getWidth() - 1 do - for l = 1, 3 do - for m = 1, 3 do - if k + (l - 1) < 1 then - x = heightMap:getWidth() - 1 - elseif k + (l - 1) > heightMap:getWidth() - 1 then - x = 1 - else - x = k + l - 1 - end - - if i + (m - 1) < 1 then - y = heightMap:getHeight() - 1 - elseif i + (m - 1) > heightMap:getHeight() - 1 then - y = 1 - else - y = i + m - 1 - end - - local red, green, blue, alpha = imgData:getPixel(x, y) - matrix[l][m] = red - end - end - - red = (255 + ((matrix[1][2] - matrix[2][2]) + (matrix[2][2] - matrix[3][2])) * strength) / 2.0 - green = (255 + ((matrix[2][2] - matrix[1][1]) + (matrix[2][3] - matrix[2][2])) * strength) / 2.0 - blue = 192 - - imgData2:setPixel(k, i, red, green, blue) - end - end - - return love.graphics.newImage(imgData2) -end - -return height_map diff --git a/lib/light_world.lua b/lib/light_world.lua index f36f68e..9e1ba40 100644 --- a/lib/light_world.lua +++ b/lib/light_world.lua @@ -25,7 +25,7 @@ local _PACKAGE = (...):match("^(.+)[%./][^%./]+") or "" local class = require(_PACKAGE..'/class') local Light = require(_PACKAGE..'/light') local Body = require(_PACKAGE..'/body') -local height_map_conv = require(_PACKAGE..'/height_map_conv') +local normal_map = require(_PACKAGE..'/normal_map') local light_world = class() @@ -456,7 +456,7 @@ end -- new refraction from height map function light_world:newRefractionHeightMap(heightMap, x, y, strength) - local normal = height_map_conv.toNormalMap(heightMap, strength) + local normal = normal_map.fromHeightMap(heightMap, strength) self.isRefraction = true return self.newRefraction(p, normal, x, y) end @@ -469,7 +469,7 @@ end -- new reflection from height map function light_world:newReflectionHeightMap(heightMap, x, y, strength) - local normal = height_map_conv.toNormalMap(heightMap, strength) + local normal = normal_map.fromHeightMap(heightMap, strength) self.isReflection = true return self.newReflection(p, normal, x, y) end diff --git a/lib/normal_map.lua b/lib/normal_map.lua new file mode 100644 index 0000000..04e5a04 --- /dev/null +++ b/lib/normal_map.lua @@ -0,0 +1,123 @@ +normal_map = {} + +function normal_map.fromHeightMap(heightMap, strength) + local imgData = heightMap:getData() + local imgData2 = love.image.newImageData(heightMap:getWidth(), heightMap:getHeight()) + local red, green, blue, alpha + local x, y + local matrix = {} + matrix[1] = {} + matrix[2] = {} + matrix[3] = {} + strength = strength or 1.0 + + for i = 0, heightMap:getHeight() - 1 do + for k = 0, heightMap:getWidth() - 1 do + for l = 1, 3 do + for m = 1, 3 do + if k + (l - 1) < 1 then + x = heightMap:getWidth() - 1 + elseif k + (l - 1) > heightMap:getWidth() - 1 then + x = 1 + else + x = k + l - 1 + end + + if i + (m - 1) < 1 then + y = heightMap:getHeight() - 1 + elseif i + (m - 1) > heightMap:getHeight() - 1 then + y = 1 + else + y = i + m - 1 + end + + local red, green, blue, alpha = imgData:getPixel(x, y) + matrix[l][m] = red + end + end + + red = (255 + ((matrix[1][2] - matrix[2][2]) + (matrix[2][2] - matrix[3][2])) * strength) / 2.0 + green = (255 + ((matrix[2][2] - matrix[1][1]) + (matrix[2][3] - matrix[2][2])) * strength) / 2.0 + blue = 192 + + imgData2:setPixel(k, i, red, green, blue) + end + end + + return love.graphics.newImage(imgData2) +end + +function normal_map.generateFlat(img, mode) + local imgData = img:getData() + local imgNormalData = love.image.newImageData(img:getWidth(), img:getHeight()) + local color + + if mode == "top" then + color = {127, 127, 255} + elseif mode == "front" then + color = {127, 0, 127} + elseif mode == "back" then + color = {127, 255, 127} + elseif mode == "left" then + color = {31, 0, 223} + elseif mode == "right" then + color = {223, 0, 127} + end + + for i = 0, self.imgHeight - 1 do + for k = 0, self.imgWidth - 1 do + local r, g, b, a = imgData:getPixel(k, i) + if a > 0 then + imgNormalData:setPixel(k, i, color[1], color[2], color[3], 255) + end + end + end + + return love.graphics.newImage(imgNormalData) +end + +function normal_map.generateGradient(img, horizontalGradient, verticalGradient) + horizontalGradient = horizontalGradient or "gradient" + verticalGradient = verticalGradient or horizontalGradient + + local imgData = img:getData() + local imgWidth, imgHeight = img:getWidth(), img:getHeight() + local imgNormalData = love.image.newImageData(imgWidth, imgHeight) + local dx = 255.0 / imgWidth + local dy = 255.0 / imgHeight + local nx + local ny + local nz + + for i = 0, imgWidth - 1 do + for k = 0, imgHeight - 1 do + local r, g, b, a = imgData:getPixel(i, k) + if a > 0 then + if horizontalGradient == "gradient" then + nx = i * dx + elseif horizontalGradient == "inverse" then + nx = 255 - i * dx + else + nx = 127 + end + + if verticalGradient == "gradient" then + ny = 127 - k * dy * 0.5 + nz = 255 - k * dy * 0.5 + elseif verticalGradient == "inverse" then + ny = 127 + k * dy * 0.5 + nz = 127 - k * dy * 0.25 + else + ny = 255 + nz = 127 + end + + imgNormalData:setPixel(i, k, nx, ny, nz, 255) + end + end + end + + return love.graphics.newImage(imgNormalData) +end + +return normal_map