[Nori]番外-简单纹理映射
番外会记录一下个人拿nori扩展或者修改的一些特性,不保证正确性,如果有问题请各位大佬指出来,我会非常开心 :)
(没想到吧,除了nori本体的作业,还有会番外篇
啊对了,这里要特地说一下,nori本体是个C++工程,但是因为个人实在不想写C++,就拿C#复刻了一遍nori,基本一模一样,API都一样。不出意外的话,以后文章基本都是以C#为主。(想复刻回C++应该也比较简单吧(大概))
放一下C#版本的repo(顺便求个star):https://github.com/ksgfk/Pursuit
这是nori番外篇的第一篇文章。我们先来实现一个相对简单,而且效果爆炸的功能
纹理映射
这里有很多部分是跟着Ray Tracing: The Next Week走的
关于什么是纹理,GAMES101第9课已经为我们解释的非常清楚了。像是OpenGL这类图像API支持二维,三维的纹理。不过这里呢我们为了实现简单(挖坑),就只实现二维纹理了。以下说的纹理都是二维纹理。
众所周知,纹理也有坐标系,横轴是u纵轴是v,称为纹理坐标,范围0到1。一般来说坐标原点默认是左下角(0, 0),右上角在(1, 1)。
所以我们只要获取到uv坐标,就可以对纹理进行采样了
一般来说,在建模软件里导出模型时,会同时导出模型的纹理坐标
我们只需要根据光线与三角形相交时的重心坐标,对模型自带的纹理坐标进行插值,就可以得到需要的uv了,和法线插值是一个道理
首先在Common/Intersection.cs
里面添加一个uv字段(nori的Intersection声明在mesh.h
里面)
1 |
|
然后在Common/Mesh.cs
的GetIntersectionInfo
方法里照着法线插值的代码CV一份改一下变成纹理坐标插值(nori原版的相交信息计算都在accel.cpp里面,不太方便,个人觉得这些可以抽象出来交给图元计算,为以后更多图元类型做准备)
1 |
|
别忘了uv坐标是要在BSDF里使用的,我们在BsdfQueryRecord
里也新增一个uv字段,并且在各个积分器里填充
接下来设计纹理类。众所周知,一张贴图的RGB通道不一定都用来保存数据,像是PBR里面metallic,roughness纹理只有R通道保存了数据。也就是说采样的返回值可能有许多类型。我们可以使用泛型(C++模板一样的233)
Common/ITexture.cs
1 |
|
实现一个最简单的纯色纹理。
Common/ConstantTexture.cs
1 |
|
The Next Week介绍了一种程序化纹理,看上去像是国际象棋棋盘。以前在shader抄过一个效果类似的…但是忘记出处在哪了…具体实现可以看Common/ChessboardTexture.cs
,这里就不放代码了
接下来是从其他地方加载贴图作为纹理。C++可以用stb_image之类的库。C#加载纹理可以使用Magick.NET。巨硬文档不推荐使用System.Drawing
具体怎么加载就不写了,就算有库辅助还是有很多要注意的…总之,最终我们拿到了一个贴图Common/ImageTexture.cs
。直接对它采样就可以了。
1 |
|
嗯,既然涉及到采样,那必然会出现失真现象。为了解决这种问题可以使用双线性插值,mipmap等一系列采样方法。不过这篇是简单纹理采样,就先不深入这些方法吧(主要是还不会233)
接下来就是去各种BSDF里,把可以用纹理的参数替换掉,这是个体力活。
在搞定纹理加载流程,搭建完测试场景后,首先来试一下Diffuse材质的纹理采样效果吧。我把GAMES202的202娘直接搬过来了,启动!
画面质量直接起飞
再来几张结果