Compare commits
2 Commits
e7bc9882e6
...
294cd72ee7
Author | SHA1 | Date |
---|---|---|
dvdrw | 294cd72ee7 | |
dvdrw | 3827be61ac |
8
Makefile
8
Makefile
|
@ -19,11 +19,15 @@ bin/raytracer: $(OBJ_FILES)
|
||||||
@mkdir -p $(OBJ_DIR)
|
@mkdir -p $(OBJ_DIR)
|
||||||
$(CXX) $(CXXFLAGS) -o $@ $^
|
$(CXX) $(CXXFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
.PHONY: randsampl
|
||||||
|
randsampl: CXXFLAGS += -DRANDOM_SAMPLING
|
||||||
|
randsampl: bin/raytracer
|
||||||
|
|
||||||
.PHONY: debug
|
.PHONY: debug
|
||||||
debug: CXXFLAGS += -O0 -g
|
debug: CXXFLAGS += -O0 -g
|
||||||
debug: clean bin/raytracer
|
debug: clean bin/raytracer
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
$(RM) -r obj/*.o
|
$(RM) obj/*.o
|
||||||
$(RM) bin/*
|
$(RM) bin/raytracer
|
||||||
|
|
1
README
1
README
|
@ -9,6 +9,7 @@ The raytracer implements the following:
|
||||||
- IOR-based refraction
|
- IOR-based refraction
|
||||||
- Cook-Torrance BRDF (a few other models are left in the code)
|
- Cook-Torrance BRDF (a few other models are left in the code)
|
||||||
- Primitive object materials
|
- Primitive object materials
|
||||||
|
- Random sampling (build with `make randsampl' to add fireflies :)
|
||||||
|
|
||||||
You can move around with WASD and SPC/Z; zoom with I/O, change the exposure with
|
You can move around with WASD and SPC/Z; zoom with I/O, change the exposure with
|
||||||
+/-, and quit with Q.
|
+/-, and quit with Q.
|
||||||
|
|
15
src/main.cpp
15
src/main.cpp
|
@ -11,8 +11,8 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
static std::vector<Renderable*> lights {
|
static std::vector<Renderable*> lights {
|
||||||
new Light(v3{0, 0, 19}, 2, v3{1, 1, 1}),
|
new Light(v3{0, 0, 19}, 2, v3{2, 1, 1}),
|
||||||
new Light(v3{-7, 15, 0}, 2, v3{1, 1, 1}),
|
new Light(v3{-7, 15, 0}, 2, v3{1, 2, 2}),
|
||||||
new Light(v3{17, -9, 16}, 2, v3{1, 1, 1}),
|
new Light(v3{17, -9, 16}, 2, v3{1, 1, 1}),
|
||||||
|
|
||||||
// new Light(v3{0, 0, 19}, 2, v3{0.8, 0.8, 0.9}),
|
// new Light(v3{0, 0, 19}, 2, v3{0.8, 0.8, 0.9}),
|
||||||
|
@ -22,17 +22,17 @@ static std::vector<Renderable*> lights {
|
||||||
|
|
||||||
static const Material PLANE_MAT = {
|
static const Material PLANE_MAT = {
|
||||||
.specular = 0.12,
|
.specular = 0.12,
|
||||||
.roughness = 0.55,
|
.roughness = 0.75,
|
||||||
.ior = 2,
|
.ior = 2,
|
||||||
.transparency = 0,
|
.transparency = 0,
|
||||||
.colour = {1, 1, 1},
|
.colour = {1, 0, 1},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const Material SPHERE_MAT_TRANS = {
|
static const Material SPHERE_MAT_TRANS = {
|
||||||
.specular = 0.85,
|
.specular = 0.85,
|
||||||
.roughness = 0.5,
|
.roughness = 0.5,
|
||||||
.ior = 1.2,
|
.ior = 1.2,
|
||||||
.transparency = 0.95,
|
.transparency = 0.75,
|
||||||
.colour = {0, 1, 0},
|
.colour = {0, 1, 0},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -60,8 +60,6 @@ static std::vector<Renderable*> objects
|
||||||
|
|
||||||
static std::vector<Renderable*> scene;
|
static std::vector<Renderable*> scene;
|
||||||
|
|
||||||
// static constexpr int W = 294*2, H = 82*2;
|
|
||||||
// static constexpr int W = 2 * 640 * 2.9 * 1.8, H = 2 * 480 * 1.5 * 2.5;
|
|
||||||
static constexpr int W = 2*80, H = 2*24;
|
static constexpr int W = 2*80, H = 2*24;
|
||||||
static constexpr choice_t ASPECT_RATIO = W/(H * 1.9);
|
static constexpr choice_t ASPECT_RATIO = W/(H * 1.9);
|
||||||
|
|
||||||
|
@ -152,7 +150,8 @@ int main()
|
||||||
camera.zoom /= 1.015;
|
camera.zoom /= 1.015;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
printf("pos: " V3_FMT "\nrot: " V3_FMT, V3_ARG(camera.pos), V3_ARG(camera.rotation));
|
printf("pos: " V3_FMT, V3_ARG(camera.pos));
|
||||||
|
printf("\nrot: " V3_FMT, V3_ARG(camera.rotation));
|
||||||
break;
|
break;
|
||||||
case '\n':
|
case '\n':
|
||||||
case 'q':
|
case 'q':
|
||||||
|
|
102
src/raytrace.cpp
102
src/raytrace.cpp
|
@ -1,7 +1,36 @@
|
||||||
#include "../include/raytrace.hpp"
|
#include "../include/raytrace.hpp"
|
||||||
#include "../include/objects.hpp"
|
#include "../include/objects.hpp"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
#ifdef RANDOM_SAMPLING
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RANDOM_SAMPLING
|
||||||
|
#define MAX(l, r) ((l) < (r)) ? (r) : (l)
|
||||||
|
#define MIN(l, r) ((r) < (l)) ? (r) : (l)
|
||||||
|
|
||||||
|
static inline v3 generate_normal(const v3 &v)
|
||||||
|
{
|
||||||
|
struct h {
|
||||||
|
choice_t x;
|
||||||
|
unsigned n;
|
||||||
|
bool operator<(const h& r) { return x < r.x; }
|
||||||
|
};
|
||||||
|
|
||||||
|
h one{v.x, 1}, two{v.y, 2}, three{v.z, 3};
|
||||||
|
auto max = MAX(one, MAX(two, three));
|
||||||
|
auto min = MIN(one, MAX(two, three));
|
||||||
|
unsigned middle = 6 - max.n - min.n;
|
||||||
|
|
||||||
|
v3 normal;
|
||||||
|
normal.c[max.n] = normal.c[middle];
|
||||||
|
normal.c[middle] = -max.x;
|
||||||
|
normal.c[min.n] = 0;
|
||||||
|
|
||||||
|
return normal;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
Renderable::Renderable(const Material& specs) : specs(specs) {}
|
Renderable::Renderable(const Material& specs) : specs(specs) {}
|
||||||
|
|
||||||
|
@ -33,6 +62,12 @@ Renderable* shoot_ray_into_objects(const v3& eye, const v3& dir, const std::vect
|
||||||
return hit_object;
|
return hit_object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef RANDOM_SAMPLING
|
||||||
|
std::random_device rd;
|
||||||
|
std::mt19937 gen(rd());
|
||||||
|
std::uniform_real_distribution<> dis(0.0, 1.0);
|
||||||
|
#endif
|
||||||
|
|
||||||
v3 ray_trace(const v3& eye, const v3& dir,
|
v3 ray_trace(const v3& eye, const v3& dir,
|
||||||
const std::vector<Renderable*>& scene,
|
const std::vector<Renderable*>& scene,
|
||||||
const std::vector<Renderable*>& objects,
|
const std::vector<Renderable*>& objects,
|
||||||
|
@ -56,7 +91,6 @@ v3 ray_trace(const v3& eye, const v3& dir,
|
||||||
colour += ((Light*)hit_obj)->specs.colour * 8 * kDistance;
|
colour += ((Light*)hit_obj)->specs.colour * 8 * kDistance;
|
||||||
if(depth > 0) colour += ray_trace(eye, dir, scene, objects, lights, depth - 1, l) * (1 - kDistance);
|
if(depth > 0) colour += ray_trace(eye, dir, scene, objects, lights, depth - 1, l) * (1 - kDistance);
|
||||||
} else if (hit_type > 0) {
|
} else if (hit_type > 0) {
|
||||||
// Figure out which lights are visible from the hit location
|
|
||||||
choice_t dist;
|
choice_t dist;
|
||||||
v3 loc, normal;
|
v3 loc, normal;
|
||||||
v3 light_dir;
|
v3 light_dir;
|
||||||
|
@ -64,22 +98,47 @@ v3 ray_trace(const v3& eye, const v3& dir,
|
||||||
|
|
||||||
Light *l = nullptr;
|
Light *l = nullptr;
|
||||||
|
|
||||||
|
// Figure out which lights are visible from the hit location
|
||||||
for (auto* _l : lights) {
|
for (auto* _l : lights) {
|
||||||
l = (Light *)_l;
|
l = (Light *)_l;
|
||||||
const v3 to_light = l->o - hit_loc;
|
const v3 to_light = l->o - hit_loc;
|
||||||
light_dir = to_light.norm();
|
light_dir = to_light.norm();
|
||||||
dist = to_light.len();
|
dist = to_light.len();
|
||||||
shoot_ray_into_objects(hit_loc, light_dir, objects,
|
|
||||||
dist, loc, normal, type, hit_obj);
|
|
||||||
|
|
||||||
// We hit the light directly: shade the pixel.
|
v3 sample_dir = light_dir;
|
||||||
if (type == -1) {
|
#ifndef RANDOM_SAMPLING
|
||||||
const choice_t kDistance = to_light.lensquared() / 1000;
|
constexpr const int SAMPLE_COUNT = 1;
|
||||||
colour += cook_torrance(dir, hit_normal, light_dir, hit_obj->specs.specular,
|
#endif
|
||||||
hit_obj->specs.roughness, hit_obj->specs.ior,
|
|
||||||
hit_obj->specs.colour, l->specs.colour)
|
#ifdef RANDOM_SAMPLING
|
||||||
* (1 - hit_obj->specs.transparency) / kDistance;
|
v3 disc_n1 = generate_normal(light_dir).norm();
|
||||||
|
v3 disc_n2 = disc_n1.cross(light_dir);
|
||||||
|
choice_t cone_angle = asin(l->r / sqrt(l->r*l->r + dist*dist));
|
||||||
|
|
||||||
|
constexpr const int SAMPLE_COUNT = 5;
|
||||||
|
|
||||||
|
for(int i = 0; i < SAMPLE_COUNT; ++i) {
|
||||||
|
choice_t phi = dis(gen) * 2 * M_PI;
|
||||||
|
choice_t r = sqrt(dis(gen)) * l->r;
|
||||||
|
|
||||||
|
sample_dir = (((disc_n1 * cos(phi) + disc_n2 * sin(phi)) * r) + to_light).norm();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
shoot_ray_into_objects(hit_loc, sample_dir, objects,
|
||||||
|
dist, loc, normal, type, hit_obj);
|
||||||
|
|
||||||
|
// We hit the light: shade the pixel.
|
||||||
|
if (type == -1) {
|
||||||
|
const choice_t kDistance = to_light.lensquared() / 1000;
|
||||||
|
colour += cook_torrance(dir, hit_normal, light_dir, hit_obj->specs.specular,
|
||||||
|
hit_obj->specs.roughness, hit_obj->specs.ior,
|
||||||
|
hit_obj->specs.colour, l->specs.colour)
|
||||||
|
* (1 - hit_obj->specs.transparency) / (kDistance * SAMPLE_COUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef RANDOM_SAMPLING
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the colour from the reflection, if we have enough depth
|
// Add the colour from the reflection, if we have enough depth
|
||||||
|
@ -99,17 +158,18 @@ v3 ray_trace(const v3& eye, const v3& dir,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Random sample
|
|
||||||
// std::random_device rd;
|
#ifdef RANDOM_SAMPLING
|
||||||
// std::mt19937 gen(rd());
|
if(kReflectionAtt > 1e-4 && depth > 0) {
|
||||||
// std::uniform_real_distribution<> dis(0.0, 1.0);
|
const v3 y = hit_normal.cross(dir);
|
||||||
// const v3 y = hit_normal.cross(dir);
|
for(int i = 0; i < 3; ++i) {
|
||||||
// for(int i = 0; i < 2; ++i) {
|
const v3 sample_dir = (hit_normal + dir * dis(gen) + y * dis(gen)).norm();
|
||||||
// const v3 sample_dir = (hit_normal + dir * dis(gen) + y * dis(gen)).norm();
|
const v3 hit_colour = ray_trace(hit_loc, sample_dir, scene, objects, lights, 0, hit_obj, &dist);
|
||||||
// choice_t dist = 1;
|
colour += hit_colour * kReflectionAtt / 3;
|
||||||
// const v3 hit_colour = ray_trace(hit_loc, sample_dir, scene, objects, lights, 0, hit_obj, &dist);
|
}
|
||||||
// colour += hit_colour / (dist * dist);
|
}
|
||||||
// }
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return colour;
|
return colour;
|
||||||
|
|
Loading…
Reference in New Issue