【Ray Tracing in One Weekend 超详解】 光线追踪1-2
今天我们开始进入正篇
Chapter 3: Rays, a simple camera, and background
对于所有的光线追踪器,基本都有一个光线类,计算沿光线看到的颜色。
我们的光线是一个矢量运算:
p(t) = a + t * b.
书中的向量用大写粗体字表示,但这里我遵循一般表示法:矩阵为粗体大写字母,向量为粗体小写字母,而标量为正常字体
P是光线指向的目标位置,a是光线的起点,b是光线指向的方向,t则是光线步长。
如图:
我们如下定义ray-class
/// ray.h // -----------------------------------------------------
// [author] lv
// [begin ] 2018.12
// [brief ] the ray-class for the ray-tracing project
// from the 《ray tracing in one week》
// ----------------------------------------------------- #ifndef RAY_H
#define RAY_H #include <lvgm\type_vec\type_vec.h> //https://www.cnblogs.com/lv-anchoret/p/10163085.html class ray
{
public: using value_type = lvgm::precision; using vec_type = lvgm::vec3<value_type>; public:
ray()
:_a{vec_type()}
, _b{vec_type()}
{ } ray(const vec_type& a, const vec_type& b)
:_a(a)
,_b(b)
{ } ray(const ray& r)
:_a(r._a)
,_b(r._b)
{ } inline vec_type origin()const { return _a; } inline vec_type direction()const { return _b; } inline vec_type go(const value_type t)const { return _a + t * _b; } private:
vec_type _a; vec_type _b; }; #endif //ray_h
然后我们来看制作一个光线追踪器,它的核心在于,发送光线去穿过像素,进而计算出沿着光线方向,什么颜色被看到了
我们看到物体,是外部光照射到物体表面,经过表面反射之后,那部分反射进入眼睛的光被我们捕捉,从而看到了光来源位置的物体,那么,我们假设从眼睛发射一束光,它代表我们的视线,当它沿着某个方向一直向前,视线会与物体表面相交,那么,我们就捕捉到了一个像素。光线追踪器就是计算视线的一种形式。
为了更贴切,我们在此之后将光线统一称为视线。
它可以计算视线与表面交点以及交点处的颜色。
上述内容会在后续的案例讲解过程中逐步理解的。
现在,我们来了解一下本书采用的默认坐标系统
coord 1.1
坐标(0,0,0)处为我们的眼睛(或者相机),我们的绘图区域为蓝色框代表的矩形平面,也就是你观察图像的那个屏幕。
按照学OpenGL的老规矩,第一堂当然是线性插值
差值公式:
blended_value = (1-t) * start_value + t * end_value
解释一下上面的公式:
t 是一个系数,根据情况确定,将开始颜色和终止颜色进行比例混合,然后得到混合色
如果我们要做一个从白色到蓝色根据坐标位置确定混合比例进行插值的矩形彩图
我们该如何做呢?
第一步,我们需要确定分辨率,假定为400*200,就用coord1.1的坐标体系去做。
第二步,我们需要确定开始位置和终止位置,假定从左下角混合到右上角,混合颜色为白色和蓝色。
第三步,我们需要确定视线,即确定从眼睛出发到屏幕的向量
1. 确定在平面中的位置,从左下角开始每一个平面位置均由水平和垂直两个分向量叠加而成:
diagram 3-1
由坐标系统得知,lower-left的坐标为(-2,-1,-1)
若y =(0,0.5,0),x =(1,0,0),则pos =(-1,-0.5,-1)
2.当我们确定了pos之后,其实,视线已经确定好了,因为眼睛的坐标为(0,0,0),pos即为视线向量
第四步,我们需要从分辨率到屏幕做一个映射。
看图还记得我们的分辨率是400*200吗,而屏幕的范围是4*2的矩形
所以,我们需要做一个映射,和上次一样,我们可以将分辨率下的位置通过除法转换到标准坐标,然后再通过标准坐标转换到屏幕坐标
例如一个分辨率下的x的步长为388,首先通过388/400变为一个0~1的实数,然后乘以4,即可变为屏幕步长
然后通过diagram 3-1,确定屏幕中的位置
第五步,我们需要确定比例系数t,我们可以选择x或y方向的其中一个做映射。
因为屏幕坐标系不确定,我们采用的是4*2的,但不是铭文规定的,所以我们需要将视线向量(等同于pos坐标位置)进行单位化,这样的话就可以把每个坐标分量的长度控制在[-1, 1],如果我们把它+1再除以2,那么就完全转化到[0, 1]了,此时,每个坐标方向的分向量范数均为[0, 1],它们是由三个坐标基共同作用而成的独一无二的,所以,你可以采用x的单位化值作为t,也可以把y作为t。
第六步,经过上述一顿操作,我们终于得到了屏幕某个点对应的blend_value,颜色混合值(或称为插值)
至此,我们基于位置进行的颜色插值就讲解完了
下面是代码:
#define LOWPRECISION #include <fstream>
#include "ray.h"
using namespace lvgm; #define stds std:: ray::vec_type lerp(const ray& r)
{
ray::vec_type unit_dir = r.direction().ret_unitization(); //单位化
ray::value_type t = 0.5*(unit_dir.y() + 1.0); //将y分量映射到[0, 1]
//插值公式 白色&蓝色
return (1.0 - t)*ray::vec_type(1.0, 1.0, 1.0) + t*ray::vec_type(0.0, 0.0, 1.0);
} void build_3_1()
{
int X = , Y = ; //分辨率 400*200
stds ofstream file("graph3-1.ppm");
if (file.is_open())
{
file << "P3\n" << X << " " << Y << "\n255\n";
ray::vec_type left_bottom{ -2.0,-1.0,-1.0 }; //左下角作为开始位置
ray::vec_type horizontal{ 4.0,, }; //屏幕水平宽度
ray::vec_type vertical{ ,2.0, }; //屏幕垂直高度
ray::vec_type eye{ ,, }; //眼睛位置
for (int j = Y - ; j >= ; --j)
for (int i = ; i < X; ++i)
{
vec2<ray::value_type> para(ray::value_type(i) / X, ray::value_type(j) / Y);
ray r(eye, left_bottom + para.u() * horizontal + para.v() * vertical);
ray::vec_type color = lerp(r); //得到插值颜色(rgb)
int ir = int(255.99*color.r());
int ig = int(255.99*color.g());
int ib = int(255.99*color.b());
file << ir << " " << ig << " " << ib << stds endl;
}
file.close();
}
else
stds cerr << "load file failed!" << stds endl;
stds cout << "complished" << stds endl;
} int main()
{
build_3_1();
}
下面是效果图(y分量作为插值公式系数)
当然你也可以用x分量作为插值公式系数 t
感谢您的阅读,生活愉快~
【Ray Tracing in One Weekend 超详解】 光线追踪1-2的更多相关文章
- 【Ray Tracing The Next Week 超详解】 光线追踪2-9
我们来整理一下项目的代码 目录 ----include --hit --texture --material ----RTdef.hpp ----ray.hpp ----camera.hpp ---- ...
- 【Ray Tracing The Next Week 超详解】 光线追踪2-6 Cornell box
Chapter 6:Rectangles and Lights 今天,我们来学习长方形区域光照 先看效果 light 首先我们需要设计一个发光的材质 /// light.hpp // ------- ...
- 【Ray Tracing in One Weekend 超详解】 光线追踪1-4
我们上一篇写了Chapter5 的第一个部分表面法线,那么我们来学剩下的部分,以及Chapter6. Chapter5:Surface normals and multiple objects. 我们 ...
- 【Ray Tracing The Next Week 超详解】 光线追踪2-7 任意长方体 && 场景案例
上一篇比较简单,很久才发是因为做了一些好玩的场景,后来发现这一章是专门写场景例子的,所以就安排到了这一篇 Preface 这一篇要介绍的内容有: 1. 自己做的光照例子 2. Cornell box画 ...
- 【Ray Tracing The Next Week 超详解】 光线追踪2-8 Volume
Preface 今天有两个东东,一个是体积烟雾,一个是封面图 下一篇我们总结项目代码 Chapter 8:Volumes 我们需要为我们的光线追踪器添加新的物体——烟.雾,也称为participat ...
- 【Ray Tracing The Next Week 超详解】 光线追踪2-5
Chapter 5:Image Texture Mapping 先看效果: 我们之前的纹理是利用的是撞击点p处的位置信息,比如大理石纹理 而我们今天的图片映射纹理采用2D(u,v)纹理坐标来进行. 在 ...
- 【Ray Tracing in One Weekend 超详解】 光线追踪1-8 自定义相机设计
今天,我们来学习如何设计自定义位置的相机 ready 我们只需要了解我们之前的坐标体系,或者说是相机位置 先看效果 Chapter10:Positionable camera 这一章我们直接用概念 ...
- 【Ray Tracing The Next Week 超详解】 光线追踪2-4 Perlin noise
Preface 为了得到更好的纹理,很多人采用各种形式的柏林噪声(该命名来自于发明人 Ken Perlin) 柏林噪声是一种比较模糊的白噪声的东西:(引用书中一张图) 柏林噪声是用来生成一些看似杂乱 ...
- 【Ray Tracing The Next Week 超详解】 光线追踪2-3
Preface 终于到了激动人心的纹理章节了 然鹅,看了下,并不激动 因为我们之前就接触过 当初有一个 attenuation 吗? 对了,这就是我们的rgb分量过滤器,我们画出的红色.蓝色.绿色等 ...
- 【Ray Tracing The Next Week 超详解】 光线追踪2-2
Chapter 2:Bounding Volume Hierarchies 今天我们来讲层次包围盒,乍一看比较难,篇幅也多,但是咱们一步一步来,相信大家应该都能听懂 BVH 和 Perlin text ...
随机推荐
- ELK 日志分析实例
ELK 日志分析实例一.ELK-web日志分析二.ELK-MySQL 慢查询日志分析三.ELK-SSH登陆日志分析四.ELK-vsftpd 日志分析 一.ELK-web日志分析 通过logstash ...
- Java基础-虚拟内存之映射字节缓冲区(MappedByteBuffer)
Java基础-虚拟内存之映射字节缓冲区(MappedByteBuffer) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.映射字节缓冲区 1>.什么是虚拟内存 答:虚拟内 ...
- bzoj千题计划261:bzoj3294: [Cqoi2011]放棋子
http://www.lydsy.com/JudgeOnline/problem.php?id=3294 如果一个颜色的棋子放在了第i行第j列,那这种颜色就会占据第i行第j列,其他颜色不能往这儿放 设 ...
- [整理]win7下VS2010遇到内存不足解决方发
电脑重装Win7 64bit不久后,一天内VS2010使用久了,就会出现内存不足,实际内存使用情况却不是,显示内存已使用70%.以前没有遇到过,经网上查找,貌似是VS2010对内存计算会在某些情况下计 ...
- iOS 远程推送注册的小问题
iOS8有了新方法,用新方法后,用7.0版本运行会奔溃.只要加一句判断就ok: #ifdef __IPHONE_8_0 // 在 iOS 8 下注册苹果推送,申请推送权限. UIUserNotific ...
- 如何用Procmon.exe来监视SQLSERVER的logwrite大小
如何用Procmon.exe来监视SQLSERVER的logwrite大小 在微软亚太区数据库技术支持组官方博客里面,你会发现很多篇文章都用到了Procmon.exe这个工具 今天我也介绍一下这个工具 ...
- 第12月第25天 ImagePickerSheetController
1.ImagePickerSheetController open class ImagePickerSheetController: UIViewController, UITableViewDat ...
- Apache的对象复制详解
BeanUtils.copyProperties 和 PropertyUtils.copyProperties 两个工具类都是对两个bean之前存在name相同的属性进行处理,无论是源bean或者目标 ...
- 灵活、可高度自定义的——Progress进度圈、弹窗、加载进度、小菊花
DDProgressHUD的介绍 提供了四种类型的展示: 显示无限旋转的加载图(比如小菊花,可以自定义),显示文字信息.网络刷新时经常用到. 显示加载进度的动画,也可以显示文字.网络下载时用的比较多, ...
- GBDT理解
一.提升树 提升方法实际采用加法模型(即基函数的线性组合)与前向分布算法.以决策树为基函数的提升方法称为提升树,boosting tree.对分类问题的决策树是二叉分类树,对回归问题的决策树是二叉回归 ...