问题三十五: 怎么用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)——单页双曲面、双页双曲面、椭圆锥面、椭圆柱面相关推荐
- 问题三十五: 怎么用ray tracing画二次曲面(quadratic surfaces)(1)——椭球面
二次曲面包括:球面.椭圆球面.单页双曲面.双页双曲面.椭圆锥面.椭圆柱面.椭圆抛物面.双曲抛物面等等. 注意到:只有球面和椭球面是封闭面,其他的都是开放面. 二次曲面是有方程的(我们已经学过的多边形. ...
- 问题三十五: 怎么用ray tracing画二次曲面(quadratic surfaces)(3)——椭球抛物面
35.3 椭球抛物面 35.3.1 数学推导 椭球抛物面的方程如下: 所以,其一:我们需要对两个实根进行排序(先处理小的) 另外,由于,是开放曲面,也就是,光线有可能撞击到曲面的正反两面,所以,对于撞 ...
- 问题三十五: 怎么用ray tracing画二次曲面(quadratic surfaces)(4)——双曲抛物面(马鞍面)
35.4 双曲抛物面(马鞍面) 35.4.1 数学推导 双曲抛物面的方程如下: 35.4.2 看C++代码实现 -------------------------------------------- ...
- 问题三十五: 怎么用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 ...
- 问题三十三:怎么用ray tracing画特殊长方体(box)
33.1 怎么用ray tracing画特殊长方体 在光线追踪中被用到的一种常见形态是长方体盒子.这种基本物体被用于可见物体和包围盒,包围盒被用于加速复杂物体的相交测试. 吐槽:单词都认识,就是不知道 ...
- 问题五十:怎么用ray tracing画blobs
这一节,画这个: 参考文献: Blinn, J.F., A generalization of algebraic surfacedrawing. ACM Trans. Graph. 1(3) , 2 ...
- 问题六十:怎么用ray tracing画回旋体(rotational sweeping / revolution)
60.1 概述 回旋体,大概是长这个样子: 回旋体是指曲线(称为"基本曲线")围绕y轴转一圈得到的图形. (基本曲线是由多段b-spline曲线段连接而成) 这里先强调一下: 上图 ...
- NeHe OpenGL第三十五课:播放AVI
NeHe OpenGL第三十五课:播放AVI 在OpenGL中播放AVI: 在OpenGL中如何播放AVI呢?利用Windows的API把每一帧作为纹理绑定到OpenGL中,虽然很慢,但它的效果不错. ...
- 微信小程序把玩(三十五)Video API
原文:微信小程序把玩(三十五)Video API 电脑端不能测试拍摄功能只能测试选择视频功能,好像只支持mp4格式,值得注意的是成功之后返回的临时文件路径是个列表tempFilePaths而不是tem ...
最新文章
- 2018深度学习引用数最高的十大论文
- Unable to instantiate default tuplizer [org.hibernate.tuple.entity.PojoEntityTuplizer]
- oracle 前导列_通过 PL/SQL Developer (Oracle)-数据库(26)
- matlab uicontrol中popupmenu(弹出式菜单)用法,用于显示不同的函数
- 2020-07-02 CVPR2020 VL论文讨论(3) 笔记
- Redis跳跃表详解
- 机器学习分类与性能度量
- 导航栏-滚动渐变 - 封装版
- java 程序执行原理
- linux 多个makefile,linux – 具有多个目标的Makefile
- php将权限写入session,PHP由session文件夹权限不够引起的报错
- OneNote无法同时设置中英文字体设置解决办法
- STM32物联网实战教程(一)—ESP8266的AT指令集详解
- 视频直播系统源码,简单的移动端轮播图
- 故事板(StoryBoards)和动画(Animations)
- 2022CVPR云分享 | 清华大学刘烨斌老师实验室四位讲者带你走进计算机视觉领域顶会...
- 如何解决算百分比,加起来不是100%的问题
- IT农民工如何来美国工作(续)
- 【OneDrive篇】OneDrive禁用个人保管库(网页端)
- ctab提取dna流程图_CTAB法提取DNA简要步骤
热门文章
- Why does the Eigen decomposition of the covariance matrix of a point cloud give its orientation?
- 武里南主帅鲁能大球场内放言:来这里就是为赢鲁能
- AJAX框架衣柜设计师,9张衣柜设计,设计师真的是那么不堪吗?
- goahead占用CPU问题
- 香港舞蹈家荣毅捷“回乡”办学记:民族的就是世界的
- java学习笔记13:正则表达式、System类、Date类、Calendar类
- 计算机网络发展快速的原因,计算机网络技术发展历程、功能及展望
- 虚幻引擎安装失败:先决条件失败 IS-PQR23
- 【郑轻】[1837]LT说我不服
- android11微信分享图片黑色,Android 微信分享图片问题集锦