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)——单页双曲面、双页双曲面、椭圆锥面、椭圆柱面相关推荐

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

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

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

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

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

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

  4. 问题三十五: 怎么用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 ...

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

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

  6. 问题五十:怎么用ray tracing画blobs

    这一节,画这个: 参考文献: Blinn, J.F., A generalization of algebraic surfacedrawing. ACM Trans. Graph. 1(3) , 2 ...

  7. 问题六十:怎么用ray tracing画回旋体(rotational sweeping / revolution)

    60.1 概述 回旋体,大概是长这个样子: 回旋体是指曲线(称为"基本曲线")围绕y轴转一圈得到的图形. (基本曲线是由多段b-spline曲线段连接而成) 这里先强调一下: 上图 ...

  8. NeHe OpenGL第三十五课:播放AVI

    NeHe OpenGL第三十五课:播放AVI 在OpenGL中播放AVI: 在OpenGL中如何播放AVI呢?利用Windows的API把每一帧作为纹理绑定到OpenGL中,虽然很慢,但它的效果不错. ...

  9. 微信小程序把玩(三十五)Video API

    原文:微信小程序把玩(三十五)Video API 电脑端不能测试拍摄功能只能测试选择视频功能,好像只支持mp4格式,值得注意的是成功之后返回的临时文件路径是个列表tempFilePaths而不是tem ...

最新文章

  1. 2018深度学习引用数最高的十大论文
  2. Unable to instantiate default tuplizer [org.hibernate.tuple.entity.PojoEntityTuplizer]
  3. oracle 前导列_通过 PL/SQL Developer (Oracle)-数据库(26)
  4. matlab uicontrol中popupmenu(弹出式菜单)用法,用于显示不同的函数
  5. 2020-07-02 CVPR2020 VL论文讨论(3) 笔记
  6. Redis跳跃表详解
  7. 机器学习分类与性能度量
  8. 导航栏-滚动渐变 - 封装版
  9. java 程序执行原理
  10. linux 多个makefile,linux – 具有多个目标的Makefile
  11. php将权限写入session,PHP由session文件夹权限不够引起的报错
  12. OneNote无法同时设置中英文字体设置解决办法
  13. STM32物联网实战教程(一)—ESP8266的AT指令集详解
  14. 视频直播系统源码,简单的移动端轮播图
  15. 故事板(StoryBoards)和动画(Animations)
  16. 2022CVPR云分享 | 清华大学刘烨斌老师实验室四位讲者带你走进计算机视觉领域顶会...
  17. 如何解决算百分比,加起来不是100%的问题
  18. IT农民工如何来美国工作(续)
  19. 【OneDrive篇】OneDrive禁用个人保管库(网页端)
  20. ctab提取dna流程图_CTAB法提取DNA简要步骤

热门文章

  1. Why does the Eigen decomposition of the covariance matrix of a point cloud give its orientation?
  2. 武里南主帅鲁能大球场内放言:来这里就是为赢鲁能
  3. AJAX框架衣柜设计师,9张衣柜设计,设计师真的是那么不堪吗?
  4. goahead占用CPU问题
  5. 香港舞蹈家荣毅捷“回乡”办学记:民族的就是世界的
  6. java学习笔记13:正则表达式、System类、Date类、Calendar类
  7. 计算机网络发展快速的原因,计算机网络技术发展历程、功能及展望
  8. 虚幻引擎安装失败:先决条件失败 IS-PQR23
  9. 【郑轻】[1837]LT说我不服
  10. android11微信分享图片黑色,Android 微信分享图片问题集锦