问题三十五: 怎么用ray tracing画二次曲面(quadratic surfaces)(2)——单页双曲面、双页双曲面、椭圆锥面、椭圆柱面
35.2.1 數學推導
單頁雙曲面、雙頁雙曲面、橢圓錐面、橢圓柱面。
這四個二次曲面方程共同形式:
但是,注意到,這些曲面都是開放曲面。在畫圖時,需要限制曲面的范圍(以免曲面覆蓋整個畫面)。
我們在這里是限制曲面在y軸方向距離中心點的長度為height_y(引入該參數)。
所以,我們可以在根據實根t求得交點坐標后,對交點坐標作如下判斷:
((rec.p.y()-center.y()) >-height_half_y) && ((rec.p.y()-center.y()) < height_half_y)
?
這里,要特別注意:
之前,球面的處理方式是:
所以,其一:我們需要對兩個實根進行排序(先處理小的)
?
另外,由于,是開放曲面,也就是,光線有可能撞擊到曲面的正反兩面,所以,對于撞擊點處的標準化之后的法向量,我們需要做如下判斷:
??????????????????????? if (dot(rec.normal,r.direction()) > 0) {
??????????????????????????? rec.normal =-rec.normal;
??????????????????????? }//(法向量決定著反射光線和折射光線)
?
還有,由于我們引入了height_y參數來限制曲面的高度,但是,我們要注意到:小實根對應的交點超出高度范圍時(之前的一貫做法:小根不在t_min、t_max范圍,就直接return false),大實根是有可能在高度范圍的(而且,如果在范圍的話,光線撞擊的曲面的內表面,這時的法向量是需要反向的)。
35.2.2 看C++代碼實現
----------------------------------------------quadratic.h ------------------------------------------
quadratic.h
?
#ifndef QUADRATIC_H #define QUADRATIC_H#include <hitable.h> #include "material.h" #include "log.h"class quadratic : public hitable {public:quadratic() {}quadratic(vec3 cen, float a, float b, float c, int s1, int s2, int hy, material *m) : center(cen), intercept_x(a), intercept_y(b), intercept_z(c), sign1(s1), sign2(s2), height_half_y(hy), ma(m) {} /* (x-xc)^2/a^2 + s1*(y-yc)^2/b^2 + (z-zc)^2/c^2 = s2 s1= -1,s2= 1: hyperboloid of one sheet s1= -1,s2= -1: hyperboloid of two sheets s1= -1,s2= 0: elliptic cone s1= 0,s2= 1: elliptic cylinder */virtual bool hit(const ray& r, float tmin, float tmax, hit_record& rec) const;vec3 center;float intercept_x;float intercept_y;float intercept_z;int sign1, sign2, height_half_y;material *ma; };#endif // QUADRATIC_H----------------------------------------------quadratic.cpp ------------------------------------------
quadratic.cpp
?
#include "quadratic.h"#include <iostream> using namespace std;bool quadratic::hit(const ray& r, float t_min, float t_max, hit_record& rec) const {float ab_square = intercept_x*intercept_x*intercept_y*intercept_y;float bc_square = intercept_y*intercept_y*intercept_z*intercept_z;float ac_square = sign1*intercept_x*intercept_x*intercept_z*intercept_z;float abc_square = sign2*intercept_x*intercept_x*intercept_y*intercept_y*intercept_z*intercept_z;vec3 inter_square = vec3(bc_square, ac_square, ab_square);vec3 rd_square = vec3(r.direction().x()*r.direction().x(),r.direction().y()*r.direction().y(),r.direction().z()*r.direction().z());float A = dot(inter_square, rd_square);vec3 r0_c = r.origin() - center;vec3 r0_c_rd = vec3(r0_c.x()*r.direction().x(),r0_c.y()*r.direction().y(),r0_c.z()*r.direction().z());float B = 2*dot(r0_c_rd, inter_square);vec3 r0_c_square = vec3(r0_c.x()*r0_c.x(),r0_c.y()*r0_c.y(),r0_c.z()*r0_c.z());float C = dot(r0_c_square, inter_square) - abc_square;float temp, temp1, temp2;vec3 pc;if(A == 0) {if (B == 0) {return false;}else {temp = -C/B;if (temp < t_max && temp > t_min) {rec.t = temp;rec.p = r.point_at_parameter(rec.t);if (((rec.p.y()-center.y()) > -height_half_y) && ((rec.p.y()-center.y()) < height_half_y)) {pc = rec.p - center;rec.normal = unit_vector(vec3(2*bc_square*pc.x(), 2*ac_square*pc.y(), 2*ab_square*pc.z()));if (dot(rec.normal, r.direction()) > 0) {rec.normal = -rec.normal;}rec.mat_ptr = ma;return true;}else {return false;}}}}else {float discriminant = B*B - 4*A*C;if (discriminant >= 0) {temp1 = (-B - sqrt(discriminant)) / (2.0*A);temp2 = (-B + sqrt(discriminant)) / (2.0*A); if (temp1 > temp2) {//make sure that temp1 is smaller than temp2temp = temp1;temp1 = temp2;temp2 = temp;} /*對兩個實根進行排序,t1<t2,先處理t1*/if (temp1 < t_max && temp1 > t_min) {rec.t = temp1;rec.p = r.point_at_parameter(rec.t);if (((rec.p.y()-center.y()) > -height_half_y) && ((rec.p.y()-center.y()) < height_half_y)) {//限制曲面的高度pc = rec.p - center;rec.normal = unit_vector(vec3(2*bc_square*pc.x(), 2*ac_square*pc.y(), 2*ab_square*pc.z()));/*任何時候,都最好將法向量進行標準化*/if (dot(rec.normal, r.direction()) > 0) {rec.normal = -rec.normal;} /*如果光線和前面內表面相交,需要將法向量反向*/rec.mat_ptr = ma;return true;}else { // return false; /*這里要特別注意,一個實根不在高度范圍內,不能直接return false,還需在判斷另一個實根*/}}if (temp2 < t_max && temp2 > t_min) {rec.t = temp2;rec.p = r.point_at_parameter(rec.t); if (((rec.p.y()-center.y()) > -height_half_y) && ((rec.p.y()-center.y()) < height_half_y)) { pc = rec.p - center;rec.normal = unit_vector(vec3(2*bc_square*pc.x(), 2*ac_square*pc.y(), 2*ab_square*pc.z()));if (dot(rec.normal, r.direction()) > 0) {rec.normal = -rec.normal;}rec.mat_ptr = ma;return true;}else { // return false;}}}return false;} }----------------------------------------------main.cpp ------------------------------------------
main.cpp
?
hitable *list[5];list[0] = new sphere(vec3(0.0,-100.5,-1), 100, new lambertian(vec3(0.8, 0.8, 0.0)));list[1] = new quadratic(vec3(-2.5, 1.5, 0), 0.5, 0.7, 1, -1, 1, 1, new lambertian(vec3(0.0, 0.1, 0.5)));list[2] = new quadratic(vec3(-0.4, 1.5, 0), 0.15, 0.2, 0.2, -1, -1, 1, new lambertian(vec3(0.3, 0.1, 0.5)));list[3] = new quadratic(vec3(1.2, 1.5, 0), 0.5, 0.7, 1, -1, 0, 1, new lambertian(vec3(0.6, 0.1, 0.5)));list[4] = new quadratic(vec3(2.8, 1.5, 0), 0.5, 0.7, 1, 0, 1, 1, new lambertian(vec3(0.9, 0.1, 0.5)));hitable *world = new hitable_list(list,5);vec3 lookfrom(0,5,10);vec3 lookat(0,1,0);float dist_to_focus = (lookfrom - lookat).length();float aperture = 0.0;camera cam(lookfrom, lookat, vec3(0,1,0), 20, float(nx)/float(ny), aperture, 0.7*dist_to_focus);
輸出圖片:
從左到右依次是:單頁雙曲面、雙頁雙曲面、橢圓錐面、橢圓柱面
總結
以上是生活随笔為你收集整理的问题三十五: 怎么用ray tracing画二次曲面(quadratic surfaces)(2)——单页双曲面、双页双曲面、椭圆锥面、椭圆柱面的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机器学习:特征工程
- 下一篇: 大数据安全:Hadoop安全模型的演进