从零开始手敲次世代游戏引擎(三十三)

本篇我们来实现场景图的计算。
首先我们需要重构一下我们的SceneNode和SceneObject,让我们的GraphicsManager能够比较方便地获取场景几何体的空间位置。
相关的调整代码在article_33分支的 commit baefd06a 当中。
执行的效果如下:
 
 
 
 
视频封面

上传视频封面

 
 
 
 
可以看到几何体不再重合在一起了。但是几何体的位置与我们在Blender里面设置的不同。这是因为我们没有采用Blender当中设置的相机进行渲染。(Blender采用的是右手坐标系且Z轴垂直向上)
于是接下来我们进行相机的导入,并使用0号相机(第一个相机)输出画面。相关的代码在article_33分支当中通过 commit c6b39c2ab提交。执行的效果如下:
 
 
视频封面

上传视频封面

 
 
 
 
在执行这一步的时候,我遇到的主要的难关是Blender所导出的相机的矩阵是相机本身的平移与旋转矩阵(位置矩阵)。这个矩阵与View Matrix(就是将场景物体从世界坐标系变换到相机坐标系的矩阵)的关系是求逆的关系。因此我需要在我们之前写的数学库(GeomMath)当中添加矩阵求逆的函数。(参考引用*1)
在使用ispc进行矩阵求逆的函数编写的时候,遇到了下面这么一个问题:
在上面这段代码当中,foreach_tiled当中计算的inv[]矩阵,在foreach_tiled循环体当中看的时候(打印输出log)是正确的,但是到了下一个foreach当中,内容就变成随机的了。调查了一段时间之后,发现是因为inv[]矩阵未被申明为uniform类型。也就是说,按照上面这个写法,其实每个并行计算的instance都会有一个inv[16],其中只有一个数组成员会被赋值,其他的都是随机内容(未初始化)。而后面的foreach因为gang(就是单次并行运算所包括的instance数量)与前面的不同,这个inv似乎会重新分配,内容就更加不可预测了。
解决的方法很简单,因为我们实际是想让各个并行计算线程共享inv[],每个线程计算填写16个值当中的一个,所以只要把inv[]申明为uniform就可以了。
当然,如果觉得并列化计算不好理解或者不想用ispc,完全可以用纯粹的c/c++编写。方法参照(参考引用*2)
在编写数学相关的函数的时候,我们往往需要验证结果是否正确。这可以通过对比外部计算工具的结果来实现。矩阵相关的常用的有matlab,但是这个是个商业软件。Wolfram Alpha(参考引用*5)是一个强大的计算网站,如果你知道该怎么用英文描述你的数学问题,那么它能够帮你做完差不多所有的高数题,包括具体的解题步骤 ( ‘ω’ )
接下来是导入光照。我们这里首先导入经典的Phong全局照明模型。(参考引用*4)
 
图片来源:Wikipedia(参考引用*4)
 
为了实现Phong光照,我们首先需要从Blender导出的OGEX当中导入光照参数,然后将这个参数传递给Shader。然后我们在Shader当中需要根据Phong模型的公式进行计算。commit f3f66a6加入了Phong的Defuse(漫反射)计算部分,而commit a3844920加入Phong的Specular(高光)计算部分。调整后的PS Shader代码如下:(注意VS Shader也有小范围修改,主要是导出未经透视变化的摄像机坐标系当中的顶点位置,用来在PS Shader当中确定入射光和反射光方向)
下图是只有漫反射的效果:
 
 
视频封面

上传视频封面

 
 
 
 
下图是加了高光的效果(高光因子0.01)
 
视频封面

上传视频封面

 
 
 
 
(高光因子0.1)
 
视频封面

上传视频封面

 
 
 
 
高光因子1.0
 
 
视频封面

上传视频封面

 
 
 
 
可以看到有比较强烈的金属质感了。
漫反射系数0.5高光0.01
 
 
视频封面

上传视频封面

 
 
 
 
比较强烈的橡胶质感。
对比题图(用Blender渲染),主要少了阴影,以及光的衰减。这是我们接下来的课题。
(注:所有截屏为macOS版,但是Windows/Linux版能够输出同样画面)
 
参考引用:

发表评论

Fill in your details below or click an icon to log in:

WordPress.com 徽标

您正在使用您的 WordPress.com 账号评论。 注销 /  更改 )

Facebook photo

您正在使用您的 Facebook 账号评论。 注销 /  更改 )

Connecting to %s

%d 博主赞过: