RayTracinginOneWeekend (中⽂翻译)
⽂章⽬录
1. 写在前⾯
2. Output an Image (输出⼀张图⽚)
2.1 The PPM Image Format (ppm 图⽚格式)
⾸先介绍⼀下
格式,我们将使⽤它来存储图⽚的信息,因为它⾮常简单。
我们可以写⼀个程序来⽣成这样的⽂件。
#include <iostream>
using std ::cin ;
using std ::cout ;
int main () {
const int image_width = 256;
const int image_height = 256;
cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";
for (int j = image_height - 1; j >= 0; --j ) {
for (int i = 0; i < image_width ; ++i ) {
double r = double (i ) / (image_width - 1);
double g = double (j ) / (image_height - 1);
double b = 0.25;
int ir = static_cast <int >(255.999 * r );
int ig = static_cast <int >(255.999 * g );
int ib = static_cast <int >(255.999 * b );
cout << ir << ' ' << ig << ' ' << ib << '\n';
}
}
}
像素按照从左⾄右、从上⾄下的顺序打印,由于计算出的在之间,所以输出时应当将它们扩展⾄。
2.2 Creating an Image File (创建图⽚⽂件)
编译运⾏后,在项⽬⽂件夹下到对应的
⽂件:
通过命令⾏运⾏并将其输出重定向到⽂件中:
通过查看
:
3. The vec3 Class (vec3类)
⼏乎所有图形程序都有⼀些⽤于存储⼏何⽮量和颜⾊的类。 在许多系统中,这些向量是(加上⼏何的齐次坐标,⽽加上颜⾊的透明通道)。 就我们的⽬的⽽⾔,就⾜够了。 我们将对颜⾊,位置,⽅向,偏移量等使⽤相同的类。
PPM C ++(main .cc )r 、g 、b [0,1][0,255]exe XnV iew image .ppm 4D 3D RGB alpha 3D vec 3
3.1 Variables and Methods (变量和⽅法)
vec3.h
头⽂件的第⼀部分。
#ifndef VEC3_H
#define VEC3_H
#include<cmath>
#include<iostream>
using std::sqrt;
class vec3 {
public:
//构造函数
vec3():e{0,0,0}{}
vec3(double e0,double e1,double e2):e{ e0, e1, e2 }{}
/
/坐标
double x()const{return e[0];}
double y()const{return e[1];}
double z()const{return e[2];}
//运算符
vec3 operator-()const{return vec3(-e[0],-e[1],-e[2]);} double operator[](int i)const{return e[i];}
double&operator[](int i){return e[i];}
vec3&operator+=(const vec3& v){
e[0]+= v.e[0];
e[1]+= v.e[1];
e[2]+= v.e[2];
return*this;
}
vec3&operator*=(const double t){
e[0]*= t;
e[1]*= t;
e[2]*= t;
return*this;
}
vec3&operator/=(const double t){
return*this*=1/ t;
}
/
/长度相关
double length()const{
return sqrt(length_squared());
}
double length_squared()const{
return e[0]* e[0]+ e[1]* e[1]+ e[2]* e[2];
}
public:
double e[3];
};
using point3 = vec3;//3D point
using color = vec3;//RGB color
3.2 vec3 Utility Functions (vec3实⽤函数)头⽂件的第⼆部分。
width的意思中文翻译// vec3 Utility Functions
inline std ::ostream & operator <<(std ::ostream & out , const vec3& v ) {
return out << v .e [0] << ' ' << v .e [1] << ' ' << v .e [2];
}
inline vec3 operator +(const vec3& u , const vec3& v ) {
return vec3(u .e [0] + v .e [0], u .e [1] + v .e [1], u .e [2] + v .e [2]);
}
inline vec3 operator -(const vec3& u , const vec3& v ) {
return vec3(u .e [0] - v .e [0], u .e [1] - v .e [1], u .e [2] - v .e [2]);
}
inline vec3 operator *(const vec3& u , const vec3& v ) {
return vec3(u .e [0] * v .e [0], u .e [1] * v .e [1], u .e [2] * v .e [2]);
}
inline vec3 operator *(double t , const vec3& v ) {
return vec3(t * v .e [0], t * v .e [1], t * v .e [2]);
}
inline vec3 operator *(const vec3& v , double t ) {
return t * v ;
}
inline vec3 operator /(const vec3& v , double t ) {
return (1 / t ) * v ;
}
//数量积
inline double dot (const vec3& u , const vec3& v ) {
return u .e [0] * v .e [0] + u .e [1] * v .e [1] + u .e [2] * v .e [2];
}
//叉乘
inline vec3 cross (const vec3& u , const vec3& v ) {
return vec3(u .e [1] * v .e [2] - u .e [2] * v .e [1],
u .e [2] * v .e [0] - u .e [0] * v .e [2],
u .e [0] * v .e [1] - u .e [1] * v .e [0]);
}
inline vec3 unit_vector (const vec3& v ) {
return v / v .length ();
}
3.3 Color Utility Functions (color 实⽤函数)
使⽤新的类,我们将创建⼀个函数,将单个像素的颜⾊写到标准输出流中。
#ifndef COLOR_H
#define COLOR_H
#include "vec3.h"
#include <iostream>
void write_color (std ::ostream & out , color pixel_color ) {
/
/写下每个颜⾊分量转换后的值[0,255]
out << static_cast <int >(255.999 * pixel_color .x ()) << ' '
<< static_cast <int >(255.999 * pixel_color .y ()) << ' '
<< static_cast <int >(255.999 * pixel_color .z ()) << '\n';
}
#endif // !COLOR_H
那么可以将修改如下:
vec 3color .h main .cc
using std ::cout ;
int main () {
const int image_width = 256;
const int image_height = 256;
cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";
for (int j = image_height - 1; j >= 0; --j ) {
for (int i = 0; i < image_width ; ++i ) {
double r = double (i ) / (image_width - 1);
double g = double (j ) / (image_height - 1);
double b = 0.25;
color pixel_color (r , g , b );
write_color (cout , pixel_color );
}
}
}
4. Rays, a Simple Camera, and Background (光、摄像机、背景)
4.1 The ray Class (光线类)
所有的光线追踪器都以类为基础,它还包含颜⾊(沿着光所能看到的颜⾊)。我们可以把光想象成函数:,是光线的起点,是光线的⽅向,
是⼀个实数,当它取不同的值时,就对应光线上不同的点。
#ifndef RAY_H
#define RAY_H
#include "vec3.h"
class ray {
public :
ray (){}
ray (const point3& origin , const vec3& direction ) :orig (origin ),dir (direction ){ }
point3 origin () const { return orig ; }
vec3 direction () const { return dir ; }
point3 at (double t ) const {
return orig + t * dir ;
}
public :
point3 orig ;
vec3 dir ;
};
#endif // !RAY_H
4.2 Sending Rays Into the Scene (在场景中添加光线)
光线追踪器的核⼼是使得光线穿过每个像素,并计算沿着对应⽅向所能看到的颜⾊。这包含三个步骤:计算从眼睛到像素的光线。求出与光线相交的物体。计算出交点处的颜⾊。下⾯的例⼦中我们将渲染长⽅形图⽚,并且我们还需要设置⼀个虚拟视⼝,以使场景射线通过。视⼝的宽⾼⽐应当与渲染的图像相同。我们选择⼀个⾼度为个单位的视⼝,并将投影平⾯和投影点之间的距离设置为个单位,这被称为,注意不要与混淆。我将眼睛(摄像机)放在,同时使⽤右⼿坐标系:
下⾯修改ray P (t )=+A ˉt ∗b ˉA
ˉb ˉt ray .h :
1. 2.3.21focal length focus distance (0,0,0)main .cc :
using std ::cin ;
using std ::cout ;
//实现渐变⾊
color ray_color (const ray & r ) {
vec3 unit_direction = unit_vector (r .direction ());
auto t = 0.5 * (unit_direction .y () + 1.0);
//线性插值
return (1.0 - t ) * color (1.0, 1.0, 1.0) + t * color (0.5, 0.7, 1.0);
}
int main () {
//Image
const double aspect_ratio = 16.0 / 9.0;
const int image_width = 400;
const int image_height = static_cast <int >(image_width / aspect_ratio );
/
/Camera
double viewport_height = 2.0;
double viewport_width = aspect_ratio * viewport_height ;
double focal_length = 1.0;
point3 origin = point3(0, 0, 0);
vec3 horizontal = vec3(viewport_width , 0, 0);
vec3 vertical = vec3(0, viewport_height , 0);
//视⼝左下⾓的坐标
point3 lower_left_corner = origin - horizontal / 2 - vertical / 2 - vec3(0, 0, focal_length );
//Render
cout << "P3\n" << image_width << " " << image_height << "\n255\n";
for (int j = image_height - 1; j >= 0; --j ) {
for (int i = 0; i < image_width ; ++i ) {
double u = double (i ) / (image_width - 1);
double v = double (j ) / (image_height - 1);
ray r (origin , lower_left_corner + u * horizontal + v * vertical - origin );
color pixel_color = ray_color (r );
write_color (cout , pixel_color );
}
}
}
中间计算的部分可能有点难懂,其实就是计算视⼝左下⾓的坐标,建议结合上⾯的图理解。其实实现了渐变⾊效果,经过转换把的范围限定在
内,那么套公式就好了(线性插值):
查看⽣成的
⽂件,应该如下图所⽰:
5. Adding a Sphere (添加球体)
现在我们准备给场景添加⼀个球体。
5.1 Ray-Sphere Intersection (光线球体求交
)
上⾯是球体求交的推导过程,⽐较简单就不多解释了。可以看到我们最后得到了⼀个⼀元⼆次⽅程,那么利⽤判别式和求根公式,很容易计
算出交点。
5.2 Creating Our First Raytraced Image (第⼀个光追图像)lower _left _corner ray _color t [0,1]ppm
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论