【Ray Tracing in One Weekend 超详解】 光线追踪1-5
一天一篇,今天来学习第7章 (散射)漫反射材质
Chapter7: Diffuse Materials
Preface
从这一章开始,我们将通过光线追踪制作一些逼真的材质。
我们将从漫射(磨砂)材料开始。
先看效果:
正文
不发光的漫射物体仅仅呈现其周围的颜色,但是它们用它们自己的固有颜色来调和这些色彩。
从漫反射表面反射的光方向是随机的,比如:如果我们将三条光线发送到一个漫反射表面,它们将各自具有不同的随机行为:
引用书上的图:
diagram 7-1
它们也可能被吸收而不是被反射。 表面越暗,光线越可能被吸收。 (这就是为什么它是黑的!)
任何随机化方向的算法都会产生看起来很粗糙的表面。 最简单的方法之一是理想的漫反射表面。
原文还提到了Lambertian发射面
我们来看一下,如何实现上述功能
图说一切:
diagram 7-2
图解
先简述一下各个原件:左黄球是以eye为中心的一个单位圆,右黄球是一个和左黄球一样的圆,至于怎么生成的,后续说
左黄球上有两个随机点,蓝紫色的s1,红紫色的s2,对应于右黄球上为s1' 和s2'
红色为视线;深绿色为反射线;三个黑球为漫反射球体,黑色只是用颜色来区分各个原件的功能,并不是黑色的漫反射球(画完才发现,黑球都把光线吸收了。。。。==!)
实现过程
步骤一:从eye发出一条视线,交球面于p点,之后我们确定随机反射方向
将右边的黄色圆部分放大:
引用书中一张图:
diagram 7-3
n为P点的单位法向量,方向向外,下面那个点是碰撞点P,找一个和点P相切的单位圆
而这个圆的圆心o的位置就等于p+n(p : eye->P),因为我们的原点就是eye,所以根据向量就可以得出位置信息
基于eye的向量和位置体系,其实方便了我们利用向量运算代替位置运算,更直观。这个自己理解下就好,不是重点。
步骤二:then, we pick a random point s from the unit randius sphere.
当我们找到这个s点之后,我们将沿着p->s的方向进行反射,但是我们如何找这个random point呢?
这个时候我们就需要用到我们的diagram 7-2了,回去看一眼那个蓝紫色点s1,做一个平行四边形,对应到s1',他们是等价的(向量只用方向和大小进行定义,不规定起始位置,所以我们能说它们等价)。
我们先在原点单位球中找一个随机点,构成一个eye->s的向量s1,然后,将s1的起点移动到o处,即s1',也就是说s1'就是我们要求的随机点,因为直接求随机点s1'的位置并不好求,所以,只能这样,其实想是很好想,但是要描述清楚就应该是这么描述。
步骤三:最后我们得到反射线的方向dir = s1' - p,s1' = o + s1, o = p + n
然后,我们来求s1:
#include <random>
#define stds std::
using namespace rt; stds mt19937 mt;
stds uniform_real_distribution<rtvar> rtrand; const rtvec random_unit_sphere()
{
rtvec p;
do
{
p = 2.0*rtvec(rtrand(mt), rtrand(mt), rtrand(mt)) - rtvec(, , );
} while (dot(p, p) >= 1.0); //rejection method
return p;
}
关于随机数生成,在上一篇讲过了,应该是靠后讲的
rtrand生成的是0~1的随机数,然后乘以2再减去1,得到的p的每一个分量均位于-1~1,其实它的范围是一个正方体,而我们要求的是球内随机点。
所以我们采用书中所述的rejection方法,拒绝非法点:如果基于原点eye找一个随机点(x,y,z)
如果x*x+y*y+z*z>=1,那么它不符合我们的需要,我们重新找。
最后,我们通过上面的代码就得到了一个球内随机点。
上述就是diagram 7-2中基于蓝紫色点进行反射的深绿色光线的反射过程
当然,还有基于红紫色的反射线,前半部分就和上面一样,所以也没有画平行四边形,关于后续反射
步骤四:将当前碰撞点P作为eye,以反射方向向量dir为视线方向进行步骤一
直到没有碰撞,为止
而且,光线没经过一次反射强度就会衰减,我们也是这么做的,我们采用的是每反射一次,衰减一半。
#define LOWPRECISION #include <fstream>
#include "intersect.h"
#include "sphere.h"
#include "intersections.h"
#include "camera.h"
#include <random>
#define stds std::
using namespace rt; stds mt19937 mt;
stds uniform_real_distribution<rtvar> rtrand; const rtvec random_unit_sphere()
{
rtvec p;
do
{
p = 2.0*rtvec(rtrand(mt), rtrand(mt), rtrand(mt)) - rtvec(, , );
} while (dot(p, p) >= 1.0);
return p;
} rtvec lerp(const ray& sight, const intersect* world)
{
hitInfo rec;
if (world->hit(sight, ., intersect::inf(), rec)) //如果没有有效碰撞点
{
rtvec target = rec._p + rec._n + random_unit_sphere(); //随机点s的最后位置
return 0.5*lerp(ray{ rec._p,target - rec._p }, world); //强度衰减,新建eye继续发射视线
}
else
{
rtvec dirUnit = sight.direction().ret_unitization();
rtvar t = 0.5*(dirUnit.y() + .);
return (. - t)*rtvec(., ., .) + t*rtvec(0.5, 0.7, 1.0);
}
} void build_7_1()
{
stds ofstream file("graph7-1.ppm");
size_t W = , H = , sample = ; if (file.is_open())
{
file << "P3\n" << W << " " << H << "\n255\n" << stds endl; intersect** list = new intersect*[];
list[] = new sphere(rtvec(, , -), 0.5);
list[] = new sphere(rtvec(, -100.5, -), );
intersect* world = new intersections(list, ); camera cma; for (int y = H - ; y >= ; --y)
for (int x = ; x < W; ++x)
{
rtvec color;
for (int cnt = ; cnt < sample; ++cnt)
{
lvgm::vec2<rtvar> para{
(rtrand(mt) + x) / W,
(rtrand(mt) + y) / H };
color += lerp(cma.get_ray(para), world);
}
color /= sample;
int r = int(255.99 * color.r());
int g = int(255.99 * color.g());
int b = int(255.99 * color.b());
file << r << " " << g << " " << b << stds endl;
}
stds cout << "complished" << stds endl;
file.close(); if (list[])delete list[];
if (list[])delete list[];
if (list)delete[] list;
if (world)delete world;
}
else
stds cerr << "open file error" << stds endl;
} int main()
{
build_7_1();
}
效果图如下:
注意球体下的阴影。 这张照片非常暗,但是我们的球体在光线每次反射时只吸收了一半的能量,因此它们是50%的反射器。
在现实生活中, 这些球体应该是浅灰色的。 其原因在于几乎所有图像观看者都假设图像是“伽马校正的”,这意味着这些0到1的值在被存储为字节之前做了一些变换。这种做法有很多好处,但就我们的目的而言,今天不讲这个,了解即可。
如果我们对我们日常的视觉做一个近似,我们可以使用“gamma 2”,即只是简单的平方根:
这样就会得到下图:
看起来更好些。
感谢您的阅读,生活愉快~
【Ray Tracing in One Weekend 超详解】 光线追踪1-5的更多相关文章
- 【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 ...
随机推荐
- Hibernate注解开发、注解创建索引
1.注解的目的 简化繁琐的ORM映射文件(*.hbm)的配置 2.JPA和hibernate的关系 JPA:java persistence API,JPA注解是JavaEE的标准和规范. 两者的关系 ...
- sync_binlog innodb_flush_log_at_trx_commit 浅析【转】
innodb_flush_log_at_trx_commit和sync_binlog 两个参数是控制MySQL 磁盘写入策略以及数据安全性的关键参数.本文从参数含义,性能,安全角度阐述两个参数为不同的 ...
- CentOS 6.5下PXE+Kickstart无人值守安装操作系统centos7.3
CentOS 6.5下PXE+Kickstart无人值守安装操作系统centos7.3 一.简介 1.1 什么是PXE PXE(Pre-boot Execution Environment,预启动执行 ...
- cacti系列(三)之cacti添加对mysql服务器主从的监控
1.配置主从同步 主服务器: 建立从服务器的复制权限账号 GRANT REPLICATION SLAVE,REPLICATION CLIENT ON *.* TO 'repluser'@'192.16 ...
- nagios系列(四)之nagios主动方式监控tcp常用的80/3306等端口监控web/syncd/mysql及url服务
nagios主动方式监控tcp服务web/syncd/mysql及url cd /usr/local/nagios/libexec/ [root@node4 libexec]# ./check_tcp ...
- nagios系列(三)之nagios被动监控模式之添加系统负载load、swap、磁盘iostat及memory内存监控详解
环境: nagios server:192.168.8.42 host_name:node4.chinasoft.com nagios client:192.168.8.41 host_name:no ...
- 通达OA批量处理没有结束但前台显示已经结束的流程
问题描述: 通达OA系统出现大量流程没有结束,系统显示结束的问题 通过查询操作系统日志,数据库日志,包括程序日志没有发现异常,通过观察发现大量的流程结束时间都是在2016-02-16 17:32:XX ...
- 转载:分布式文件系统 - FastDFS 在 CentOS 下配置安装部署(2)
原文:http://blog.mayongfa.cn/193.html 一.安装 Nginx 和 fastdfs-nginx-module 安装 Nginx 请看:从零开始学 Java - CentO ...
- Expm 9_3 无向图的双连通分量问题
[问题描述] 给定一个无向图,设计一个算法,判断该图中是否存在关节点,并划分双连通分量. package org.xiu68.exp.exp9; import java.util.Stack; p ...
- java调用monkeyrunner(亲测绝对可行)
我自己试验了下和官方的API编写不太一样,老别扭了,建议还是用Python写吧 昨天在网上查了一下一天,都是转来贴别人的,真正敲的很少,我真不知道转的大侠你们自己敲了么? 先截一段不负责任的blog图 ...