【图形学】Ray Tracing in a Weekend [2]

1.光线追踪

实现类:vec3,sphere(球体),ray(射线,由射线起始点+射线方向向量组成)

camera.h hitable.h hitable_list.h

ray.cpp + ray.h

sphere.h

vec3.h + vec3.cpp

图显示工具:ffplay.exe

sphere.h

#ifndef SPHEREH
#define SPHEREH
#include "hitable.h"
class sphere: public hitable {
    public:
    sphere() {}
    sphere(vec3 cen, float r): center(cen), radius(r) {}
    virtual bool hit(const ray& r, float tmin, float tmax,
    hit_record& rec) const;
    vec3 center;
    float radius;
};

bool sphere::hit(const ray& r, float t_min, float t_max, hit_record& rec) const {
    vec3 oc = r.origin() - center;
    float a = dot(r.direction(), r.direction());
    float b = dot(oc, r.direction());
    float c = dot(oc, oc) - radius * radius;
    float discriminant = b * b - a * c;
    if (discriminant > 0) {
        float temp = (-b - sqrt(b * b - a * c)) / a;
        if (temp < t_max && temp > t_min) {
            rec.t = temp;
            rec.p = r.point_at_parameter(rec.t);
            rec.normal = (rec.p - center) / radius;
            return true;
        }
        temp = (-b + sqrt(b * b - a * c)) / a;
        if (temp < t_max && temp > t_min) {
            rec.t = temp;
            rec.p = r.point_at_parameter(rec.t);
            rec.normal = (rec.p - center) / radius;
            return true;
        }
    }
    return false;
}
#endif

 

 

着色消除锯齿

 

增加光照反射

vec3 color(const ray& r, hitable* world) {
    hit_record rec;
    if (world->hit(r, 0.001, FLT_MAX, rec)) {
        vec3 rnd = random_in_unit_shpere();
        vec3 target = rec.p + rec.normal + rnd;
        // printf("%f %f %f\n", rnd[0], rnd[1], rnd[2]);
        return 0.5 * color(ray(rec.p, target - rec.p), world);
    }
    else {
        vec3 unit_direction = unit_vector(r.direction());
        float t = 0.5 * (unit_direction.y() + 1.0);
        return (1.0 - t) * vec3(1.0, 1.0, 1.0) + t * vec3(0.5, 0.7, 1.0);
    }
}

 

 

 

 

增加纹理

#ifdef MATERIAL_H
#define MATERIAL_H
#include "ray.h"
#include "hitable.h"


vec3 reflect(const vec3& v, const vec3& n) {
    return v - 2 * dot(v, n) * n;
}

class material {
    public:
    virtual bool scatter(const ray& r_in, const hit_record& rec,
        vec3& attenuation, ray& scattered) const = 0;
};

class lambertian: public material {
public:
    lambertian(const vec3& a):albedo(a) {}
    virtual bool scatter(const ray& r_in, const hit_record& rec,
        vec3& attenuation, ray& scattered)const {
        vec3 target = rec.p + rec.normal + random_in_unit_sphere();
        scattered = ray(rec.p, target - rec.p);
        attenuation = albedo;
        return true;
    }
    vec3 albedo;
};

class metal: public material {
public:
    metal(const vec3& a): albedo(a) {}
    virtual bool scatter(const ray& r_in, const hit_record& rec,
        vec3& attenuation, ray& scattered)const {
        vec3 reflected = reflect(unit_vector(r_in.direction()), rec.normal);
        scattered = ray(rec.p, reflected);
        attenuation = albedo;
        return dot(scattered.direction(), rec.normal) > 0;
    }
    vec3 albedo;
    // float fuzz;
};

#endif

 

增加球体个数

int main() {
    int nx = 200;
    int ny = 100;
    int ns = 100;
    cout << "P3\n" << nx << " " << ny << "\n255\n";
    // vec3 lower_left_corner(-2.0, -1.0, -1.0);
    // vec3 horizontal(4.0, 0.0, 0.0);
    // vec3 vertical(0.0, 2.0, 0.0);
    // vec3 origin(0.0, 0.0, 0.0);
    hitable* list[4];
    list[0] = new sphere(vec3(0, 0, -1), 0.5, new lambertian(vec3(0.8, 0.3, 0.3)));
    list[1] = new sphere(vec3(0, -100.5, -1), 100, new lambertian(vec3(0.8, 0.8, 0.0)));
    list[2] = new sphere(vec3(1, 0, -1), 0.5, new metal(vec3(0.8, 0.6, 0.2)));
    list[3] = new sphere(vec3(-1, 0, -1), 0.5, new metal(vec3(0.8, 0.8, 0.8)));
    hitable* world = new hitable_list(list, 4);
    camera cam;
    for (int j = ny - 1; j >= 0; j--) {
        for (int i = 0; i < nx; i++) {
            vec3 col(0, 0, 0);
            for (int s = 0; s < ns; s++) {
                float u = float(i + drand48()) / float(nx);
                float v = float(j + drand48()) / float(ny);
                ray r = cam.get_ray(u, v);
                vec3 p = r.point_at_parameter(2.0);
                col += color(r, world, 0);
            }
            col /= float(ns);
            col = vec3(sqrt(col[0]), sqrt(col[1]), sqrt(col[2]));
            // cout << u << " " << v << endl;
            // vec3 col = color(r, world);
            int ir = int(255.99 * col[0]);
            int ig = int(255.99 * col[1]);
            int ib = int(255.99 * col[2]);
            cout << ir << " " << ig << " " << ib << endl;
        }
    }
    return 0;
}

 

 

带金属光泽的纹理

class metal: public material {
public:
    metal(const vec3& a, float f): albedo(a) {if (f < 1) fuzz = f; else fuzz = 1;}
    virtual bool scatter(const ray& r_in, const hit_record& rec,
        vec3& attenuation, ray& scattered)const {
        vec3 reflected = reflect(unit_vector(r_in.direction()), rec.normal);
        scattered = ray(rec.p, reflected + fuzz * random_in_unit_sphere());
        attenuation = albedo;
        return dot(scattered.direction(), rec.normal) > 0;
    }
    vec3 albedo;
    float fuzz;
};

 

9. 加入Dielectrics 折射

 

10. 视角切换

12. 随机场景scene的渲染

 

 

 

 

 

 

 

 

posted @ 2019-12-01 19:00  stackupdown  阅读(290)  评论(0编辑  收藏  举报