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小时内删除。