用 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

相关文章
相关标签/搜索