用 Love2D 实现法线贴图的例程(到最新版本 0.10.1)
用 Love2D 实现法线贴图的例程(到最新版本 0.10.1)
概述
一般来说, 复杂的光照模型会被用在 3D
游戏中, 以产生逼真的效果, 不过也有些开发者研究出一些代码可以在 2D
游戏中使用这些光照模型, 这里就有两个在 2D
场景中使用法线贴图的 Love2D
例程, 不过是前几年写的, 用的是 Love2D
的旧版本, 到了今天最新版本的 Love2D
的很多函数都发生了变化, 本文的目标就是修改这些函数到最新的 Love2D
版本 0.10.1
.
例程1
这是一个用来演示 2D
场景下使用光照模型的例程, 原始下载链接 PixelArtCelShading.love
对 .love 文件解包
在 OSX
下很简单, 先新建一个目录 shader1
, 接着把 PixelArtCelShading.love
文件拷贝进去, 然后执行 unzip
命令, 就可以得到这个 love2d
项目的全部源文件了, 因为我们有两个例程, 所以还要新建一个目录 shader2
, 把 PixelCelShadingAmbientOcclusion2.love
拷贝进去, 如下:
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
命令加载, 出现了如下错误:
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()
取代了, 直接改过去, 发现不起作用, 会出现很多拖影, 如下图:
说明没起作用, 再仔细阅读一遍文档, 发现要跟 love.graphics.setCanvas(fb)
配合使用, 也就是说要把这条清除语句放在 love.graphics.setCanvas(fb)
语句后面, 修改顺序为:
G.setCanvas(fb)
G.clear(0,0,0,0)
果然起作用了, 拖影被消掉了, 如下图:
更新后代码
修改后的 main.lua
文件代码如下:
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
用 Love2D 实现法线贴图的例程(到最新版本 0.10.1)的更多相关文章
- 法线贴图——Normal Mapping
对于不曾学过.用过法线贴图的人来说,提到法线贴图,经常会提到的问题是什么是法线贴图?法线贴图用于解决什么问题?法线贴图的原理是什么?本文将就这三个问题阐述本人的一些见解,各位不喜勿喷!!! 谈到法线贴 ...
- 【Unity Shader】六、使用法线贴图(Normal Map)的Shader
学习资料: http://www.sikiedu.com/course/37/task/456/show# http://www.sikiedu.com/course/37/task/458/show ...
- ZBrush功能特性之法线贴图
ZMapper是ZBrush2.0推出的免费法线贴图插件.使用ZBrush革命性的多级别精度和新型的照明-快速光线跟踪器,ZMapper可以在几秒内产生适用于任何游戏引擎的法线贴图,不过3.5版本以后 ...
- 翻译:非常详细易懂的法线贴图(Normal Mapping)
翻译:非常详细易懂的法线贴图(Normal Mapping) 本文翻译自: Shaders » Lesson 6: Normal Mapping 作者: Matt DesLauriers 译者: Fr ...
- 一键批量添加材质的法线贴图-unity插件
有时候材质做完后需要更改贴图,或者增加贴图,数量少的时候可以一张张添加和修改,数量多的时候就只能代码生成了.原理是通过名字的关联:主贴图和法线贴图大多数只是后缀的不同上,如果不是那是美术规范没做好啊, ...
- Esfog_UnityShader教程_NormalMap法线贴图
咳咳,好久没有更新了,一来是这段时间很忙很忙,再来就是自己有些懒了,这个要不得啊,赶紧补上.在前面我们已经介绍过了漫反射和镜面反射,这两个是基本的光照类型,仅仅依靠它们就想制作出精美的效果是远远不够的 ...
- Unity3d《Shader篇》法线贴图
效果图 贴图 法线贴图 //代码 Shader "Custom/NormalMap" { Properties { _MainTex ("Texture", 2 ...
- Unity3D ShaderLab法线贴图
Unity3D ShaderLab法线贴图 说到法线贴图,应该算是我们最常使用的一种增强视觉效果的贴图.将法线贴图的各个像素点座位模型的法线,这样我们的光照可以模拟出高分辨率的效果, 同时也保持较低的 ...
- 【Unity Shaders】学习笔记——SurfaceShader(七)法线贴图
[Unity Shaders]学习笔记——SurfaceShader(七)法线贴图 转载请注明出处:http://www.cnblogs.com/-867259206/p/5627565.html 写 ...
随机推荐
- 【Coursera】经验风险最小化
一.经验风险最小化 1.有限假设类情形 对于Chernoff bound 不等式,最直观的解释就是利用高斯分布的图象.而且这个结论和中心极限定律没有关系,当m为任意值时Chernoff bound均成 ...
- SQL之联合查询学习笔记
定义: 联合查询可合并多个相似的选择查询的结果集.等同于将一个表追加到另一个表,从而实现将两个表的查询组合到一起,使用谓词为UNION或UNION ALL. 语法格式 UNION 可以将两个或两个以上 ...
- 使用JProfiler做性能分析过程
供自己记录一下,也分享给大家使用JProfiler的过程(感谢教我使用这个工具的大佬),整个博客比较粗糙,希望对大家有帮助 1.首先安装好JProfiler,打开eclipse,右键你所要分析的项目, ...
- thinkphp学习2-控制器
1.定义控制器 一般来说,ThinkPHP的控制器是一个类,而操作则是控制器类的一个公共方法. 控制器通常需要继承系统的Controller类或者其子类,例如,下面定义了一个 \Home\Contro ...
- Prism6下的MEF:添加Logger
上篇已经简单的构建了一个Prism的程序,现在我们需要添加一个Logger,Prism本身自带一个功能简单的TextLogger,但是我们希望能用.Net常用的Log4net.所以我们需要重载掉Boo ...
- L2 L3 L4
第二层交换机,是根据第二层数据链路层的MAC地址和通过站表选择路由来完成端到端的数据交换的.因为站表的建立与维护是由交换机自动完成,而路由器又是属于第三层设备,其寻址过程是根据IP地址寻址和通过路由表 ...
- Java8 新特性Stream 的学习和使用方法
流(Stream) 流是java 8 中新引入的特性,用来处理集合中的数据,Stream 是一个来自数据源的元素队列并支持聚合操作. Java 中 Stream 不会存储元素. 数据源 流的来源. 可 ...
- bzoj1027【JSOI2007】合金
题目描述 某公司加工一种由铁.铝.锡组成的合金.他们的工作很简单.首先进口一些铁铝锡合金原材料,不同种类的原材料中铁铝锡的比重不同.然后,将每种原材料取出一定量,经过融解.混合,得到新的合金.新的合金 ...
- BZOJ 3438 小M的作物 & BZOJ 1877 [SDOI2009]晨跑
我由衷地为我的朋友高兴.哈哈,yian,当你nick name破百上千时,再打“蒟蒻”就会被打的. 好的,说正事吧.请注意,这还是题解.但我发现,网络流实在是太套路了(怪不得这两年几乎销声匿迹).我们 ...
- codeforces div1 & div2 参与人员分数统计
Analysis helps to see the nature of things.