用 Love2D 實現法線貼圖的例程(到最新版本 0.10.1)

用 Love2D 實現法線貼圖的例程(到最新版本 0.10.1)

概述

通常來講, 複雜的光照模型會被用在 3D 遊戲中, 以產生逼真的效果, 不過也有些開發者研究出一些代碼能夠在 2D 遊戲中使用這些光照模型, 這裏就有兩個在 2D 場景中使用法線貼圖的 Love2D 例程, 不過是前幾年寫的, 用的是 Love2D 的舊版本, 到了今天最新版本的 Love2D 的不少函數都發生了變化, 本文的目標就是修改這些函數到最新的 Love2D 版本 0.10.1.php

例程1

這是一個用來演示 2D 場景下使用光照模型的例程, 原始下載連接 PixelArtCelShading.lovecanvas

對 .love 文件解包

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, 就能夠雙擊運行這個文件.

例程2

這是另外一個用來演示 2D 場景下使用光照模型的例程, 原始下載連接 PixelCelShadingAmbientOcclusion2.love

對 .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 文件, 雙擊運行正常.

參考

Pixel art with GLSL cel shade lighting concept

相關文章
相關標籤/搜索