Archive

Archive for August, 2020

OpenGL / DirectX 如何在知道顶点的情况下得到像素位置?

August 13th, 2020 No comments

DirectX 和 OpenGL 是如何得知对应屏幕空间对应的纹理坐标和顶点色的呢?一句话回答就是光栅化。

具体一点,实现的话,一般有两种方法:

Edge Walking

基本上所有基于 CPU 的软件渲染器都使用 Edge Walking 进行求解,因为计算量少,但是逻辑又相对复杂一点,适合 CPU 计算。具体做法分为三个阶段:

第一阶段:拆分三角形,将一个三角形拆分成上下两个平底梯形(或者一个),每个梯形由左右两条边和上下两条水平线(上底,下底)表示。

普通三角形可以拆分成上下两个平底三角形,不管是上面的那一半还是下面的那一半,都可以用一个平底梯形来表示(即上底 y 值 和下底 y 值,以及左右两边的线段),这样再送入统一的逻辑中渲染具体某一个平底梯形。

第二阶段:按行迭代,然后以梯形为单位进行渲染,先从左右两条边开始,一行一行的往下迭代,每迭代一次,y坐标下移1像素,先根据左右两边线段的端点计算出左右两边线段与水平线 y 的交点:

然后继续插值出左右两边交点的纹理坐标,RGB 值 之类的 varying 型变量,然后进入扫描线绘制阶段。

第三阶段:按像素迭代,有了上面步骤计算出来的一条水平线,以及左右端点的各种 varying 变量的值,那么就进入一个 draw_scanline 的紧凑循环,按点进行插值,相当于 fragment shader 干的事情。

计算 varying 变量插值的时候需要进行透视矫正,根据平面方程和透视投影公式,可以证明屏幕空间内的像素和 1/w 是线性相关的,而三维空间的 x / w, y / w, z / w 和屏幕空间也是线性相关的,也即各个 varying 变量按屏幕空间插值时需要先 / w,然后按照屏幕空间每迭代一个点时再除以最新的(1/w)就可以还原改点的真实 varying 变量值。

这部分可以参考我写的 700 行软件渲染器:

上面是第一种方法。

Edge Equation

这个方法简单粗暴,虽然计算量较大,但是计算方法简洁而单一,适合 GPU 实现,即按照三角形外接矩形(或者屏幕上任意矩形),两层 for 循环迭代每一个一个像素,先走一遍 Edge Equation 判断是否再三角形范围内,如果否的话就跳出,如果是的话,使用插值方式得到各个 varying 变量的值(纹理坐标,RGB顶点色和法线等)。

由于没有像 Edge Walking 一样迭代左右两边的每个像素,所以插值使用了一种“重心坐标”的公式,直接参考三个顶点的位置和当前点重心坐标来插值:(点击 Read more 展开)

Read more…

Categories: 图形编程 Tags:

关于 “帧同步” 说法的历史由来

August 2nd, 2020 No comments

关于游戏同步的话题说的太多了,我是不想再谈了,但是碰到一些含糊和容易引起混淆的地方,必须澄清一下,云风在 2018 年在《lockstep 网络游戏同步方案》中有一段:

首先,我认为把 lockstep 翻译成帧同步,还有与之对应的所谓“状态同步” (我在多次面试中听过这个名词),都是对同步算法的错误理解造成的。把自己所理解的算法牵强附会到已有的在欧美游戏先行者中经过实践的方案上。

最近网易雷火工作室的一篇文章《细谈网络同步在游戏历史中的发展变化》谈到了类似的观点,那么为了避免产生混乱,有必要对 “帧同步”这个说法做一次澄清。

帧同步不是单指某个具体算法,而是范指 “保证每帧(逻辑帧)输入一致” 的一系列算法,传统实现有帧锁定,乐观帧锁定,lockstep,bucket 同步等等,但凡满足“每帧输入一致”的方法皆可以归纳为帧同步类别,至于要不要回滚?服务端要不要跑一套完整逻辑?操作要不要是键盘鼠标?还是高阶命令?客户端要不要像视频播放器一样保证平滑缓存 1-2 帧?或者要不要保证平滑加一层显示对象的坐标插值?这些都是具体优化手段。

我在 2009 年公司应届生培训的《服务端开发培训》课程内,最早开始做同步技术培训:

这个 “帧间同步”喊着喊着就被喊成了“帧同步”,这应届生培训持续了好几年,应该数百人听过这个课程,后面的讲师又接着迭代这个 ppt 接着讲了好几年,听过的应届生们自己摸索后,又写了新的技术分享放到网上,兴许从那时候 “帧同步”和 “状态同步”的说法就流传开了吧。

(点击 Read more 展开)

Read more…

Categories: 游戏开发 Tags:
Wordpress Social Share Plugin powered by Ultimatelysocial