57.1 概述

我们这里考虑的translational sweeping是XOZ平面的封闭曲线沿着y轴平移得到的图形。类似于如下图形:我们把这种图形称为“prism”。我们这里的封闭曲线是由多段三次b-spline曲线组成的。

光线和prism相交有如下图中所示的几种情况:

第一种情况:光线和顶面所在的平面相交的交点在底面的投影在封闭曲线内,如红色光线所示。

第二种情况:光线和底面所在的平面相交的交点在封闭曲线内,如绿色光线所示。

第三种情况:光线和顶面所在的平面相交的交点在底面的投影、光线和底面所在平面相交的交点都不在封闭曲线内,如紫色光线所示。

所以,我们“求根”的算法以此分为如下几个步骤:

第一步:求光线R(t)和base plane、cap plane的交点t0、t1;

第二步:将光线R(t)投影到base plane得到R'(t);

第三步:求出投影光线R’(t)与曲线的所有交点t’;

第四步:处理t0、t1有在曲线内的情况;

第五步:处理t0、t1都不在曲线内的情况;

57.2 求根

57.2.1求光线R(t)和base plane、cap plane的交点t0、t1

57.2.2将光线R(t)投影到base plane得到R'(t)

57.2.3 怎么用三次b-spline曲线段形成封闭曲线?

参考PPT截图如下:

我们接下来要画的图形,有17个控制点,则有14段(17-3=14)曲线段。示意图如下:

形成封闭曲线,则需要控制点收尾相连。所以,这17个控制点中前三个和后三个是重复的。

57.2.4 求R’(t)和封闭曲线的所有交点

要求R’(t)和封闭曲线的所有交点,我们先求R’(t)和每一曲线段的交点,然后将这14段曲线段对应的交点汇总则得到R’(t)和封闭曲线的所有交点。

接下来,我们求R’(t)和每一曲线段的交点。

57.2.5 判断t0和t1在base plane的投影是否在封闭曲线内

我们已经求得R’(t)与曲线的所有交点。示意如下图。

t0、t1在base plane的投影必定都在R’(t)上,如上图中三角形示意。

怎么判断点是否在曲线内呢?

若大于t0/t1的交点数为偶数,则t0/t1在曲线外;

若大于t0/t1的交点数为奇数,则t0/t1在曲线内;

我们现在不说t0或者t1,改说两者中较小的t0_t1_smaller,两者中较大的t0_t1_bigger。

若t0_t1_smaller在曲线内:

如“57.1”图示的红色光线。

最终要求的t是:t0_t1_smaller。

若t0_t1_bigger在曲线内:

如“57.1”图示的绿色光线。

最终要求的t是:所有有效交点中最小的那个对应的t

57.2.6处理t0、t1都不在曲线内的情况

针对t0、t1都不在曲线内的情况,如“57.1”图示的蓝色光线和紫色光线,我们直到蓝色光线没有撞击到prism,紫色光线撞击到了prism。

但是,具体怎么判断光线是否撞击到prism呢?

参考前人的成果,判断方式如下:

所有有效交点存在一个t’满足:“式子九”

|t’-t0|*Rd·n<h

其中Rd为光线方向向量,n为base plane的单位法向量,h为prism的高度。

将t’、t0都代入光线方程:R(t)=R0+Rd*t

然后,我们可以得到R(t0)-R(t’)= (R0+Rd*t0)-( R0+Rd*t’)=(t0-t’)*Rd

然后,再和n点积(n为单位向量,所以相当于长度乘以cos(theta)),得到高度。

具体如下图所示:

注意到:t1对应的那个高度为h。

上图中存在t’3和t’4满足“式子九”。

最终要求的t是:满足“式子九”的最小的那个t’

注意:

这个时候还需要判断对应的y值是否在[base_y, cap_y]之间。若在,该t即为所求;若不在,则光线没有撞击到prism。

具体做法:将t代入光线方程“式子一”求出y值,然后判断一下即可。

上图中为t’3.

57.3 求法向量

若t0_t1_smaller在曲线内:

法向量即为cap plane的法向量:(0, 1, 0)

若t0_t1_bigger在曲线内

或者

t0、t1都不在曲线内

这两种情况的根是通过投影光线和曲线相交求得,对应的法向量即为曲线在该处的切向量的垂直向量。

我们可以通过对“式子六”求对u的微分来求得切向量。“式子十”

57.4 看C++代码实现

----------------------------------------------vec3.h ------------------------------------------

vec3.h

bool matrix_4_4_multiply_4_1(const float matrix1[4][4], const float matrix2[4][1], float (&result)[4][1]);

----------------------------------------------vec3.cpp ------------------------------------------

vec3.cpp

bool matrix_4_4_multiply_4_1(const float matrix1[4][4], const float matrix2[4][1], float (&result)[4][1]) {for (int k=0; k<1; k++) {for (int i=0; i<4; i++) {result[i][k] = 0.0;for (int j=0; j<4; j++) {result[i][k] = result[i][k] + matrix1[i][j]*matrix2[j][k];}}}return true;
}

----------------------------------------------sweeping_translational.h ------------------------------------------

sweeping_translational.h

#ifndef SWEEPING_TRANSLATIONAL_H
#define SWEEPING_TRANSLATIONAL_H#include <hitable.h>
#include <log.h>class sweeping_translational : public hitable
{public:sweeping_translational() {}sweeping_translational(vec3 *cp, float by, float cy, material *m){base_y = by;cap_y = cy;ma = m;float matrix_t_6[4][4] = {{ 1,  4,  1, 0},{-3,  0,  3, 0},{ 3, -6,  3, 0},{-1,  3, -3, 1}};float matrix_t[4][4];for (int i=0; i<4; i++) {for (int j=0; j<4; j++) {matrix_t[i][j] = matrix_t_6[i][j] / 6.0;}}float points_x[17], points_z[17], b_points_x[4][1], b_points_z[4][1], b_result_x[4][1], b_result_z[4][1];int b_num = 0;float min_x, max_x, min_z, max_z;for (int i=0; i<17; i++) {points_x[i] = cp[i].x();points_z[i] = cp[i].z();}min_x = points_x[0];max_x = points_x[0];min_z = points_z[0];max_z = points_z[0];for (int i=0; i<17; i++) {if (min_x > points_x[i]) {min_x = points_x[i];}if (max_x < points_x[i]) {max_x = points_x[i];}if (min_z > points_z[i]) {min_z = points_z[i];}if (max_z < points_z[i]) {max_z = points_z[i];}}sweeping_bl = vec3(min_x, base_y, min_z);sweeping_bh = vec3(max_x, cap_y, max_z);
/*获取包围prism的最小的长方体的参数*/for (int i=0; i<14; i=i+1) {b_points_x[0][0] = points_x[i];b_points_x[1][0] = points_x[i+1];b_points_x[2][0] = points_x[i+2];b_points_x[3][0] = points_x[i+3];b_points_z[0][0] = points_z[i];b_points_z[1][0] = points_z[i+1];b_points_z[2][0] = points_z[i+2];b_points_z[3][0] = points_z[i+3];matrix_4_4_multiply_4_1(matrix_t, b_points_x, b_result_x);matrix_4_4_multiply_4_1(matrix_t, b_points_z, b_result_z);for (int j=0; j<4; j++) {matrix_c_x[j][b_num] = ((fabs(b_result_x[j][0])<1e-6)? (0.0):(b_result_x[j][0]));matrix_c_z[j][b_num] = ((fabs(b_result_z[j][0])<1e-6)? (0.0):(b_result_z[j][0]));
/*这里是求“式子六”中提到的[Cx][Cz]*/}b_num ++;}}virtual bool hit(const ray& r, float tmin, float tmax, hit_record& rec) const;float matrix_c_x[4][14], matrix_c_z[4][14];vec3 sweeping_bl, sweeping_bh;float base_y, cap_y;material *ma;
};#endif // SWEEPING_TRANSLATIONAL_H

----------------------------------------------sweeping_translational.cpp ------------------------------------------

sweeping_translational.cpp

#include "sweeping_translational.h"#include <iostream>
#include <limits>
#include "float.h"bool ray_hit_box_st(const ray& r, const vec3& vertex_l,const vec3& vertex_h, float& t_near,
float& t_far) {
/*这里重写光线撞击长方体的函数*/t_near =(numeric_limits<float>::min)();t_far =(numeric_limits<float>::max)();vec3 direction =r.direction();vec3 origin =r.origin();vec3 bl = vertex_l;vec3 bh = vertex_h;float array1[6];if(direction.x() == 0){if((origin.x()< bl.x()) || (origin.x() > bh.x())) {return false;}array1[0] =(numeric_limits<float>::min)();array1[1] =(numeric_limits<float>::max)();}if(direction.y() == 0){if((origin.y()< bl.y()) || (origin.y() > bh.y())) {return false;}array1[2] =(numeric_limits<float>::min)();array1[3] =(numeric_limits<float>::max)();}if(direction.z() == 0){if((origin.z()< bl.z()) || (origin.z() > bh.z())) {return false;}array1[4] =(numeric_limits<float>::min)();array1[5] =(numeric_limits<float>::max)();}if((direction.x() !=0) && (direction.y() != 0) && (direction.z() != 0)) {array1[0] =(bl.x()-origin.x())/direction.x();array1[1] =(bh.x()-origin.x())/direction.x();array1[2] =(bl.y()-origin.y())/direction.y();array1[3] =(bh.y()-origin.y())/direction.y();array1[4] =(bl.z()-origin.z())/direction.z();array1[5] =(bh.z()-origin.z())/direction.z();}for (int i=0; i<6;i=i+2){if(array1[i] >array1[i+1]) {float t =array1[i];array1[i] =array1[i+1];array1[i+1] =t;}if(array1[i] >= t_near) {t_near =array1[i];}if(array1[i+1]<= t_far) {t_far = array1[i+1];}if(t_near >t_far) {return false;}if(t_far < 0) {return false;}}if (t_near != t_near){t_near = t_near *1;}return true;
}bool sweeping_translational::hit(const ray& r, float t_min, float t_max,hit_record& rec) const {
#if SWEEPING_TRANSLATIONAL_LOG == 1std::cout <<"-------------sweeping_translational::hit---1-------------" <<endl;
#endif // SWEEPING_TRANSLATIONAL_LOGfloat t_near, t_far;if (ray_hit_box_st(r,sweeping_bl, sweeping_bh, t_near, t_far)) {float x0 = r.origin().x();float y0 =r.origin().y();float z0 =r.origin().z();float xd =r.direction().x();float yd =r.direction().y();float zd =r.direction().z();if (fabs(xd) < 1e-6) {xd = 1e-6;}if (fabs(yd) < 1e-6) {yd = 1e-6;}if (fabs(zd) < 1e-6) {zd = 1e-6;}
/*非常接近0的值都用1e-6替代*/float cos_theta =dot(r.direction(), vec3(0, -1, 0))/(r.direction().length());float t0, t1,t0_t1_smaller, t0_t1_bigger, a3, a2, a1, a0, *roots3_base, roots_base[21][3],temp0, temp1, temp2, root[5], u, check_y;
/*
root[0]:    0表示没有根;1表示1个根
root[1]:   存放根t
root[2]:    1表示t0_t1_smaller在曲线内;2表示t0_t1_bigger在曲线内;3表示t0、t1都不在曲线内。(不同情况,法向量的求解方式不一样)
root[3]:    存放曲线段编号(法向量求解时需要)
root[4]:    存放根t对应的u的值(法向量求解时需要)
*/roots_base[0][0] =0.0;root[0] = 0.0;root[2] = 0.0;root[3] = -1.0;root[4] = -1.0;int num_roots_base= 0;intnum_t0_t1_smaller = 0;intnum_t0_t1_bigger = 0;intnum_roots_base_valid = 0;t0 = (base_y - y0) / yd;t1 = (cap_y - y0) / yd;
/*对应“式子三”*/t0_t1_smaller = (t0>t1)? t1:t0;t0_t1_bigger =(t0>t1)? t0:t1;for (int i=0;i<14; i++) {
/*14段曲线段。求解14个一元三次方程。对应“式子七”*/a3 =zd*matrix_c_x[3][i] - xd*matrix_c_z[3][i];a2 =zd*matrix_c_x[2][i] - xd*matrix_c_z[2][i];a1 =zd*matrix_c_x[1][i] - xd*matrix_c_z[1][i];a0 =zd*matrix_c_x[0][i] - xd*matrix_c_z[0][i] + xd*z0 - zd*x0;roots3_base =roots_cubic_equation(a3, a2, a1, a0);if(roots3_base[0] != 0.0) {for (intj=1; j<(int(roots3_base[0])+1); j++) {u =roots3_base[j];if((u>=0.0) && (u<=1.0)) {roots_base[num_roots_base+1][0] =(matrix_c_x[0][i]+matrix_c_x[1][i]*u+matrix_c_x[2][i]*u*u+matrix_c_x[3][i]*u*u*u-x0)/xd;
/*对应“式子八”,将u转化为t*/roots_base[num_roots_base+1][1] = i;roots_base[num_roots_base+1][2] = u;
/*同时保存曲线段编号和u,为了后面求法向量*/num_roots_base ++;}}roots_base[0][0] = float(num_roots_base);}delete []roots3_base;}if (roots_base[0][0] != 0.0) {
/*对所有根进行从小到大排序*/for (int i=1;i<int(roots_base[0][0]); i++) {for (intj=i+1; j<int(roots_base[0][0])+1; j++) {if(roots_base[i][0] > roots_base[j][0]) {temp0 =roots_base[i][0];roots_base[i][0] = roots_base[j][0];roots_base[j][0] = temp0;temp1 = roots_base[i][1];roots_base[i][1] = roots_base[j][1];roots_base[j][1] = temp1;temp2 = roots_base[i][2];roots_base[i][2] = roots_base[j][2];roots_base[j][2] = temp2;}}}for (int i=1;i<(int(roots_base[0][0])+1); i++) {
/*判断大于t0_t1_smaller的根的个数,为了判断其是否在曲线内,对应57.2.5*/if(roots_base[i][0] > (t0_t1_smaller)) {num_t0_t1_smaller = int(roots_base[0][0])+1-i;break;}}if((num_t0_t1_smaller%2) != 0) {root[1] =t0_t1_smaller;root[0] =1.0;root[2] =1.0;}else {for (inti=1; i<(int(roots_base[0][0])+1); i++) {
/*判断大于t0_t1_bigger的根的个数,为了判断其是否在曲线内,对应57.2.5*/if(roots_base[i][0] > (t0_t1_bigger)) {num_t0_t1_bigger = int(roots_base[0][0])+1-i;break;}}if((num_t0_t1_bigger%2) != 0) {root[1] = roots_base[1][0];//fabs(cos_theta);root[0] = 1.0;root[2] = 2.0;root[3] = roots_base[1][1];root[4] = roots_base[1][2];}else {
/*如下处理t0,t1都不在曲线内的情况,对应“57.2.6”*/for(int i=1; i<(int(roots_base[0][0])+1); i++) {if(fabs(roots_base[i][0]-t0_t1_bigger)*fabs(dot(r.direction(), vec3(0, -1,0)))<fabs(cap_y-base_y)) {
/*对应“式子九”*/
//                           if (roots_base[i][0] > t0_t1_smaller) {num_roots_base_valid = i;
/*保存大于t0_t1_smaller的最小的那个根的编号*/break;}}if(num_roots_base_valid != 0) {root[1] = roots_base[num_roots_base_valid][0];//fabs(cos_theta);check_y = y0 + yd * root[1];

if ((check_y > base_y) &&(check_y < cap_y)) {

/*这里就是“57.2.6”中提到的需要注意的地方,必须加这个限制条件。后续我们对比有无这个限制条件时的输出图形*/

                                root[0] = 1.0;root[2] = 3.0;root[3] = roots_base[num_roots_base_valid][1];root[4] = roots_base[num_roots_base_valid][2];}}}}if (root[0] != 0.0) {if ((root[1] < t_max) && (root[1] > t_min)) {rec.t = root[1];rec.p = r.point_at_parameter(rec.t);if (root[2] == 1.0) {
/*若t0_t1_smaller在曲线内:法向量即为cap plane的法向量:(0, 1, 0)*/rec.normal = vec3(0, 1, 0);}else {float nx, nz, nu;int num = int(root[3]);nu = root[4];nx = matrix_c_x[1][num]+2.0*matrix_c_x[2][num]*nu+3.0*matrix_c_x[3][num]*nu*nu;nz = matrix_c_z[1][num]+2.0*matrix_c_z[2][num]*nu+3.0*matrix_c_z[3][num]*nu*nu;
/*对应“式子十”*/rec.normal = unit_vector(vec3(nx, 0, nz));}if(dot(r.direction(), rec.normal) > 0) {rec.normal = - rec.normal;}rec.mat_ptr = ma;rec.u = -1.0;rec.v = -1.0;return true;}else {return false;}}else {return false;}}else {return false;}}else {return false;}
}

----------------------------------------------main.cpp ------------------------------------------

main.cpp

        vec3 ctrl_points[17] = {vec3(-4.0,  0.0, -1.0), vec3(-3.0,  0.0, -4.0), vec3(-2.0,  0.0, -4.0), vec3(-1.0,  0.0,  -1.0),vec3( 1.0,  0.0, -1.0), vec3( 1.0,  0.0, -5.0), vec3( 3.0,  0.0, -5.0), vec3( 4.0,  0.0,   1.0),vec3( 2.0,  0.0,  2.0), vec3( 0.5,  0.0,  2.0), vec3(-2.0,  0.0,  1.0), vec3(-2.0,  0.0,  -2.0),vec3(-2.5,  0.0, -3.0), vec3(-3.0,  0.0, -1.0), vec3(-4.0,  0.0, -1.0), vec3(-3.0,  0.0,  -4.0), vec3(-2.0,  0.0, -4.0)};hitable *list[1];list[0] = new sweeping_translational(ctrl_points, 0.0, 3.0, new lambertian(vec3(1.0, 0.0, 0.0)));hitable *world = new hitable_list(list,1);vec3 lookfrom(0.0001, 20, 20);vec3 lookat(0, 1.5, 0);float dist_to_focus = (lookfrom - lookat).length();float aperture = 0.0;camera cam(lookfrom, lookat, vec3(0,1,0), 30, float(nx)/float(ny), aperture, 0.7*dist_to_focus);

输出图片如下:(前边是没有加“57.2.6”中提到的限制条件时;后边是加了该限制条件时)

(0.0001,20, 20)

(0.0001,20, 10)

(0.0001,20, 5)

(-5, 20, 10)

问题五十七:怎么用ray tracing画translational sweeping图形相关推荐

  1. 问题六十三:怎么用ray tracing画sphere sweeping图形

    63.1 概述 Translational sweeping.conic sweeping.rotational sweeping都是任意曲线以某种固定方式移动后形成的图形. 接下来,我们要画的sph ...

  2. 问题六十三:怎么用ray tracing画sphere sweeping图形(2)——teapot

    63.5 组合rotational sweeping和sphere sweeping画一个teapot ----------------------------------------------ma ...

  3. 问题三十五: 怎么用ray tracing画二次曲面(quadratic surfaces)(1)——椭球面

    二次曲面包括:球面.椭圆球面.单页双曲面.双页双曲面.椭圆锥面.椭圆柱面.椭圆抛物面.双曲抛物面等等. 注意到:只有球面和椭球面是封闭面,其他的都是开放面. 二次曲面是有方程的(我们已经学过的多边形. ...

  4. 问题三十五: 怎么用ray tracing画二次曲面(quadratic surfaces)(3)——椭球抛物面

    35.3 椭球抛物面 35.3.1 数学推导 椭球抛物面的方程如下: 所以,其一:我们需要对两个实根进行排序(先处理小的) 另外,由于,是开放曲面,也就是,光线有可能撞击到曲面的正反两面,所以,对于撞 ...

  5. 问题三十五: 怎么用ray tracing画二次曲面(quadratic surfaces)(2)——单页双曲面、双页双曲面、椭圆锥面、椭圆柱面

    35.2.1 数学推导 单页双曲面.双页双曲面.椭圆锥面.椭圆柱面. 这四个二次曲面方程共同形式: 但是,注意到,这些曲面都是开放曲面.在画图时,需要限制曲面的范围(以免曲面覆盖整个画面). 我们在这 ...

  6. 问题三十五: 怎么用ray tracing画二次曲面(quadratic surfaces)(4)——双曲抛物面(马鞍面)

    35.4 双曲抛物面(马鞍面) 35.4.1 数学推导 双曲抛物面的方程如下: 35.4.2 看C++代码实现 -------------------------------------------- ...

  7. 问题三十五: 怎么用ray tracing画二次曲面(quadratic surfaces)(5)——汇总

    二次曲面来张合照: hitable *list[9];list[0] = new sphere(vec3(0.0,-100.5,-1), 100, new lambertian(vec3(0.8, 0 ...

  8. 问题五十三:怎么用ray tracing画参数方程表示的曲面(1)

    首先,以球面为例学习怎么用ray tracing画参数方程表示的曲面:然后,再画一个牛角面. 特别说明:这一章节所画的曲面只是示意性的,所以先不care图片上的瑕疵. 53.1 数学推导 球面的参数方 ...

  9. 问题三十三:怎么用ray tracing画特殊长方体(box)

    33.1 怎么用ray tracing画特殊长方体 在光线追踪中被用到的一种常见形态是长方体盒子.这种基本物体被用于可见物体和包围盒,包围盒被用于加速复杂物体的相交测试. 吐槽:单词都认识,就是不知道 ...

最新文章

  1. 《我想进大厂》之mysql夺命连环13问
  2. V神建议使用BCH区块链用于以太坊“数据层”
  3. notepad++ php开发环境,Notepad++可以结合命令行来搭建各种编程环境
  4. uva 299 - Train Swapping
  5. 蓝桥杯基础练习--杨辉三角
  6. Linux中内联函数,Windows 7上的内联函数的doParallel问题(适用于Linux)
  7. 携程梁建章:要让元宇宙技术成为真宇宙探索、旅游的灵感来源
  8. 【岗位详情】腾讯广告策略产品经理(北京)
  9. paip.应用程序远程WEB 接口的设计
  10. Python之旅Day14 JQuery部分
  11. 伯克利(Berkeley cs61b)git使用
  12. 【Opencv综合应用】自制训练集的人脸识别1——拍摄10张人脸图片
  13. class0:计算机的潜意识——机器学习
  14. xign跨平台游戏引擎演示
  15. atk-hc05 蓝牙
  16. pandas DataFrame 交集并集补集
  17. ABAP学习笔记-基础语法-06-流程控制(01)-条件语句
  18. java课程设计象棋_java课程设计 中国象棋
  19. 高校房产管理平台架构及安全性需求分析
  20. 为什么RISC-V中需要恒零寄存器?

热门文章

  1. Linux Crontab定时任务
  2. Linux访问windows共享文件夹
  3. shell 模拟多进程(3)
  4. CloudStack 4.3功能前瞻
  5. STM32/TMS320F2812+W5500硬软件调试总结
  6. np.squeeze():把张量中维度为1的维度去掉
  7. 笔记:css中的position定位
  8. RabbitMq初探——Hello World
  9. 浅谈企业内部安全漏洞的运营(一):规范化
  10. oracle 表查询(二)