2013-09-10 16:28:32 -07:00
|
|
|
/* scene.c
|
|
|
|
*
|
|
|
|
* Definition of Scene-related functions.
|
|
|
|
*
|
|
|
|
* Eryn Wells <eryn@erynwells.me>
|
|
|
|
*/
|
|
|
|
|
2013-09-12 09:10:22 -07:00
|
|
|
#include <chrono>
|
2013-09-10 16:28:32 -07:00
|
|
|
#include <cmath>
|
2013-09-10 21:04:56 -07:00
|
|
|
#include <cstdio>
|
|
|
|
|
2013-09-10 16:28:32 -07:00
|
|
|
#include "basics.h"
|
2013-09-11 10:35:03 -07:00
|
|
|
#include "light.h"
|
2013-09-10 16:28:32 -07:00
|
|
|
#include "object.h"
|
|
|
|
#include "scene.h"
|
2013-09-10 21:04:56 -07:00
|
|
|
#include "writer.h"
|
2013-09-10 16:28:32 -07:00
|
|
|
|
|
|
|
|
|
|
|
Scene::Scene()
|
2013-09-10 21:04:56 -07:00
|
|
|
: width(640), height(480),
|
2013-09-11 10:33:16 -07:00
|
|
|
max_depth(5),
|
2013-09-12 09:10:22 -07:00
|
|
|
nrays(0),
|
2013-09-10 16:28:32 -07:00
|
|
|
pixels(NULL)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
Scene::~Scene()
|
|
|
|
{
|
|
|
|
if (pixels != NULL) {
|
|
|
|
delete[] pixels;
|
|
|
|
_is_rendered = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
Scene::is_rendered()
|
|
|
|
const
|
|
|
|
{
|
|
|
|
return _is_rendered;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-10 21:04:56 -07:00
|
|
|
int
|
|
|
|
Scene::get_width()
|
|
|
|
const
|
|
|
|
{
|
|
|
|
return width;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
Scene::get_height()
|
|
|
|
const
|
|
|
|
{
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const Color *
|
|
|
|
Scene::get_pixels()
|
|
|
|
const
|
|
|
|
{
|
|
|
|
return pixels;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-10 16:28:32 -07:00
|
|
|
/*
|
|
|
|
* scene_load --
|
|
|
|
*
|
|
|
|
* Load scene objects into this Scene from the given file.
|
|
|
|
*/
|
|
|
|
void
|
2013-09-10 21:04:56 -07:00
|
|
|
Scene::read(const std::string &filename)
|
2013-09-10 16:28:32 -07:00
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* scene_save --
|
|
|
|
*
|
|
|
|
* Write a rendered scene to the given file.
|
|
|
|
*/
|
|
|
|
void
|
2013-09-10 21:04:56 -07:00
|
|
|
Scene::write(Writer &writer, const std::string &filename)
|
|
|
|
{
|
|
|
|
writer.write_scene(*this, filename);
|
|
|
|
}
|
2013-09-10 16:28:32 -07:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Scene::render --
|
|
|
|
*
|
|
|
|
* Render the given Scene.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
Scene::render()
|
|
|
|
{
|
2013-09-12 09:10:22 -07:00
|
|
|
std::chrono::time_point<std::chrono::system_clock> start, end;
|
|
|
|
start = std::chrono::system_clock::now();
|
|
|
|
|
2013-09-10 16:28:32 -07:00
|
|
|
pixels = new Color[width * height];
|
|
|
|
|
|
|
|
Ray primary_ray;
|
|
|
|
Vector3 o, d;
|
|
|
|
for (int y = 0; y < height; y++) {
|
|
|
|
for (int x = 0; x < width; x++) {
|
|
|
|
// Assemble a ray and trace it.
|
|
|
|
o = Vector3(x, y, -1000);
|
|
|
|
d = Vector3(0, 0, 1);
|
|
|
|
d.normalize();
|
|
|
|
primary_ray = Ray(o, d);
|
2013-09-10 21:04:56 -07:00
|
|
|
Color c = trace_ray(primary_ray, 0);
|
|
|
|
pixels[y * width + x] = c;
|
2013-09-10 16:28:32 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-12 09:10:22 -07:00
|
|
|
end = std::chrono::system_clock::now();
|
|
|
|
std::chrono::duration<float> seconds = end - start;
|
|
|
|
|
2013-09-10 16:28:32 -07:00
|
|
|
_is_rendered = true;
|
2013-09-12 09:10:22 -07:00
|
|
|
printf("Scene rendered. %d rays traced in %f seconds.\n", nrays, seconds.count());
|
2013-09-10 16:28:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-10 21:49:01 -07:00
|
|
|
/*
|
|
|
|
* Scene::add_shape --
|
|
|
|
*
|
|
|
|
* Add a shape to the scene.
|
|
|
|
*/
|
2013-09-10 16:28:32 -07:00
|
|
|
void
|
|
|
|
Scene::add_shape(Shape *shape)
|
|
|
|
{
|
|
|
|
shapes.push_back(shape);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-10 21:49:01 -07:00
|
|
|
/*
|
|
|
|
* Scene::add_light --
|
|
|
|
*
|
|
|
|
* Add a light to the scene.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
Scene::add_light(Light *light)
|
|
|
|
{
|
|
|
|
lights.push_back(light);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Scene::trace_ray --
|
|
|
|
*
|
|
|
|
* Trace the given ray through the scene, recursing until depth has been reached.
|
|
|
|
*/
|
2013-09-10 16:28:32 -07:00
|
|
|
Color
|
|
|
|
Scene::trace_ray(const Ray &ray, const int depth)
|
|
|
|
{
|
|
|
|
Shape *intersected_shape = NULL;
|
|
|
|
float *t = NULL;
|
|
|
|
float nearest_t = INFINITY;
|
|
|
|
int nints;
|
2013-09-11 10:35:03 -07:00
|
|
|
|
2013-09-12 09:10:22 -07:00
|
|
|
// Keep stats.
|
|
|
|
nrays++;
|
|
|
|
|
2013-09-11 10:35:03 -07:00
|
|
|
// Find intersections of this ray with objects in the scene.
|
2013-09-10 16:28:32 -07:00
|
|
|
for (Shape *s : shapes) {
|
|
|
|
nints = s->does_intersect(ray, &t);
|
|
|
|
if (nints > 0) {
|
|
|
|
for (int i = 0; i < nints; i++) {
|
|
|
|
if (t[i] < nearest_t) {
|
|
|
|
intersected_shape = s;
|
|
|
|
nearest_t = t[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
delete[] t;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there was no intersection, return black.
|
2013-09-11 10:33:56 -07:00
|
|
|
if (intersected_shape == NULL) {
|
2013-09-10 21:04:56 -07:00
|
|
|
return Color::Black;
|
2013-09-10 16:28:32 -07:00
|
|
|
}
|
|
|
|
|
2013-09-11 22:03:50 -07:00
|
|
|
Color out_color = intersected_shape->get_material().get_color();
|
|
|
|
|
|
|
|
Vector3 intersection = ray.parameterize(nearest_t);
|
|
|
|
Vector3 normal = intersected_shape->compute_normal(intersection);
|
|
|
|
|
|
|
|
for (Light *l : lights) {
|
2013-09-11 22:11:56 -07:00
|
|
|
Vector3 light_direction = (intersection - l->get_origin()).normalize();
|
2013-09-11 22:03:50 -07:00
|
|
|
float ldotn = light_direction.dot(normal);
|
|
|
|
out_color.red *= ((ldotn >= 0.0) ? ldotn : 0.0) * l->get_intensity();
|
|
|
|
out_color.green *= ((ldotn >= 0.0) ? ldotn : 0.0) * l->get_intensity();
|
|
|
|
out_color.blue *= ((ldotn >= 0.0) ? ldotn : 0.0) * l->get_intensity();
|
|
|
|
}
|
|
|
|
|
|
|
|
return out_color;
|
2013-09-10 16:28:32 -07:00
|
|
|
}
|