通常来讲, 复杂的光照模型会被用在 3D
游戏中, 以产生逼真的效果, 不过也有些开发者研究出一些代码能够在 2D
游戏中使用这些光照模型, 这里就有两个在 2D
场景中使用法线贴图的 Love2D
例程, 不过是前几年写的, 用的是 Love2D
的旧版本, 到了今天最新版本的 Love2D
的不少函数都发生了变化, 本文的目标就是修改这些函数到最新的 Love2D
版本 0.10.1
.php
这是一个用来演示 2D
场景下使用光照模型的例程, 原始下载连接 PixelArtCelShading.lovecanvas
在 OSX
下很简单, 先新建一个目录 shader1
, 接着把 PixelArtCelShading.love
文件拷贝进去, 而后执行 unzip
命令, 就能够获得这个 love2d
项目的所有源文件了, 由于咱们有两个例程, 因此还要新建一个目录 shader2
, 把 PixelCelShadingAmbientOcclusion2.love
拷贝进去, 以下:dom
Air:lua admin$ mv PixelCelShadingAmbientOcclusion2.love ./shader2 Air:lua admin$ cd shader2 Air:shader2 admin$ ls PixelCelShadingAmbientOcclusion2.love Air:shader2 admin$ unzip ./ PixelCelShadingAmbientOcclusion2.love unzip: cannot find or open ./, ./.zip or ./.ZIP. Air:shader2 admin$ unzip ./PixelCelShadingAmbientOcclusion2.love Archive: ./PixelCelShadingAmbientOcclusion2.love inflating: globe.png inflating: main.lua extracting: pithos.png inflating: pixel_font.png inflating: shader.glsl Air:shader2 admin$ ls PixelCelShadingAmbientOcclusion2.love main.lua pixel_font.png globe.png pithos.png shader.glsl Air:shader2 admin$
用 love
命令加载, 出现了以下错误:ide
Air:shader2 admin$ love ../shader1 Error: main.lua:25: attempt to call field 'setDefaultImageFilter' (a nil value) stack traceback: main.lua:25: in function 'load' [string "boot.lua"]:439: in function <[string "boot.lua"]:435> [C]: in function 'xpcall' Air:shader2 admin$ love ../shader1 Error: main.lua:31: attempt to call field 'newPixelEffect' (a nil value) stack traceback: main.lua:31: in function 'load' [string "boot.lua"]:439: in function <[string "boot.lua"]:435> [C]: in function 'xpcall' Air:shader2 admin$ love ../shader1 Error: main.lua:50: attempt to call method 'clear' (a nil value) stack traceback: main.lua:50: in function 'draw' [string "boot.lua"]:467: in function <[string "boot.lua"]:435> [C]: in function 'xpcall' Air:shader2 admin$
修改方法也很简单, 打开 Love2D官网Wiki文档, 查看 love.graphics
模块的函数 setDefaultImageFilter
, 发如今版本 0.10.0
以后就更名为 setDefaultFilter
了, 后面的 newPixelEffect
也被改成 newShader``, 顺手把 setPixelEffect
也改为 setShader
.函数
关于 clear()
方法稍微不一样, 由于它是 Canvas
对象的一个方法, 查询 Canvas
, 发现它的 clear()
方法被 love.graphics.clear()
取代了, 直接改过去, 发现不起做用, 会出现不少拖影, 以下图:lua
说明没起做用, 再仔细阅读一遍文档, 发现要跟 love.graphics.setCanvas(fb)
配合使用, 也就是说要把这条清除语句放在 love.graphics.setCanvas(fb)
语句后面, 修改顺序为:rest
G.setCanvas(fb) G.clear(0,0,0,0)
果真起做用了, 拖影被消掉了, 以下图:code
修改后的 main.lua
文件代码以下:orm
local function captionf (...) G.setCaption(string.format(...)) end local function distance (x1, y1, x2, y2) return ((x1 - x2)^2 + (y1 - y2)^2)^0.5 end local sz = 3 local z = 30 local function update_light_vector () local x, y = love.mouse.getPosition() y = 600 - y -- glsl works from bottom left rather than top left x = x/sz y = y/sz mouse = {x=x, y=600/sz-y} effect:send("light_vec", {x, y, z}) end function love.load () G = love.graphics G.setDefaultFilter("nearest", "nearest") G.setBackgroundColor(35, 30, 65) stump = G.newImage "treestump.png" stump_lines = G.newImage "treestump_lines.png" stump_diffuse = G.newImage "treestump_diffuse.png" globe = G.newImage "globe.png" effect = G.newShader "gooch.glsl" G.setShader(effect) update_light_vector() fb = G.newCanvas(800/sz, 600/sz) fb:setFilter("nearest", "nearest") effect:send("diffuse", stump_diffuse) end time = 0 function love.update (dt) update_light_vector() time = time+dt z = z + math.cos(time)/3 end local r = math.random function love.draw () G.setColor(255, 255, 255, 255) G.setCanvas(fb) G.clear(0,0,0,0) math.randomseed(2) G.setShader(effect) for x = 20, (800-34)/sz, 34 do for y = 20, (600-34)/sz, 34 do if r() > 0.7 then G.draw(stump, x, y, 0, 1, 1, 16, 16) G.setShader() local q = 0.3 G.setColor(145*q, 75*q, 39*q) G.draw(stump_lines, x, y, 0, 1, 1, 16, 16) G.setShader(effect) end end end G.setShader() G.setColor(255, 255, 255) G.draw(globe, mouse.x, mouse.y-z, 0, 1, 1, 8, 8) G.setCanvas() G.draw(fb, 0, 0, 0, sz, sz) end
若是想打包成 .love
的形式, 以便发布, 能够用命令 zip -0 -r -X -q
, 操做纪录以下:对象
Air:lua admin$ cd shader1 Air:shader1 admin$ zip -0 -r -X -q ../shader1.love ./* Air:shader1 admin$ cd .. Air:lua admin$ ls -al total 152 drwxr-xr-x 18 admin staff 612 7 5 15:13 . drwxr-xr-x 15 admin staff 510 7 4 09:55 .. -rw-r--r--@ 1 admin staff 12292 7 5 14:41 .DS_Store drwxr-xr-x 6 admin staff 204 7 1 21:11 2048 -rw-r--r--@ 1 admin staff 7691 7 5 10:05 Pixel1 -rw-r--r--@ 1 admin staff 7691 9 27 2012 PixelArtCelShading.love -rw-r--r--@ 1 admin staff 10471 9 27 2012 PixelCelShadingAmbientOcclusion2.love drwxr-xr-x 6 admin staff 204 7 4 00:01 c-test drwxr-xr-x 5 admin staff 170 7 1 21:12 love drwxr-xr-x 6 admin staff 204 7 1 21:06 particle drwxr-xr-x 8 admin staff 272 7 5 15:05 shader1 -rw-r--r-- 1 admin staff 10095 7 5 15:13 shader1.love drwxr-xr-x 7 admin staff 238 7 5 15:04 shader2 -rw-r--r-- 1 admin staff 2128 6 29 00:23 spider.lua -rw-r--r-- 1 admin staff 884 6 18 16:31 test1.lua -rw-r--r-- 1 admin staff 1568 6 18 16:31 test2.lua -rw-r--r-- 1 admin staff 1769 6 18 16:32 test3.lua -rw-r--r-- 1 admin staff 279 6 19 10:32 timeProfile.lua Air:lua admin$
咱们看到新生成了一个名为 shader1.love
的文件, 只要你的电脑上安装了 Love2D
, 就能够双击运行这个文件.
这是另外一个用来演示 2D
场景下使用光照模型的例程, 原始下载连接 PixelCelShadingAmbientOcclusion2.love
整个操做过程跟第一个例程同样,
Air:lua admin$ cd shader2 Air:shader2 admin$ love ../shader2 Error: main.lua:12: attempt to call field 'setCaption' (a nil value) stack traceback: main.lua:12: in function 'load' [string "boot.lua"]:439: in function <[string "boot.lua"]:435> [C]: in function 'xpcall' Air:shader2 admin$ love ../shader2 Error: main.lua:75: attempt to call field 'drawq' (a nil value) stack traceback: main.lua:75: in function 'draw' main.lua:59: in function 'draw' [string "boot.lua"]:467: in function <[string "boot.lua"]:435> [C]: in function 'xpcall' Air:shader2 admin$ love ../shader2 Air:shader2 admin$
依次解决错误函数, 跟第一个例程的错误大同小异, 相同的地方就很少说了, 说两个新错误: G.setCaption
改成 love.window.setTitle
, G.drawq
改成 G.draw
.
修改后的 main.lua
文件代码以下:
s = [=[ ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,:;'"?/\[](){}<>1234567890!@#$%^&*_-+=~`| ]=] s = s.."\t" local G, W, H local sz = 2 function love.load () G = love.graphics W = G.getWidth H = G.getHeight love.window.setTitle "Ambient occlusion test" G.setBackgroundColor(35, 30, 65) ao_toggle = 1 -- ao_toggle starts on z = 30 time = 0 font_img = G.newImage "pixel_font.png" font = G.newImageFont(font_img, s) G.setFont(font) G.setDefaultFilter("nearest", "nearest") globe = G.newImage "globe.png" img = G.newImage "pithos.png" diffuse = G.newQuad(0, 0, 32, 43, 96, 43) canvas = G.newCanvas(W()/sz, H()/sz) canvas:setFilter("nearest", "nearest") effect = G.newShader "shader.glsl" effect:send("ao_toggle", ao_toggle) end function love.update (dt) time = time + dt z = z + math.cos(time)/3 local x, y = love.mouse.getPosition() x = x/sz y = y/sz mouse = {x=x, y=y} y = H()/sz - y effect:send("light_pos", {x, y, z}) end function love.mousepressed () ao_toggle = (ao_toggle + 1)%2 effect:send("ao_toggle", ao_toggle) end function love.draw () G.setCanvas(canvas) G.clear(0,0,0,0) draw() G.setCanvas() G.setShader() G.draw(canvas, 0, 0, 0, sz, sz) end function printf (...) G.print(string.format(...), 20, 10) end function draw () G.setShader() G.setColor(220, 190, 0) printf("Click toggles ambient occlusion.\nCurrently: %s.", ao_toggle == 1 and "on" or "off") G.setShader(effect) G.setColor(255, 255, 255) G.draw(img, diffuse, W()/sz/2 - 34, H()/sz/2 - 18, 0, 1, 1, 16, 27) G.draw(img, diffuse, W()/sz/2 + 34, H()/sz/2 + 18, 0, 1, 1, 16, 27) G.setShader() G.draw(globe, mouse.x, mouse.y-z, 0, 1, 1, 9, 9) end
运行截图以下:
Air:shader2 admin$ zip -0 -r -X -q ../shader2.love ./* Air:shader2 admin$ cd .. Air:lua admin$ ls -al total 184 drwxr-xr-x 19 admin staff 646 7 5 15:35 . drwxr-xr-x 15 admin staff 510 7 4 09:55 .. -rw-r--r--@ 1 admin staff 12292 7 5 14:41 .DS_Store drwxr-xr-x 6 admin staff 204 7 1 21:11 2048 -rw-r--r--@ 1 admin staff 7691 7 5 10:05 Pixel1 -rw-r--r--@ 1 admin staff 7691 9 27 2012 PixelArtCelShading.love -rw-r--r--@ 1 admin staff 10471 9 27 2012 PixelCelShadingAmbientOcclusion2.love drwxr-xr-x 6 admin staff 204 7 4 00:01 c-test drwxr-xr-x 5 admin staff 170 7 1 21:12 love drwxr-xr-x 6 admin staff 204 7 1 21:06 particle drwxr-xr-x 8 admin staff 272 7 5 15:21 shader1 -rw-r--r-- 1 admin staff 10095 7 5 15:13 shader1.love drwxr-xr-x 7 admin staff 238 7 5 15:31 shader2 -rw-r--r-- 1 admin staff 13104 7 5 15:35 shader2.love -rw-r--r-- 1 admin staff 2128 6 29 00:23 spider.lua -rw-r--r-- 1 admin staff 884 6 18 16:31 test1.lua -rw-r--r-- 1 admin staff 1568 6 18 16:31 test2.lua -rw-r--r-- 1 admin staff 1769 6 18 16:32 test3.lua -rw-r--r-- 1 admin staff 279 6 19 10:32 timeProfile.lua Air:lua admin$
成功生成 shader2.love
文件, 双击运行正常.