08 1月

ppm 图片格式文件

好了,经过前面两章的介绍,我们知道了,如何来判断从观察者射出的光线是否能和圆碰到。接下来我们要继续讲下去去之前,要先介绍用什么图片格式来保存我们的数据。

我们平时用到最多的格式恐怕就是jpg图了,当然搞cg的同学平时渲染会输出现在的主流格式exr,当然用maya还会有tiff。不管什么格式的图片格式他们做的事情都是保存图片信息,不同是压缩算法的不同,看哪家的格式占用空间最少,图片信息丢失最少。这些都不是我们现在要关心的,我们现在关心的哪个图片格式最容易入门,那当然是ppm格式。

为什么说他容易,因为你可以用电脑自带的记事本做一个图片,对,就是那么的容易。

现在大家打开记事本贴写以下几行。

然后另存为test.ppm。好了,一张图片创建好了。

pixelppm

ppm像素的排列顺序是从左到右,从上到下。

对了。因为我是在Linux系统下工作环境,所以linux是直接支持ppm的格式图片。

如果大家是在windows平台下面,那么要看到ppm就需要安装看图软件ACDSEE

下面我们通过一个Rgb类来输出Rgb这三个颜色通道。

注意,我在内部进行数据操作的时候R,G,B的范围是0-1,理论上是可以大于1的,但是大于1之后,人眼分辨不出,但是可能以后后期较色需要这些信息,这里我们假定是[0,1]范围
还有,我们在写入到ppm文件是,需要将R,G,B值域范围映射到[0,255]的范围。如果值大于1了,限定等于255(clamp)。

写入ppm文件

 

07 1月

你可能说要知道的知识

光 颜色 Light and Color

 

我们知道,计算机中三维模型都需要投射到二维屏幕上。那么投射到二维屏幕上的每个像素点的颜色是由谁来决定的呢。

一个物体的颜色、明暗是由场景中灯光照射到物体上和这个物体本身的材质有关。

光——是由千千万万个光子(传递电磁相互作用的基本粒子)所组成,也就是说这些粒子他们带有能量,他们会震荡,就好比声波在空气中传播一样,他们是直线传播的。.光子是从光源中发射的,太阳,就是我们身边最大的一个光源。如果一组光子打到一个物体上。那么会发生以下三种情况:被吸收,反弹,穿过。不同的材质这三个情况发生的概率是不一样的。所以,每个不同材质的物体在我们眼里他们表现的质感也是不同的。但是,有一个规则是所有材质都相同的。那就是他们遵循能量守恒的原则,设入的光子总量=吸收+反弹+穿过的光子总和。

在科学界上,我们将材料总归为两类,导体和非导体。导体:金属类。非导体:玻璃,塑料,木头。非导体,可以是透明或不透明的(如下图塑料球和玻璃球)。

同样的,材质是可以合成在一起的,比如下图的彩色球,和颜色偏深的玻璃球一样

下面我们来考虑一下漫反射,一束光照射到一个球上,为什么他会显示红色?我们简单假设一束白光是由,红,绿,蓝三种颜色光子组成,现在我们照射一个红球上,现在蓝色和绿色光被这个球所吸收(过滤)了。而红光(光子)反射到我们眼睛里面,所以我们看到的是红色。为什么我们能看到五颜六色的物体,就是因为大自然界中的光源发射能量不同(颜色不同)的光子,然后这些光子在空间中来回穿梭,有的被吸收了,有的被反弹,有的穿过了,这也就是为什么天有时候是蓝的,有时候是橘红色,太阳光被大气过滤。然后不同光子从不同物体上反射到不同角度上,到达我们眼睛就是我们所看到不同的颜色。所以说,人眼配合上人脑是非常非常牛逼的渲染器,他要处理无数个光子是我们现在电脑处理器所远远达不到的运算速度。

06 1月

从一个球开始

好了,我们定义好光线了,那么接下来我们需要拿些物体来检测了光线碰撞了,我们会介绍光线和平面交互,光线和box,光线和三角平面,光线和圆。

很多人会问,为什么不介绍复杂模型碰撞检测呢,比如说茶壶,龙。因为在三维中所有的三维模型都能用三角面组成,所以只要讲光线和三角面碰撞检测,我们就能融会贯通了。

首先我们使用圆来进行。为什么用圆来做碰撞检测呢。因为圆最简单。(为什么最简单,等以后你就知道了)

我们在初中学过圆的方程:

(x-c)²=r²

光线的方程:

p=o+t*d;  (  t>0  )

当光线和圆交互也就是有交点的时候,点p是在圆上面。得到

(p-c)²=r²;

(p-c)²-r²=0;

将光线代入:

(o+t*d-c)²-r²=0;

现在我们唯一不知道的是未知数t:

所以就变成解二元一次方程解:

d²t²+[2(o-c)d]t+(o-c)(o-c)-r²=0;

简化方程:

at²+bt+c=0;

a=d²

b=2(o-c)d

c=(o-c)(o-c)-r²

那么得到t的解是:

b_4abc

我们确定有没有解,就要判断开根号里面的值是否>0

所以,我们要判断试着个等式

d=b²-4ac;

如果,d>0,那么t有两个解,如果d=0,那么t有一个解。如果d<0则无解。我们用一张图来表示

sphere

这是第一步。因为如果我求出d>0,不等于就一定就有交互。我们还要看t的值。t值必须大于0,因为光线只会向前进,不会倒着走。

ok,求出了p的值之后,那么再将t代入p=o+t*d,我们就能知道撞击点的位置了。

Hitpos=0+t*d

现在我们来看看圆的类

以下是碰撞检测函数,

*这里来解释一下为什么t要大于0.0001而不是0,以后章节会提到,我这里简单说一下,之后为了判断这个点在不在阴影里面还要从这个点再继续射出一根shadow_ray。为了避免碰到自己本身=0的极端值,用着个方法把碰撞点往外推了一点点。

 

 

 

 

06 1月

Rays 光线

介绍光线之前,我们来讲讲场景,The World

我们的渲染器首先是在一个场景进行,这个场景会包含模型物体,灯光,摄像机,光线,这些物体都是在一个统一的世界坐标系统中。坐标原点为(0,0,0)。具体的坐标系统变换我们会在以后的章节中讨论。

光线

一根光线就是一根射线,我在年轻的时候学过射线就是从一个起点出发射向无穷远。所以,我们定义o为光线的起点,dir为光线的方向。为了能够参数化这个光线射出多远。我们用引入t这个变量。当t=0在起点。

ray

那么根据下图这个光线的表达式: p=o+td;

光线的种类又可分为:

主光线:从摄像机射出的光线

间接光线:反弹光线

阴影光线:从物体表面射出的光线是和材质有关的

灯光光线:从灯光射出的,在特定场合会用到,比如全局光。

光线定义:

 

06 1月

Vector 向量

首先的首先,我们来讲向量,向量是有方向和大小的量。在三维中是必不可少。我们一般已x,y,z来表示三个维度

Vector由分为位置向量:比如表示点的位置Positon。

和方向向量;比如表示速度Velocity。

我们在C++中这么定义

dot :点乘,我们可以用他来判断两个向量的夹角
cross: 差乘,我们可以求得垂直于两个向量所组成平面的向量
length:向量的大小
normalize: 向量的归一话,得到长度等于1的向量

我省略了一些代码,为了能保持整洁同时也不让大家过于纠结c++。

04 1月

ray tracing 简介

光线追踪的渲染技术已经被大量运用到现在的电影产业中,我们身边也出现了大量光线追踪的渲染器,arnorld,vray,houdini的mantra,maxwell等等。它出现的目的也是为了追求更真实的物理效果。
800px-Ray_trace_diagram.svg
光线追踪算法中,一个物体要被观察者(camera)看到要具备两个因素。其一,就是要有光,物体不被光照到我们是看不到,其二,就是当然要有物体,光被物体反射入观察者眼中才能被看到。所以,光线追踪算法就是计算光线和物体交互,碰撞检测的算法。
光线追踪算法分为两种:正向追踪算法和反向追踪算法。其中,正向追踪算法是大自然的光线追踪方式,即由光源发出的光经环境景物间的多次反射、透射后投射到景物表面,最终进入人眼。
反向追踪算法正好相反,它是从观察者的角度出发,只追踪那些观察者所能看见的表面投射光。就目前而言,所有3D制作软件的光线追踪算法都是采用反向追踪法,原因是这种算法能够最大程度地节省计算机的系统资源,而且不会导致渲染质量的下降。

接下来我们来介绍栅格化(Rasterization)。就是将图转化为一个个栅格组成的图象

为什么要栅格化,因为我们知道我们的电脑屏幕是由像素点组成。目前主流的像素已经1920*1080。也就是说,我们的屏幕横向有1920个像素,然后丛向有1080个像素点。

所以,我们要将三维的模型投射到屏幕上面,然后将每个像素点填充上一个相对硬的颜色,就好比一个圆是由多个网格组成。当然了,网格细分越高,显示精度也越好。

raster

光线追踪的灵魂所在就在于光线。所以,我们基于屏幕的每个像素点射出去一个光线。如果射出去的光线碰到了障碍物(模型),我们就能将这个像素点填充上相应障碍物的信息(根据灯光,物体材质)。如果什么都没碰到,那么相对因的像素就什么都不显示(背景颜色)。

现在我们知道了,每个像素到底看到了什么。然后我们通过重复的遍历屏幕上的每个点,那么一个球就出现在屏幕上了。是不是很好理解?

好了,下面我用为代码来简单介绍一下一个简单的渲染器的工作流程。

影响一个像素点颜色由三个通道来表示,R(红),G(绿),B(蓝)也就是这三个通道来表示,我们知道通过这三个颜色组合,我们可以得到所有的颜色。比如红色+蓝色=紫色。如果还不清楚的同学建议你们去看颜色构成方面的内容。

我们现在定义每个颜色通道为8位,也就是2^8。他表示范围为0-255。0表示最小值,255表示最大值。所以

黑色:0,0,0

红色:255,0,0

绿色:0,255,0

蓝色:0,0,255

白色:255,255,255

那么问题来了,如何来决定某个像素的值呢:

它由多个因素来决定的。请看下图:

我们简单来分析: 首先一束光射出去,我们打到一个物体上,

如果打到一个物体向光面上,那么我们会根据物体的材质(物体本体颜色,对光的漫反射,对其他物体的反射)来计算像素点材质。

如果打到一个背光面上,那么这就是阴影。

如果什么都没打到那么,那么他就是个背景颜色。

毕竟在光线追踪影响物体颜色的因素太多了,因为光线是在空间中不停的反弹。有直接反射,间接反射,理论上来说如果计算时间足够长,那么得到的结果就无限接近真实效果,但是时间和效果往往是矛盾的,我们如何在有限的时间中得到尽量真实的效果就是我们之后要做的。