Add material system.

This commit is contained in:
Marcus Ihde 2014-03-24 05:01:07 +01:00
parent e9cb98889b
commit 5caeb12568
23 changed files with 209 additions and 32 deletions

BIN
gfx/ape.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
gfx/ape_glow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
gfx/ape_normal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 981 B

After

Width:  |  Height:  |  Size: 981 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
gfx/sphere/cooper.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
gfx/sphere/glass.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
gfx/sphere/glow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
gfx/sphere/lava.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
gfx/sphere/neon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
gfx/sphere/reflect.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
gfx/sphere/toon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

119
light.lua
View File

@ -39,6 +39,7 @@ function love.light.newWorld()
o.refractionMap2 = love.graphics.newCanvas() o.refractionMap2 = love.graphics.newCanvas()
o.reflectionMap = love.graphics.newCanvas() o.reflectionMap = love.graphics.newCanvas()
o.reflectionMap2 = love.graphics.newCanvas() o.reflectionMap2 = love.graphics.newCanvas()
o.normalInvert = false
o.glowBlur = 1.0 o.glowBlur = 1.0
o.isGlowBlur = false o.isGlowBlur = false
o.glowTimer = 0.0 o.glowTimer = 0.0
@ -49,6 +50,8 @@ function love.light.newWorld()
o.shader = love.graphics.newShader("shader/poly_shadow.glsl") o.shader = love.graphics.newShader("shader/poly_shadow.glsl")
o.glowShader = love.graphics.newShader("shader/glow.glsl") o.glowShader = love.graphics.newShader("shader/glow.glsl")
o.normalShader = love.graphics.newShader("shader/normal.glsl") o.normalShader = love.graphics.newShader("shader/normal.glsl")
o.normalInvertShader = love.graphics.newShader("shader/normal_invert.glsl")
o.materialShader = love.graphics.newShader("shader/material.glsl")
o.refractionShader = love.graphics.newShader("shader/refraction.glsl") o.refractionShader = love.graphics.newShader("shader/refraction.glsl")
o.refractionShader:send("screen", {love.window.getWidth(), love.window.getHeight()}) o.refractionShader:send("screen", {love.window.getWidth(), love.window.getHeight()})
o.reflectionShader = love.graphics.newShader("shader/reflection.glsl") o.reflectionShader = love.graphics.newShader("shader/reflection.glsl")
@ -219,14 +222,25 @@ function love.light.newWorld()
for i = 1, #o.lights do for i = 1, #o.lights do
if o.lights[i].visible then if o.lights[i].visible then
o.normalShader:send('screenResolution', {love.graphics.getWidth(), love.graphics.getHeight()}) if normalInvert then
o.normalShader:send('lightColor', {o.lights[i].red / 255.0, o.lights[i].green / 255.0, o.lights[i].blue / 255.0}) o.normalInvertShader:send('screenResolution', {love.graphics.getWidth(), love.graphics.getHeight()})
o.normalShader:send('lightPosition',{o.lights[i].x, love.graphics.getHeight() - o.lights[i].y, o.lights[i].z / 255.0}) o.normalInvertShader:send('lightColor', {o.lights[i].red / 255.0, o.lights[i].green / 255.0, o.lights[i].blue / 255.0})
o.normalShader:send('lightRange',{o.lights[i].range}) o.normalInvertShader:send('lightPosition',{o.lights[i].x, love.graphics.getHeight() - o.lights[i].y, o.lights[i].z / 255.0})
o.normalShader:send("lightSmooth", o.lights[i].smooth) o.normalInvertShader:send('lightRange',{o.lights[i].range})
o.normalShader:send("lightAngle", math.pi - o.lights[i].angle / 2.0) o.normalInvertShader:send("lightSmooth", o.lights[i].smooth)
o.normalShader:send("lightDirection", o.lights[i].direction) o.normalInvertShader:send("lightAngle", math.pi - o.lights[i].angle / 2.0)
love.graphics.setShader(o.normalShader) o.normalInvertShader:send("lightDirection", o.lights[i].direction)
love.graphics.setShader(o.normalInvertShader)
else
o.normalShader:send('screenResolution', {love.graphics.getWidth(), love.graphics.getHeight()})
o.normalShader:send('lightColor', {o.lights[i].red / 255.0, o.lights[i].green / 255.0, o.lights[i].blue / 255.0})
o.normalShader:send('lightPosition',{o.lights[i].x, love.graphics.getHeight() - o.lights[i].y, o.lights[i].z / 255.0})
o.normalShader:send('lightRange',{o.lights[i].range})
o.normalShader:send("lightSmooth", o.lights[i].smooth)
o.normalShader:send("lightAngle", math.pi - o.lights[i].angle / 2.0)
o.normalShader:send("lightDirection", o.lights[i].direction)
love.graphics.setShader(o.normalShader)
end
love.graphics.draw(o.normalMap, LOVE_LIGHT_TRANSLATE_X, LOVE_LIGHT_TRANSLATE_Y) love.graphics.draw(o.normalMap, LOVE_LIGHT_TRANSLATE_X, LOVE_LIGHT_TRANSLATE_Y)
end end
end end
@ -408,6 +422,18 @@ function love.light.newWorld()
love.graphics.draw(o.pixelShadow, LOVE_LIGHT_TRANSLATE_X, LOVE_LIGHT_TRANSLATE_Y) love.graphics.draw(o.pixelShadow, LOVE_LIGHT_TRANSLATE_X, LOVE_LIGHT_TRANSLATE_Y)
love.graphics.setBlendMode("alpha") love.graphics.setBlendMode("alpha")
end end
-- draw material
o.drawMaterial = function()
love.graphics.setShader(o.materialShader)
for i = 1, #o.body do
if o.body[i].material and o.body[i].normal then
love.graphics.setColor(255, 255, 255)
o.materialShader:send("material", o.body[i].material)
love.graphics.draw(o.body[i].normal, o.body[i].x - o.body[i].nx + LOVE_LIGHT_TRANSLATE_X, o.body[i].y - o.body[i].ny + LOVE_LIGHT_TRANSLATE_Y)
end
end
love.graphics.setShader()
end
-- draw glow -- draw glow
o.drawGlow = function() o.drawGlow = function()
love.graphics.setColor(255, 255, 255) love.graphics.setColor(255, 255, 255)
@ -507,6 +533,10 @@ function love.light.newWorld()
o.setAmbientBlue = function(blue) o.setAmbientBlue = function(blue)
o.ambient[3] = blue o.ambient[3] = blue
end end
-- set normal invert
o.setNormalInvert = function(invert)
o.normalInvert = invert
end
-- set blur -- set blur
o.setBlur = function(blur) o.setBlur = function(blur)
o.blur = blur o.blur = blur
@ -558,6 +588,14 @@ function love.light.newWorld()
o.newRefractionHeightMap = function(heightMap, x, y, strength) o.newRefractionHeightMap = function(heightMap, x, y, strength)
return love.light.newRefractionHeightMap(o, heightMap, x, y, strength) return love.light.newRefractionHeightMap(o, heightMap, x, y, strength)
end end
-- new reflection
o.newReflection = function(normal, x, y)
return love.light.newReflection(o, normal, x, y)
end
-- new reflection from height map
o.newReflectionHeightMap = function(heightMap, x, y, strength)
return love.light.newReflectionHeightMap(o, heightMap, x, y, strength)
end
-- new body -- new body
o.newBody = function(type, ...) o.newBody = function(type, ...)
return love.light.newBody(o, type, ...) return love.light.newBody(o, type, ...)
@ -738,6 +776,7 @@ function love.light.newBody(p, type, ...)
o.id = #p.body o.id = #p.body
o.type = type o.type = type
o.normal = nil o.normal = nil
o.material = nil
o.glow = nil o.glow = nil
if o.type == "circle" then if o.type == "circle" then
o.x = args[1] or 0 o.x = args[1] or 0
@ -834,12 +873,41 @@ function love.light.newBody(p, type, ...)
o.width = args[4] or 64 o.width = args[4] or 64
o.height = args[5] or 64 o.height = args[5] or 64
end end
o.ox = o.width / 2.0 o.ox = o.width * 0.5
o.oy = o.height / 2.0 o.oy = o.height * 0.5
o.reflection = false o.reflection = false
o.reflective = false o.reflective = false
o.refraction = true o.refraction = true
o.refractive = false o.refractive = false
elseif o.type == "reflection" then
o.normal = args[1]
o.x = args[2] or 0
o.y = args[3] or 0
if o.normal then
o.normalWidth = o.normal:getWidth()
o.normalHeight = o.normal:getHeight()
o.width = args[4] or o.normalWidth
o.height = args[5] or o.normalHeight
o.nx = o.normalWidth * 0.5
o.ny = o.normalHeight * 0.5
o.normal:setWrap("repeat", "repeat")
o.normalVert = {
{0.0, 0.0, 0.0, 0.0},
{o.width, 0.0, 1.0, 0.0},
{o.width, o.height, 1.0, 1.0},
{0.0, o.height, 0.0, 1.0}
}
o.normalMesh = love.graphics.newMesh(o.normalVert, o.normal, "fan")
else
o.width = args[4] or 64
o.height = args[5] or 64
end
o.ox = o.width * 0.5
o.oy = o.height * 0.5
o.reflection = true
o.reflective = false
o.refraction = false
o.refractive = false
end end
o.shine = true o.shine = true
o.red = 0 o.red = 0
@ -1062,13 +1130,13 @@ function love.light.newBody(p, type, ...)
if mode == "top" then if mode == "top" then
color = {127, 127, 255} color = {127, 127, 255}
elseif mode == "front" then elseif mode == "front" then
color = {127, 255, 127}
elseif mode == "back" then
color = {127, 0, 127} color = {127, 0, 127}
elseif mode == "back" then
color = {127, 255, 127}
elseif mode == "left" then elseif mode == "left" then
color = {31, 255, 223} color = {31, 0, 223}
elseif mode == "right" then elseif mode == "right" then
color = {223, 223, 127} color = {223, 0, 127}
end end
for i = 0, o.imgHeight - 1 do for i = 0, o.imgHeight - 1 do
@ -1109,10 +1177,10 @@ function love.light.newBody(p, type, ...)
end end
if verticalGradient == "gradient" then if verticalGradient == "gradient" then
ny = 127 + k * dy * 0.5 ny = 127 - k * dy * 0.5
nz = 255 - k * dy * 0.5 nz = 255 - k * dy * 0.5
elseif verticalGradient == "inverse" then elseif verticalGradient == "inverse" then
ny = 127 - k * dy * 0.5 ny = 127 + k * dy * 0.5
nz = 127 - k * dy * 0.25 nz = 127 - k * dy * 0.25
else else
ny = 255 ny = 255
@ -1138,6 +1206,12 @@ function love.light.newBody(p, type, ...)
o.nx = o.normalWidth * 0.5 o.nx = o.normalWidth * 0.5
o.ny = o.normalHeight * 0.5 o.ny = o.normalHeight * 0.5
end end
-- set material
o.setMaterial = function(material)
if material then
o.material = material
end
end
-- set normal -- set normal
o.setGlowMap = function(glow) o.setGlowMap = function(glow)
o.glow = glow o.glow = glow
@ -1242,6 +1316,17 @@ function love.light.newRefractionHeightMap(p, heightMap, x, y, strength)
return love.light.newRefraction(p, normal, x, y) return love.light.newRefraction(p, normal, x, y)
end end
-- reflection object
function love.light.newReflection(p, normal, x, y, width, height)
return p.newBody("reflection", normal, x, y, width, height)
end
-- reflection object (height map)
function love.light.newReflectionHeightMap(p, heightMap, x, y, strength)
local normal = HeightMapToNormalMap(heightMap, strength)
return love.light.newReflection(p, normal, x, y)
end
-- vector functions -- vector functions
function normalize(v) function normalize(v)
local len = math.sqrt(math.pow(v[1], 2) + math.pow(v[2], 2)) local len = math.sqrt(math.pow(v[1], 2) + math.pow(v[2], 2))
@ -1423,7 +1508,7 @@ function HeightMapToNormalMap(heightMap, strength)
end end
red = (255 + ((matrix[1][2] - matrix[2][2]) + (matrix[2][2] - matrix[3][2])) * strength) / 2.0 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 green = (255 + ((matrix[2][2] - matrix[1][1]) + (matrix[2][3] - matrix[2][2])) * strength) / 2.0
blue = 192 blue = 192
imgData2:setPixel(k, i, red, green, blue) imgData2:setPixel(k, i, red, green, blue)

View File

@ -72,6 +72,17 @@ function love.load()
led_glow = love.graphics.newImage("gfx/led_glow.png") led_glow = love.graphics.newImage("gfx/led_glow.png")
led_glow2 = love.graphics.newImage("gfx/led_glow2.png") led_glow2 = love.graphics.newImage("gfx/led_glow2.png")
led_glow3 = love.graphics.newImage("gfx/led_glow3.png") led_glow3 = love.graphics.newImage("gfx/led_glow3.png")
ape = love.graphics.newImage("gfx/ape.png")
ape_normal = love.graphics.newImage("gfx/ape_normal.png")
ape_glow = love.graphics.newImage("gfx/ape_glow.png")
-- materials
material = {}
local files = love.filesystem.getDirectoryItems("gfx/sphere")
for i, file in ipairs(files) do
material[i] = love.graphics.newImage("gfx/sphere/" .. file)
end
-- light world -- light world
lightRange = 400 lightRange = 400
@ -80,9 +91,10 @@ function love.load()
lightWorld.setAmbientColor(15, 15, 31) lightWorld.setAmbientColor(15, 15, 31)
lightWorld.setRefractionStrength(16.0) lightWorld.setRefractionStrength(16.0)
lightWorld.setReflectionVisibility(0.75) lightWorld.setReflectionVisibility(0.75)
mouseLight = lightWorld.newLight(0, 0, 255, 127, 63, lightRange) mouseLight = lightWorld.newLight(0, 0, 255, 191, 127, lightRange)
mouseLight.setGlowStrength(0.3) mouseLight.setGlowStrength(0.3)
mouseLight.setSmooth(lightSmooth) mouseLight.setSmooth(lightSmooth)
mouseLight.z = 63
lightDirection = 0.0 lightDirection = 0.0
colorAberration = 0.0 colorAberration = 0.0
@ -270,7 +282,7 @@ function love.draw()
love.graphics.setBlendMode("alpha") love.graphics.setBlendMode("alpha")
for i = 1, phyCnt do for i = 1, phyCnt do
if phyLight[i].getType() == "image" then if phyLight[i].getType() == "image" and not phyLight[i].material then
if not normalOn then if not normalOn then
math.randomseed(i) math.randomseed(i)
love.graphics.setColor(math.random(127, 255), math.random(127, 255), math.random(127, 255)) love.graphics.setColor(math.random(127, 255), math.random(127, 255), math.random(127, 255))
@ -282,6 +294,8 @@ function love.draw()
end end
end end
lightWorld.drawMaterial()
-- draw pixel shadow -- draw pixel shadow
if lightOn and not normalOn then if lightOn and not normalOn then
lightWorld.drawPixelShadow() lightWorld.drawPixelShadow()
@ -479,7 +493,7 @@ function love.keypressed(k, u)
initScene() initScene()
elseif k == "f12" then elseif k == "f12" then
lightWorld.clearLights() lightWorld.clearLights()
mouseLight = lightWorld.newLight(0, 0, 255, 127, 63, lightRange) mouseLight = lightWorld.newLight(0, 0, 255, 191, 127, lightRange)
mouseLight.setGlowStrength(0.3) mouseLight.setGlowStrength(0.3)
mouseLight.setSmooth(lightSmooth) mouseLight.setSmooth(lightSmooth)
elseif k == "1" then elseif k == "1" then
@ -493,24 +507,42 @@ function love.keypressed(k, u)
phyFixture[phyCnt] = love.physics.newFixture(phyBody[phyCnt], phyShape[phyCnt]) phyFixture[phyCnt] = love.physics.newFixture(phyBody[phyCnt], phyShape[phyCnt])
phyFixture[phyCnt]:setRestitution(0.5) phyFixture[phyCnt]:setRestitution(0.5)
elseif k == "2" then elseif k == "2" then
-- add image local r = lightWorld.getBodyCount() % 2
phyCnt = phyCnt + 1 if r == 0 then
phyLight[phyCnt] = lightWorld.newImage(cone, mx, my, 24, 12, 12, 16) -- add image
phyLight[phyCnt].setNormalMap(cone_normal) phyCnt = phyCnt + 1
phyLight[phyCnt].setShadowType("circle", 12, 0, -8) phyLight[phyCnt] = lightWorld.newImage(cone, mx, my, 24, 12, 12, 16)
phyBody[phyCnt] = love.physics.newBody(physicWorld, mx, my, "dynamic") phyLight[phyCnt].setNormalMap(cone_normal)
phyShape[phyCnt] = love.physics.newRectangleShape(0, 0, 24, 32) phyLight[phyCnt].setShadowType("circle", 12, 0, -8)
phyFixture[phyCnt] = love.physics.newFixture(phyBody[phyCnt], phyShape[phyCnt]) phyBody[phyCnt] = love.physics.newBody(physicWorld, mx, my, "dynamic")
phyFixture[phyCnt]:setRestitution(0.5) phyShape[phyCnt] = love.physics.newRectangleShape(0, 0, 24, 32)
phyFixture[phyCnt] = love.physics.newFixture(phyBody[phyCnt], phyShape[phyCnt])
phyFixture[phyCnt]:setRestitution(0.5)
elseif r == 1 then
-- add image
phyCnt = phyCnt + 1
phyLight[phyCnt] = lightWorld.newImage(chest, mx, my, 32, 24, 16, 0)
phyLight[phyCnt].setNormalMap(chest_normal)
phyBody[phyCnt] = love.physics.newBody(physicWorld, mx, my, "dynamic")
phyShape[phyCnt] = love.physics.newRectangleShape(0, 0, 32, 24)
phyFixture[phyCnt] = love.physics.newFixture(phyBody[phyCnt], phyShape[phyCnt])
phyFixture[phyCnt]:setRestitution(0.5)
end
elseif k == "3" then elseif k == "3" then
-- add image -- add image
local r = lightWorld.getBodyCount() % #material
phyCnt = phyCnt + 1 phyCnt = phyCnt + 1
phyLight[phyCnt] = lightWorld.newImage(chest, mx, my, 32, 24, 16, 0) phyLight[phyCnt] = lightWorld.newImage(ape, mx, my, 160, 128, 80, 64)
phyLight[phyCnt].setNormalMap(chest_normal) phyLight[phyCnt].setNormalMap(ape_normal)
if r == 3 then
phyLight[phyCnt].setGlowMap(ape_glow)
end
phyLight[phyCnt].setMaterial(material[r + 1])
phyBody[phyCnt] = love.physics.newBody(physicWorld, mx, my, "dynamic") phyBody[phyCnt] = love.physics.newBody(physicWorld, mx, my, "dynamic")
phyShape[phyCnt] = love.physics.newRectangleShape(0, 0, 32, 24) phyShape[phyCnt] = love.physics.newRectangleShape(0, 0, 32, 24)
phyFixture[phyCnt] = love.physics.newFixture(phyBody[phyCnt], phyShape[phyCnt]) phyFixture[phyCnt] = love.physics.newFixture(phyBody[phyCnt], phyShape[phyCnt])
phyFixture[phyCnt]:setRestitution(0.5) phyFixture[phyCnt]:setRestitution(0.5)
phyLight[phyCnt].setShadowType("image", 0, -16, 0.0)
elseif k == "4" then elseif k == "4" then
-- add glow image -- add glow image
local r = lightWorld.getBodyCount() % 5 local r = lightWorld.getBodyCount() % 5

10
shader/material.glsl Normal file
View File

@ -0,0 +1,10 @@
extern Image material;
vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
vec4 normal = Texel(texture, texture_coords);
if(normal.a == 1.0) {
return Texel(material, vec2(normal.x, normal.y));
} else {
return vec4(0.0);
}
}

View File

@ -25,7 +25,7 @@ vec4 effect(vec4 color, Image texture, vec2 texture_coords, vec2 pixel_coords) {
} }
} }
vec3 normal = vec3(pixelColor.r, 1 - pixelColor.g, pixelColor.b); vec3 normal = pixelColor.rgb;
float dist = distance(lightPosition, vec3(pixel_coords, normal.b)); float dist = distance(lightPosition, vec3(pixel_coords, normal.b));
if(dist < lightRange) { if(dist < lightRange) {

50
shader/normal_invert.glsl Normal file
View File

@ -0,0 +1,50 @@
#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);
}
}