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"
|
2014-08-02 00:28:02 -07:00
|
|
|
#include "log.hh"
|
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
|
|
|
|
2014-08-02 00:28:02 -07:00
|
|
|
#define LOG_NAME "scene"
|
|
|
|
#include "logModule.hh"
|
|
|
|
|
2014-07-20 16:54:10 -07:00
|
|
|
using namespace charles;
|
|
|
|
|
2013-09-10 16:28:32 -07:00
|
|
|
|
|
|
|
Scene::Scene()
|
2013-09-10 21:04:56 -07:00
|
|
|
: width(640), height(480),
|
2014-07-19 20:57:12 -07:00
|
|
|
mCamera(new PerspectiveCamera()),
|
2013-09-11 10:33:16 -07:00
|
|
|
max_depth(5),
|
2013-09-21 17:01:11 -07:00
|
|
|
min_weight(1e-4),
|
2013-09-13 18:25:09 -07:00
|
|
|
ambient(new AmbientLight()),
|
2013-09-13 14:15:55 -07:00
|
|
|
shapes(),
|
|
|
|
lights(),
|
2014-07-20 14:21:12 -07:00
|
|
|
mStats(),
|
2013-09-10 16:28:32 -07:00
|
|
|
pixels(NULL)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
|
|
Scene::~Scene()
|
|
|
|
{
|
2014-07-20 12:37:31 -07:00
|
|
|
mCamera.reset();
|
2014-07-16 23:32:44 -07:00
|
|
|
|
2013-09-13 14:15:55 -07:00
|
|
|
if (ambient != NULL) {
|
|
|
|
delete ambient;
|
|
|
|
}
|
|
|
|
|
|
|
|
shapes.clear();
|
|
|
|
|
|
|
|
for (PointLight *l : lights) {
|
|
|
|
delete l;
|
|
|
|
}
|
|
|
|
lights.clear();
|
|
|
|
|
2013-09-10 16:28:32 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-20 12:37:31 -07:00
|
|
|
/*
|
|
|
|
* Scene::GetCamera --
|
|
|
|
*/
|
|
|
|
Camera::Ptr
|
2014-07-19 20:57:12 -07:00
|
|
|
Scene::GetCamera()
|
|
|
|
const
|
|
|
|
{
|
|
|
|
return mCamera;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-07-20 12:37:31 -07:00
|
|
|
/*
|
|
|
|
* Scene::SetCamera --
|
|
|
|
*/
|
2014-07-19 20:57:12 -07:00
|
|
|
void
|
|
|
|
Scene::SetCamera(Camera* camera)
|
|
|
|
{
|
2014-07-20 12:37:31 -07:00
|
|
|
mCamera.reset(camera);
|
2014-07-19 20:57:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-13 18:25:09 -07:00
|
|
|
AmbientLight &
|
|
|
|
Scene::get_ambient()
|
|
|
|
const
|
|
|
|
{
|
|
|
|
return *ambient;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-10 21:04:56 -07:00
|
|
|
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()
|
|
|
|
{
|
2014-08-02 00:28:02 -07:00
|
|
|
LOG_INFO << "Rendering scene with " << shapes.size() << " objects.";
|
2014-07-22 21:40:25 -07:00
|
|
|
printf("Rendering scene with %lu objects.\n", shapes.size());
|
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++) {
|
2014-07-19 20:57:12 -07:00
|
|
|
primary_ray = mCamera->compute_primary_ray(x, width, y, height);
|
2014-07-20 14:21:12 -07:00
|
|
|
mStats.primaryRays++;
|
2013-09-21 16:45:10 -07:00
|
|
|
Color c = trace_ray(primary_ray);
|
2013-09-10 21:04:56 -07:00
|
|
|
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;
|
2014-07-20 14:21:12 -07:00
|
|
|
|
|
|
|
printf("Rendering completed in %f seconds.\n\n", seconds.count());
|
2014-08-02 00:28:02 -07:00
|
|
|
LOG_INFO << "Rendering completed in " << seconds.count() << " seconds.";
|
2014-07-20 14:21:12 -07:00
|
|
|
mStats.PrintRayTable();
|
2014-08-02 15:21:14 -07:00
|
|
|
printf("\n");
|
|
|
|
mStats.PrintIntersectionsTable();
|
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
|
2014-07-20 16:54:10 -07:00
|
|
|
Scene::add_shape(Object::Ptr shape)
|
2013-09-10 16:28:32 -07:00
|
|
|
{
|
|
|
|
shapes.push_back(shape);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-09-10 21:49:01 -07:00
|
|
|
/*
|
|
|
|
* Scene::add_light --
|
|
|
|
*
|
|
|
|
* Add a light to the scene.
|
|
|
|
*/
|
|
|
|
void
|
2013-09-13 14:12:55 -07:00
|
|
|
Scene::add_light(PointLight *light)
|
2013-09-10 21:49:01 -07:00
|
|
|
{
|
|
|
|
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
|
2013-09-21 16:45:10 -07:00
|
|
|
Scene::trace_ray(const Ray &ray,
|
|
|
|
const int depth,
|
|
|
|
const float weight)
|
2013-09-10 16:28:32 -07:00
|
|
|
{
|
2013-09-21 17:01:11 -07:00
|
|
|
if (depth >= max_depth || weight <= min_weight) {
|
2013-09-21 15:42:11 -07:00
|
|
|
return Color::Black;
|
|
|
|
}
|
|
|
|
|
2013-09-13 18:25:22 -07:00
|
|
|
Color out_color = Color::Black;
|
2014-07-20 16:54:10 -07:00
|
|
|
Object::Ptr intersected_shape;
|
|
|
|
TVector ts;
|
|
|
|
Double nearest_t = INFINITY;
|
|
|
|
|
|
|
|
ts.reserve(2);
|
2013-09-11 10:35:03 -07:00
|
|
|
|
|
|
|
// Find intersections of this ray with objects in the scene.
|
2014-07-20 16:54:10 -07:00
|
|
|
for (Object::Ptr s : shapes) {
|
|
|
|
ts.clear();
|
2014-08-02 15:21:14 -07:00
|
|
|
if (s->DoesIntersect(ray, ts, mStats)) {
|
2014-07-20 16:54:10 -07:00
|
|
|
for (Double t : ts) {
|
|
|
|
if (t < 1e-2) {
|
2013-09-21 17:02:26 -07:00
|
|
|
break;
|
|
|
|
}
|
2014-07-20 16:54:10 -07:00
|
|
|
if (t < nearest_t) {
|
2013-09-10 16:28:32 -07:00
|
|
|
intersected_shape = s;
|
2014-07-20 16:54:10 -07:00
|
|
|
nearest_t = t;
|
2013-09-10 16:28:32 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there was no intersection, return black.
|
2014-07-20 16:54:10 -07:00
|
|
|
if (!intersected_shape) {
|
2013-09-13 18:25:22 -07:00
|
|
|
return out_color;
|
2013-09-10 16:28:32 -07:00
|
|
|
}
|
|
|
|
|
2014-07-20 16:54:10 -07:00
|
|
|
Material& shape_material = intersected_shape->GetMaterial();
|
|
|
|
const Color& shape_color = shape_material.GetDiffuseColor();
|
2013-09-13 18:56:07 -07:00
|
|
|
|
2013-09-11 22:03:50 -07:00
|
|
|
Vector3 intersection = ray.parameterize(nearest_t);
|
|
|
|
Vector3 normal = intersected_shape->compute_normal(intersection);
|
2013-09-21 16:45:30 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Diffuse lighting. (Shading, etc.)
|
|
|
|
*/
|
|
|
|
|
2013-09-13 18:56:07 -07:00
|
|
|
Vector3 light_direction;
|
2014-07-20 16:54:10 -07:00
|
|
|
Double ldotn, diffuse_level, ambient_level;
|
2014-08-02 14:33:50 -07:00
|
|
|
Ray shadowRay;
|
2013-09-11 22:03:50 -07:00
|
|
|
|
2013-09-13 14:12:55 -07:00
|
|
|
for (PointLight *l : lights) {
|
2014-07-20 16:54:10 -07:00
|
|
|
light_direction = (intersection - l->GetOrigin()).normalize();
|
2013-09-13 18:56:07 -07:00
|
|
|
ldotn = light_direction.dot(normal);
|
|
|
|
|
2014-08-02 15:32:27 -07:00
|
|
|
/*
|
|
|
|
* TODO: What is this even for? Removing it makes the darker showers
|
|
|
|
* really bright.
|
|
|
|
*/
|
2013-09-13 18:56:07 -07:00
|
|
|
if (ldotn < 0) {
|
2013-09-13 18:25:22 -07:00
|
|
|
ldotn = 0.0;
|
|
|
|
}
|
2013-09-13 18:56:07 -07:00
|
|
|
|
2014-07-20 16:54:10 -07:00
|
|
|
diffuse_level = shape_material.GetDiffuseIntensity();
|
2013-09-13 18:56:07 -07:00
|
|
|
ambient_level = 1.0 - diffuse_level;
|
|
|
|
|
2014-08-02 14:30:40 -07:00
|
|
|
shadowRay = Ray(intersection, light_direction);
|
2014-07-20 16:54:10 -07:00
|
|
|
for (Object::Ptr s : shapes) {
|
2013-09-13 18:56:07 -07:00
|
|
|
if (s == intersected_shape) {
|
2014-08-02 14:30:40 -07:00
|
|
|
/* Skip the intersected shape. */
|
2013-09-13 18:56:07 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-07-20 14:21:12 -07:00
|
|
|
mStats.shadowRays++;
|
|
|
|
|
2014-08-02 14:30:40 -07:00
|
|
|
/* Figure out if we're in shadow. */
|
2014-07-20 16:54:10 -07:00
|
|
|
ts.clear();
|
2014-08-02 15:21:14 -07:00
|
|
|
if (s->DoesIntersect(shadowRay, ts, mStats)) {
|
2013-09-13 18:56:07 -07:00
|
|
|
diffuse_level = 0.0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-21 17:06:49 -07:00
|
|
|
/*
|
|
|
|
* Compute basic Lambert diffuse shading for this object.
|
|
|
|
*/
|
2013-09-13 18:56:07 -07:00
|
|
|
out_color += shape_color * ( ambient_level * ambient->compute_color_contribution()
|
|
|
|
+ diffuse_level * ldotn);
|
2013-09-11 22:03:50 -07:00
|
|
|
}
|
|
|
|
|
2013-09-21 15:42:11 -07:00
|
|
|
/*
|
|
|
|
* Specular lighting. (Reflections, etc.)
|
|
|
|
*/
|
|
|
|
|
2014-08-02 15:23:22 -07:00
|
|
|
#if 0
|
2014-07-20 16:54:10 -07:00
|
|
|
Double specular_level = shape_material.GetSpecularIntensity();
|
|
|
|
const Color& specular_color = shape_material.GetSpecularColor();
|
2013-09-21 16:45:30 -07:00
|
|
|
|
|
|
|
/*
|
2014-07-20 14:21:12 -07:00
|
|
|
* Compute the reflection ray. Computing the direction of the reflection ray
|
|
|
|
* is done by the following formula:
|
2013-09-21 16:45:30 -07:00
|
|
|
*
|
|
|
|
* d = dr - 2n(dr . n)
|
|
|
|
*
|
2014-07-20 14:21:12 -07:00
|
|
|
* where d is the direction, dr is the direction of the incoming ray, and n
|
|
|
|
* is the normal vector. Period (.) indicates the dot product.
|
2013-09-21 16:45:30 -07:00
|
|
|
*
|
2014-07-20 14:21:12 -07:00
|
|
|
* The origin of the reflection ray is the point on the surface where the
|
|
|
|
* incoming ray intersected with it.
|
2013-09-21 16:45:30 -07:00
|
|
|
*/
|
2014-07-20 14:21:12 -07:00
|
|
|
Ray reflection_ray = Ray(intersection,
|
|
|
|
ray.direction - 2.0 * normal * ray.direction.dot(normal));
|
|
|
|
mStats.reflectionRays++;
|
|
|
|
Color reflection_color = trace_ray(reflection_ray,
|
|
|
|
depth + 1,
|
|
|
|
weight * specular_level);
|
2013-09-21 16:45:30 -07:00
|
|
|
|
|
|
|
// TODO: Mix in specular_color of material.
|
2013-09-21 17:14:47 -07:00
|
|
|
out_color += specular_level * specular_color * reflection_color;
|
2014-08-02 15:23:22 -07:00
|
|
|
#endif
|
2013-09-21 16:45:30 -07:00
|
|
|
|
2013-09-11 22:03:50 -07:00
|
|
|
return out_color;
|
2013-09-10 16:28:32 -07:00
|
|
|
}
|