学习笔记26

注意这里的坐标系 是以左下角为原点。

然后关于红色和绿色坐标越大,通道分量的值越大。

cerr - Zucc_zt - 博客园 (cnblogs.com)

这里cerr主要体现在两个地方,一个是没有缓冲的,第二个是绑定了显示器输出。

PPM Viewer (rhodes.edu)

一个关于ppm的在线查看器。这块踩了不少坑,首先一定要保证代码写正确,因为图片的内容格式是有严格的要求的,有一点差错都打不开。

然后这里加上了cerr之后,运行的时候会有上边这俩,类似一个倒计时的效果。

能够实现这一点,是因为他的cerr中,写了一个\r。这个意思是把输出的光标移动到当前行的第一个位置。也就是第一次输出之后,第二次输出,并没有进入下一行,而是重新走到了当前行的第一个位置,那么再输出的时候就会把第一次输出的给盖上了。

所以这样一个类似倒计时的效果。

这里的初值列表,可以是用{}在里面写初值。

这里就注意光线是有俩方向的。

这里要干的事情就是搭建出上边图中的东西。

首先光追主要分为三步:第一计算出ray,从眼睛到像素点。第二,光线发出去之后找到相交点。第三对相交点进行shading计算。

这里首先先把屏幕确定下来,因为之前的256×256两个边一样长,有些时候可能容易混,所以这里选用16:9的

然后就是view port,这里viewport是场景中虚构的一个东西,用来做光追,最后会把他上边的像素计算得到的颜色映射到我们的屏幕上。这里高度为2,宽度遵循比例来。z是-1,这里的坐标系是右手系,摄像机朝向-Z轴。

加入一个球体,关于球体的insection判断是相对简单的。

球心和点之间的向量的模就是两点之间的距离,然后和半径比较。

当然有了一个点,我们有一个关于t表示点的,然后代入式子中,其实能够解出来t,就代表有交点,否则就没有交点。(当然要考虑t的物理意义。)

解t就是二次方程,所以这里我们只需要求delta就好了。

上边是系数相关。

判断完成之后,这里还有一些小的问题,就比如说当我们把00-1小球改到001,其实会看到一样的东西。

这就是缺乏对t实际物体意义的考虑,

考虑实际的shading,我们就需要get到法线,法线这里有一个normalize的问题,方便计算需要normalize。

关于简化。式子上是简化了,但是计算效率上只能说和原来相比没有什么质的变化。

对于它可以巧记一下,就是还是背之前的求根公式,这里就是把之前的公式b换成h,去掉所有的系数,不去负号。

优化完成之后,这里考虑被hit的物体,如果是多个球,如果是多种物体呢?

一旦涉及到多种,基本上就有继承了。

这里多种物体都有着一个必然会做的行为,就是:判断是否相交。

所以这里就可以抽象出一个base class。而且直接是虚基类即可。

然后规范一个接口,这里比我们之前的碰撞相交多了一个范围传递进去,这样可以省去很多的事情。传递进去一个t的范围,

范围之外的就不再考虑了,比如范围是一个大于0的,那么t小于0就不考虑,也就是摄像机后面的物体也就由此排除掉了。

然后参数还有光线,之前的球心半径啥的这里就不用写了,这就是封装成类的好处,因为把这个函数变成了成员函数,那么

类的所有属性直接访问,所以这里就不必作为参数传递了。

这里需要考虑的东西就是,相交之后呢?之前搞的时候是有一个返回值输出的,但是这里具体和谁相交不一定了,所以返回值也不确定

是什么类型的,这里就选择封装一个结构,然后装一些常返回的东西。

这里涉及到了一个法线方向的问题,由于我们求法线是使用两个点的,具体这俩点谁指向谁,这个还真不一定。

之前都是沿着半径指向外面的,但是如果我们来个透明球的折射,光线进入球之后再出去的时候,法线就是朝着内部的。

正确的法线方向应该是始终和ray 的方向against的。

按照上边从内外看的方法,其实就是:光线针对intersection的表面如果是从内往外,就需要是向内的法线,如果是从外往内,那就是向外

的法线。

关于ray是在内还是在外,这里可以和Normal的方向做一个比较,根据dot的正负号就可以确定出来。

注意这里,在之前rasterizer光栅化的管线之下,经常用这个dot做一个背面裁剪的判断。

这里有可能会疑问,用dot来做了光线内外的判断,那啥时候搞这个裁剪判断,这俩不冲突么。

其实关键点在于ray tracing体系下完全没有裁剪这么一说,所有的面都是不需要裁剪的。裁剪了你咋多次弹射追踪啊。

所以这里的dot正好只用来做这个内外的判断。

所以最终的处理方式就是:几何体本身存储向外的法线,然后根据光线的内外来判断法线是否需要反转,并且记录下来。

因为一个shadin point在光线追踪体系下,不只着色一次,可能被光多次照射到,所以只需要计算一次存储起来就好了。

(121条消息) error c2243:"类型转换" 转换存在,但无法访问_sz-lcw的博客-CSDN博客_错误c2243“类型转换”: 从“scriptparserimpl *”到“scriptparser

上边三个,第一个是定义一个子类变量,第二个是将子类变量传递到第二个参数中。第三个是函数原型,第二个形参是父类的引用。

首先这种玩法是可行的,也就是父类的引用指向子类的对象。(此处的父类是虚基类)

主要是问题出在下面,下面的make智能指针的时候,会创建该类型的对象,而这里<>参数传递的是虚基类类型,必然不能创建对象。

所以这里出问题了,而我一直在纠结上边,导致近一个小时才找出来。

首先产生上边的疑问,就是光线和一个物体相交,然后和另外一个物体也相交了。

上边忽略了一个非常重要的点,现在是光线追踪,这一个list的判断都是针对这个像素的。出来之后立马对像素进行着色。

生成随机数,这里主要思路就是生成一个0到1的随机数,然后利用范围映射,把得到的随机数变换到需要的范围。

C++出的一个新玩法。

这里反锯齿的主要逻辑就是MSAA,但是他也并不是严格的MSAA,他是对周围一个随机范围内搞几根光线,把最终得到的结果进行一个

平均。

这里对camera类进行了一个封装,因为camera基本上所有的信息,都是为了一件事:生成ray,所以直接把它所有的属性都包起来

然后对外开放一个生成ray的接口即可。

这里主要说了材质和几何的对应,有的情况可能是一个材质用到多个几何上,有时候可能反过来,还有几何和材质bound的。

这里我们选择separate的。

就是关于漫反射,方向上是randomized,而颜色上是周围环境+自己intrinsic固有去modulate调制出最终的结果。

然后关于这个方向的随机算法有很多,这里有一个lazy hack。

主要思路就是,对于shadin point处有两个与之相切的单位球,这两个一个是再外侧,一个是在内测,我们挑选其中一个和相机处于同

一侧的,然后在球内部随机选择一个点。

先说下宏观思路,我们要算这个p点的颜色,肯定是继续追踪其他光照射到他身上的结果。

也就是说,我们要找出一个实际光的入射方向,现在作为我们往下追踪的方向。

找的方式就是上边提到的,但是还不完整,他在实操的时候,我们能够得到P点位置,加上单位向量法线,可以得到上边的P。

然后我们会利用一个随机数,随机三个-1到1的值,然后和这个p累加就会得到一个在P内部的任意一点(随机为-1到1有可能超出球内部

,所以这里对随机的结果进行检验,如果不行就会重新随机获取一个。)

最核心的部分就来了,就是这里,形成一个递归。

这里的递归少了一个base case。当然也不算少,因为他的base case trace不到任何东西了,就是不会和物体相交了。

但是等到这个basecase ,有些情况可能栈都爆了。

所以说这里给他加了一个base case,也就是准许的递归层数,最多是50层。

其实光线追踪的终点本应该是某个光源,但是这里似乎不是光源。

其实是的,这里最终是关系不和物体相交,那和谁交。这里其实是假设和天空相交。最后递归到basecase返回的颜色其实是采样的

天空的颜色,我们最开始的时候,生成的一张图,它的颜色就是从下面的白变蓝。其实就是和天空颜色类似的。

所以这里最终渲染出来的结果,看上去是很类似天空光照亮的物体。

递归的时候写错了,这里往下递归的应该是当前位置,而这个r的原点是上一次的发出点,这里的位置是存储在rec中的。

效果上很差的。因为都认为是原点发出的,并不是往下递归搞了。

修改之后,执行时间明显变长了。

这次直接干黑了。。。。

发现了world中添加的两个东西的顺序不同。

但是却又发现,其实作者的代码和他的图有点不匹配。

如果是小球渲染在了前面,那么在数组中他就得在后面。

因为代码

写的时候,是从前往后遍历的,其实这里代码有问题,待会再说,先按这个来,那么我们如果把小球放在数组第二个位置,那么

那么交点记录的就是小球的,最后传递出去的record参数也是小球的,所以渲染就是小球的,所以小球在屏幕内的所有部分都

没有被遮挡。

所以如果想要小球在前面就得把小球放入数组后面。

但是这里按照逻辑,我们不应该写一个程序让他们和数组中的位置有关系啊,期望的应该是一个不受数组中位置影响的啊。

确实是这样。其实我们这里记录了一个变量,目前最近的t,一直没用,也不知道是不是作者忘了贴使用的代码了。

也就是这里我们最终需要返回的rec,它的值应该是场景中最近的一个交点的rec信息,而不是数组中最后一个。

所以说我们就利用这个信息始终维护一个最近。然后比较,只有出现了更小的时候才更新rec。

这样解决了这个之后,效果上还是不太对。

首先关于上边的问题,我们去调试,其实就是对比正确的效果,然后找到差别,针对差别的点进行调试就好了。

观察这里的大球,也就是充当地面的这个,他的表面其实本该是非常亮的,因为打在他上边的光线大概率会直接弹射到天空上,

也就是递归中止,颜色应该是一个天空的颜色并且没有怎么递减过几次的,所以应该是很亮的。

但是这里就变得很黑了,甚至看上去就纯黑了。

所以这里先大致估算一下这里黑的地方的viewport坐标 ,然后利用循环断点,找到他的循环,逐步进行跟踪调试。

当我们追踪它第一次碰撞的时候,是没有任何的问题的,和我们预期的一样,撞在了大球上,重点就在于撞了之后第二次弹射上。

第二次弹射和小球判断的时候,没有相交,和大球判断的时候就出现了问题了。

因为我们当前的射线是起点在大球上,也就是必然有一个交点是t<0和一个t==0的起点。这是两个交点。

而我们最初的判断条件是只要不比最小的t小,那么这里就认为是撞上的。

这个其实就错了,如果等于最小的t,这里最小的t是0,而交点也是0.

但这个时候是没有任何相交的。所以说当解出来的t小于等于最小的t时,都应该算作没有相交。因为最小的t就是起点处,而起点处必然相交,但这是上一次的交点,这次应该从弹射开始处理,

所以上边把<  t_min改成 <= t_min即可。

但是这个还是有一些不够严谨的地方,为啥呢?因为浮点数的精度的问题,这里有可能会导致求解出来的起点的那个t,他是一个0.00000001

这种数字,他本该是0,所以这里我们其实可以修改一下t_min,改成0.001这种就好了,就会把这种精度问题和之前那个问题都给解决了。

而且对比一下这俩效果,其实还是有一些差别的,前者是0.01的,后者是0的,后者就多了很多的黑点在上边。

(因为如果判断为当前点为相交点,就会一直相交下去,最后颜色就是0了.)

(121条消息) 光线追踪渲染实战:蒙特卡洛路径追踪及其c++实现_AkagiSenpai的博客-CSDN博客

猜你喜欢

转载自blog.csdn.net/yinianbaifaI/article/details/127702742