通常來講, 複雜的光照模型會被用在 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
文件, 雙擊運行正常.