问题四十:对ray tracing圆环图形进行debug(1)

来源:互联网 发布:预约挂号系统php源码 编辑:程序博客网 时间:2024/05/22 10:46

针对上一章节的最后输出图片,进行debug。


中间那个白色夹杂着红色的圈是什么鬼???


第一步:去掉绿圆环



第二步:将单个像素点的采样次数改为1

那个多余的白色夹杂着红色的圈的颜色之所以是白色偏红色,是因为:多次采样中可能一次出现红色而其他其次都是白色,所以作为最终像素点颜色的多次采样的平均值就是白色偏红色。之前单个像素点采样是100次。


放大5倍后截图:


第三步:针对下方多余像素点进行分析

图中多余的红色像素点,我们认为是多余的。但是,计算机之所以在某个位置生成一个红色像素点,是因为,它认为光线和圆环在这个位置相撞了。也就是说,这个位置对应这光线方程和圆环方程联立后的一个有效实根。

 

在代码中添加如下红色字体代码,去掉Y坐标小于3.4的“有效实根”

            for (int k=1;k<int(roots[0])+1; k++) {

                if (roots[k]< t_max && roots[k] > t_min) {

                    rec.t = roots[k];

                    rec.p =r.point_at_parameter(rec.t);

 

                   if (rec.p.y() < 3.4) {

                        break;

                   }

 

                    vec3 pc =rec.p - center;

                    float nx =4*pc.x()*pc.x()*pc.x() +4*pc.x()*(pc.y()*pc.y()+pc.z()*pc.z()-(radius_a*radius_a+radius_b*radius_b));

                    float ny =4*pc.y()*pc.y()*pc.y() +4*pc.y()*(pc.x()*pc.x()+pc.z()*pc.z()-(radius_a*radius_a+radius_b*radius_b));

                    float nz =4*pc.z()*pc.z()*pc.z() +4*pc.z()*(pc.x()*pc.x()+pc.y()*pc.y()+radius_a*radius_a-radius_b*radius_b);

                    rec.normal= unit_vector(vec3(nx, ny, nz));

                    if(dot(r.direction(), rec.normal) > 0) {

                       rec.normal = - rec.normal;

                    }

                   rec.mat_ptr = ma;

                    rec.u =-1.0;

                    rec.v =-1.0;

                    delete []roots;

                    returntrue;

                }

            }

输出图片如下:


放大5倍后截图:


图片中Y坐标小于3.4的红色像素点被去掉了。

 

但是,想想问题,“Y坐标小于3.4的红色点”为什么会出现???光线方程和圆环方程联立后的一元四次方程在这个位置不应该有实根啊。但是事实情况表示这个位置有实根?为什么?为什么?

可能有两个原因:

其一,方程错了:也就是方程的系数算错了。

其二,方程的求解结果错了。

 

第四步:验证方程系数

在网上搜了一下和书上形式不一样的圆环方程:



对比之前修改后的系数,两组系数是一样的,应该没有算错。再看看这组新系数对应的输出图片吧:

代码对应修改如下:

       float A = dot(oc, oc);

       float B = 2*dot(oc, r.direction());

       float C = dot(r.direction(), r.direction());

       float Rr_square_p = radius_a*radius_a +radius_b*radius_b;

       float Rr_square_s_square = (radius_a*radius_a - radius_b*radius_b) *(radius_a*radius_a - radius_b*radius_b);

       float R_square = radius_a*radius_a;

       float a4 = C*C;

       float a3 = 2*B*C;

       float a2 = B*B + 2*A*C - 2*Rr_square_p*C +4*R_square*r.direction().z()*r.direction().z();

       float a1 = 2*A*B - 2*Rr_square_p*B +8*R_square*oc.z()*r.direction().z();

       float a0 = A*A - 2*Rr_square_p*A + 4*R_square*oc.z()*oc.z() +Rr_square_s_square;

 

注意:

第三步中添加的如下代码已经删除

                   if (rec.p.y() < 3.4) {

                        break;

                   }

输出图片:



新系数(其实和之前的系数是一样的,只是换了种形式再算了一次)对应输出的图片和“第二步”中输出的图片是一样的。

这可以排除“第三步”中推测的第一个原因:方程错了。

现在只剩第二个原因了:一元四次方程解错了


第五步:分析一元四次方程的“多余”实根

在“第三步”添加代码的位置添加如下代码:

 

                    if (rec.p.y() < 3.4) {

                        rec.t = roots[k];//这句代码随便写,只是为了在此处设置断点

                    }

当出现Y坐标小于3.4的实根时,进入这个if条件,然后在此处设置断点。然后检查当前的方程系数。




 

所以,基本可以确定:解一元四次方程的程序有问题。

 

第六步:分析一元四次方程的解法

 

之前采用的是“37.3”的方法解一元四次方程。

采用的是“费拉里方法”。

在“37.3”的第四步中解关于y的一元三次方程后,选择参数y时是有问题的:

虽然,一元三次方程的任意个解都能保证方程右端配成一个完全平方式,但是,不同的解(y值)对应的方程右端最高次的系数可能是不一样的,从而导致原方程最终的解出现错误。

 

单独测试解一元四次方程的函数:

在函数中添加log如下:


解这个方程:

       roots = roots_quartic_equation(1.0, -10.0, 35.0, -50.0, 24.0);//1,2,3,4

正确的结果是:

四个实根分别是:1,2,3,4

我们看看选择不同y值时的结果:


y的三个取值(14、10、11)都能保证方程右端配成完全平方式,但是只有14、11能够保证结果正确,而选择10时,解出的根是错误的。

 

所以,y值应该怎么选择呢??

老实说,我尝试了几种方式(比如:随便选;选最大的;选最小的),都好像没有依据,都会有错误。

所以,我决定放弃“费拉里”方法,寻找新的方法来解一元四次方程。


未完待续~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


4 0
原创粉丝点击