EtherTK 解构《武士零》 - 蒙版光照

其实与光照的死磕在很久之前便已经开始了,在开发第一代使用 OpenGL 可编程渲染管线的引擎时,便实现了一套简单的 2D 光照算法,那时候更多的还是借鉴自 LearnOpenGL 的 3D 光照思路,但是在对《武士零》的研究过程中,发现如果仅制作 2D 游戏的话,使用源自上个游戏技术世代的蒙版贴图,配合现代化的渲染管线,可以更简明地实现更符合艺术效果的光照效果(至少在像素风格的 2D 游戏看来是这样),本文将对该过程的探索过程进行阐述。

本文及相关程序所使用的实现依然为 EtherTk,不过由于需要更精确自由的渲染逻辑,所以底层实现由 SDL Renderer 变更为了 OpenGL。

基于公式计算的光照

此节内容更多参考自:投光物 - LearnOpenGL CN

对于游戏中的光照公式可以简化为:物体受光 = 环境光 + 聚光灯(点光源可以看作是外切角为 360° 的聚光灯),而整个世界是一片漆黑没有任何光照的,环境光作为让场景中各物体雨露均沾接受光照的光源,为物体提供了最基础的光照贡献——简单理解,在不使用光照进行渲染的场景中,不经任何处理绘制的物体纹理贴图相当于被赋予了环境光强度为 1 的白色光照;而聚光灯的技术核心,更多的是使用统一的公式和参数描述指向性光源的外形,从而计算得到世界中受此影响的像素片段。

对于聚光灯的处理,首先要计算的便是处理其径向衰减,逆向思考一下,聚光灯也可以看做是指向性的点光源,所以在处理径向衰减的思路和点光源完全相同。虽然我向来不喜欢将晦涩的数学公式搬上台面,但是无奈光照这种基于物理和经验的模拟,很难找到除去公式之外的第二种表述方式——当然,这样方便了我们,即使不能完全理解,也是可以直接套用公式实现不错的效果:
径向衰减公式

阅读更多

EtherTK 解构《武士零》 - 动态文本

动态文本在很多拥有文字故事讲述的游戏中都各有体现,从拥有相当文本体量的 Galgame 类型游戏的经典打字机特效,到《武士零》《传说之下》这类融合了更多文字动态效果的游戏,动态文本在提升交互体验、增加画面质感、表达作者情绪 等方面均发挥了不小的作用。

考虑到《武士零》这款游戏对于团队在下一阶段的作品很有参考和学习的价值,于是便开始尝试从程序功能角度去解构这一部优秀的作品,动态文本作为相对简单的功能,便被优先提上了日程;在 EtherTk 的基础上,实现了相对丰富的动画文本效果,并提供了类似 Markdown 的轻量标记语法,使得策划同学可以在文案阶段对游戏内的文本动态效果进行设计,从而减轻引擎内工作量。

EtherTK 是我个人在旧有开源项目 EtherEngine 基础之上重构实现的一套工具集,核心理念便是 All In One Toolkit,用来方便使用 Lua 脚本快速开发和算法功能等验证;虽然 EtherTk 源代码现阶段仍未公开,但在本功能的实现过程中主要使用的 Graphic 模块主要是对 SDL Renderer 渲染管线相关功能的 1:1 封装,只要对 SDL2 全家桶的使用较为熟悉,便完全可以理解动态文本实现的相关思路。

下面对该功能的实现过程进行简要描述(先放一张游戏内的效果)。

《武士零》游戏内文本效果

阅读更多

控制台字符游戏开发库

控制台字符画可谓是程序员永远的浪漫~

前不久有朋友问我:如何实现控制台的飞机大战游戏,想来想去,控制台游戏我玩过,飞机大战我也写过,逻辑也并不复杂,但是控制台飞机大战还真没有做过,控制台没有方便的图形API,如何实现简单高效地绘图恐怕是最大的问题;
转念一想,类比图形API,控制台下每一个字符都可以被视作一个单独的像素,图片便是字符串数组,而二维的字符数组就可以充当渲染缓冲区,调用printf进行输出的操作就可以当成是将渲染缓冲区的数据拷贝至显示器的操作,这样来看,完全可以从头设计一套简单的控制台图形API来方便将游戏数据显示到屏幕上;

阅读更多

16行代码能做什么?写一个随机图片服务器!

在经过一番旷日持久的苦战后,自己的开源游戏引擎 EtherEngine 终于迎来了 4.x 版本
更新内容
本次更新除了增加了更多系统交互 API,优化了接口调用方式和二进制数据传参缓冲区之外,更重要的是对 Network 模块 进行了十分重要的更新,让 EtherEngine 的网络模块摇身一变变成了可以与 Python 的 Requests 库 / Nodejs 的 Express 框架 功能相媲美的工具了!

EtherEngine 虽然被更名为了 EtherAPI ,但是我更习惯叫它原来的名字(因为这样更装x),它的设计思想是尽可能地简单、易上手并且易于快速开发,所以这次网络模块的更新也恰恰印证了它的这些特性:

16行代码能够做点啥?
—— 写一个随机图片服务器足够!

阅读更多

C++ 分割 HTTP 链接为 主机名、路由和参数

前几日在更新自己的开源游戏引擎 EtherEngine 时编写了使用 C++ 对 HTTP/HTTPS 链接进行分割的算法,分享一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
ETHER_API splitLink(lua_State* L)
{
string link = luaL_checkstring(L, 1), domain, route, param;

if (!link.empty())
{
link.erase(0, link.find_first_not_of(" "));
link.erase(link.find_last_not_of(" ") + 1);
}

domain = link.substr(0, 5) == "http:" || link.substr(0, 6) == "https:" ?
link.substr(0, link.find_first_of("/", link.find_first_of("/") + 3))
: link.find_first_of("/") == string::npos ? link : link.substr(0, link.find_first_of("/"));

size_t index_quemark = link.find_first_of("?");

index_quemark == string::npos ?
(param = "", route = domain.size() == link.size() ? "/" : link.substr(domain.size()))
: (param = link.substr(index_quemark + 1), route = link.substr(domain.size(), index_quemark - domain.size()));

lua_pushstring(L, domain.c_str());
lua_pushstring(L, route.c_str());
lua_pushstring(L, param.c_str());

return 3;
}

由于上述代码是与 Lua 语言进行交互的 API,所以在下面给出通用的函数封装:

阅读更多