今天简单的学习一下相关类的定义和作用
Vec3类
图形程序中需要一些用于存储几何向量和颜色的类,这里的话我们设置一个最简单的,只需要三个坐标就够了。我们使用相同的类vec3来表示颜色、位置、方向、偏移。所以我们会为这个类声明另外两个别名point3和color,但是要注意,不要将一个point3添加到一个color中
我们定义一个类文件:
#ifndef RENDER_C___VEC3_H
#define RENDER_C___VEC3_H
#include <cmath>
#include <iostream>
// 向量类
class vec3 {
public:
double e[3];
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 {-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*=(double t){
e[0] *= t;
e[1] *= t;
e[2] *= t;
return *this;
}
vec3& operator/=(double t){
return *this *= 1/t;
}
double length_squared() const{
return e[0]*e[0]+e[1]*e[1]+e[2]*e[2];
}
double length() const {
return std::sqrt(length_squared());
}
};
// 设置别名
using point3 = vec3;
// 设置内联函数
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 {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 {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 {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 {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 {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 uint_vector(const vec3& v){
return v/v.length();
}
#endif //RENDER_C___VEC3_H
其中大量应用了函数的重载,不过对着《c++ primer plus》还是看的差不多了。
这里的小数我们使用了double 数据类型,因为它更加的准确,不过还是以自己使用的机器为主,看你内存空间咯
vec3类在颜色中的应用
基于vec3类,定义一个color.h,并向里面定义一个写入像素的函数
#ifndef RENDER_C___COLOR_H
#define RENDER_C___COLOR_H
#include "vec3.h"
using color = vec3;
void write_color(std::ostream& out,const color& pixel_color){
auto r = pixel_color.x();
auto g = pixel_color.y();
auto b = pixel_color.z();
int rbyte = int (255.999 * r);
int gbyte = int (255.999 * g);
int bbyte = int (255.999 * b);
out << rbyte << ' ' << gbyte << ' ' << bbyte << '\n';
}
#endif //RENDER_C___COLOR_H
现在我们可以用我们定义的类去实现我们昨天手搓出来的图片了
#include "color.h"
#include "vec3.h"
#include <iostream>
int main(){
int image_width = 256;
int image_height = 256;
std::cout << "P3\n" << image_width << ' ' << image_height << "\n255\n";
for (int j=0;j<image_height;j++){
std::clog << "\rScanlines remaining: "<< (image_height-j) << '\r' << std::flush;
for(int i =0;i<image_width;i++){
auto pixel_color = color(double(i)/(image_width-1),double(j)/(image_height-1),0);
write_color(std::cout,pixel_color);
}
}
std::clog << "\rDone\n";
}
虽然没有节省多少内容,但是在后续的过程中,这个简便性会慢慢体现出来。
基于vec3实现射线类
我们需要一个光线类,来实现对光线的计算。我们可以用函数ray::at(t)表示
#ifndef RENDER_C___RAY_H
#define RENDER_C___RAY_H
#include "vec3.h"
class ray{
public:
ray(){}
ray(const point3& origin,const vec3& direction): orig(origin),dir(direction){}
const point3& origin() const {return orig;}
const vec3& direction() const {return dir;}
point3 at(double t) const{
return orig + t*dir;
}
private:
point3 orig;
vec3 dir;
};
#endif //RENDER_C___RAY_H
这里将射线的起点和方向进行了封装,只能通过接口访问以确保程序的完整与安全
现在我们接下来要用到几个类就设置完成啦