Skip to content
This repository was archived by the owner on Oct 10, 2019. It is now read-only.

Addresses issues: #9, #15, #18, #26, #54, #58, #65, #67, #69 #79

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
23 changes: 23 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 3.6)

set(ProjectName "InOneWeekend")

project(${ProjectName})

# Add source and header files
file(GLOB_RECURSE sources ${CMAKE_CURRENT_SOURCE_DIR}/*.hpp ${CMAKE_CURRENT_SOURCE_DIR}/*.h ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ${CMAKE_CURRENT_SOURCE_DIR}/*.cc)
# Exclude the build directory
list(FILTER sources EXCLUDE REGEX "build/")
# Create the VS filters based on the directory tree layout
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${sources})

# Add the project
add_executable (${ProjectName} ${sources})

# Add openmp
# https://stackoverflow.com/questions/56202041/compiling-and-linking-against-openmp-with-appleclang-on-mac-os-x-mojave
find_package(OpenMP) # Find the package
target_link_libraries(${PROJECT_NAME} ${OpenMP_CXX_LIBRARIES}) # Link against it for C++

# Set this project as startup project (MSVC)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${ProjectName})
6 changes: 4 additions & 2 deletions src/camera.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
//==================================================================================================

#include "ray.h"
#include "constants.hpp" // pi<float>(), issues: #65, #67
#include "rng.hpp" // random(), issue: #65

vec3 random_in_unit_disk() {
vec3 p;
do {
p = 2.0*vec3(drand48(),drand48(),0) - vec3(1,1,0);
p = 2.0*vec3(random(),random(),0) - vec3(1,1,0);
} while (dot(p,p) >= 1.0);
return p;
}
Expand All @@ -26,7 +28,7 @@ class camera {
camera(vec3 lookfrom, vec3 lookat, vec3 vup, float vfov, float aspect, float aperture, float focus_dist) {
// vfov is top to bottom in degrees
lens_radius = aperture / 2;
float theta = vfov*M_PI/180;
float theta = vfov*pi<float>()/180;
float half_height = tan(theta/2);
float half_width = aspect * half_height;
origin = lookfrom;
Expand Down
11 changes: 11 additions & 0 deletions src/constants.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once
/*
Addresses issues: #65, #69
*/


template<typename T>
constexpr T pi() { return static_cast<T>(3.141592653589793238); }

// there's no ideal value, it is scene dependent
constexpr const float OFFSET_EPSILON = 0.0001f;
2 changes: 1 addition & 1 deletion src/hitable_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class hitable_list: public hitable {
bool hitable_list::hit(const ray& r, float t_min, float t_max, hit_record& rec) const {
hit_record temp_rec;
bool hit_anything = false;
double closest_so_far = t_max;
float closest_so_far = t_max;
for (int i = 0; i < list_size; i++) {
if (list[i]->hit(r, t_min, closest_so_far, temp_rec)) {
hit_anything = true;
Expand Down
137 changes: 102 additions & 35 deletions src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,21 @@
//==================================================================================================

#include <iostream>
#include <limits> // std::numeric_limits<float>::infinity()
#include <fstream> // doesn't require output redirection
#include <chrono> // Output elapsed time
#include "sphere.h"
#include "hitable_list.h"
#include "float.h"
#include "camera.h"
#include "material.h"
#include "random.h"
#include "rng.hpp" // random()



vec3 color(const ray& r, hitable *world, int depth) {
hit_record rec;
if (world->hit(r, 0.001, MAXFLOAT, rec)) {
if (world->hit(r, 0.001f, std::numeric_limits<float>::infinity(), rec)) {
ray scattered;
vec3 attenuation;
if (depth < 50 && rec.mat_ptr->scatter(r, rec, attenuation, scattered)) {
Expand All @@ -32,8 +36,8 @@ vec3 color(const ray& r, hitable *world, int depth) {
}
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);
float t = 0.5f*(unit_direction.y() + 1.0f);
return (1.0f-t)*vec3(1.0f, 1.0f, 1.0f) + t*vec3(0.5f, 0.7f, 1.0f);
}
}

Expand All @@ -45,70 +49,133 @@ hitable *random_scene() {
int i = 1;
for (int a = -11; a < 11; a++) {
for (int b = -11; b < 11; b++) {
float choose_mat = random_double();
vec3 center(a+0.9*random_double(),0.2,b+0.9*random_double());
if ((center-vec3(4,0.2,0)).length() > 0.9) {
if (choose_mat < 0.8) { // diffuse
float choose_mat = random();
vec3 center(a+0.9f*random(),0.2f,b+0.9f*random());
if ((center-vec3(4,0.2f,0)).length() > 0.9f) {
if (choose_mat < 0.8f) { // diffuse
list[i++] = new sphere(
center, 0.2,
new lambertian(vec3(random_double()*random_double(),
random_double()*random_double(),
random_double()*random_double()))
center, 0.2f,
new lambertian(vec3(random()*random(),
random()*random(),
random()*random()))
);
}
else if (choose_mat < 0.95) { // metal
else if (choose_mat < 0.95f) { // metal
list[i++] = new sphere(
center, 0.2,
new metal(vec3(0.5*(1 + random_double()),
0.5*(1 + random_double()),
0.5*(1 + random_double())),
0.5*random_double())
center, 0.2f,
new metal(vec3(0.5f*(1 + random()),
0.5f*(1 + random()),
0.5f*(1 + random())),
0.5f*random())
);
}
else { // glass
list[i++] = new sphere(center, 0.2, new dielectric(1.5));
list[i++] = new sphere(center, 0.2f, new dielectric(1.5f));
}
}
}
}

list[i++] = new sphere(vec3(0, 1, 0), 1.0, new dielectric(1.5));
list[i++] = new sphere(vec3(-4, 1, 0), 1.0, new lambertian(vec3(0.4, 0.2, 0.1)));
list[i++] = new sphere(vec3(4, 1, 0), 1.0, new metal(vec3(0.7, 0.6, 0.5), 0.0));
list[i++] = new sphere(vec3(0, 1, 0), 1.0f, new dielectric(1.5f));
list[i++] = new sphere(vec3(-4, 1, 0), 1.0f, new lambertian(vec3(0.4f, 0.2f, 0.1f)));
list[i++] = new sphere(vec3(4, 1, 0), 1.0f, new metal(vec3(0.7f, 0.6f, 0.5f), 0.0f));

return new hitable_list(list,i);
}


int main() {
int nx = 1200;
int ny = 800;

// faster preview
/*
int nx = 1200;
int ny = 800;
*/
int nx = 320;
int ny = 240;
int ns = 10;
std::cout << "P3\n" << nx << " " << ny << "\n255\n";





hitable *world = random_scene();

vec3 lookfrom(13,2,3);
vec3 lookat(0,0,0);
float dist_to_focus = 10.0;
float aperture = 0.1;
float dist_to_focus = 10.0f;
float aperture = 0.1f;

camera cam(lookfrom, lookat, vec3(0,1,0), 20, float(nx)/float(ny), aperture, dist_to_focus);

for (int j = ny-1; j >= 0; j--) {
/*
Addresses issue: #58

We write the code to memory before saving to disk, this may prove beneficial not only
with regards to parallelization.

To use OMP with MSVC add /openmp to the command line options
*/
vec3* image = new vec3[nx * ny];


/*
Extra feature: output rendering time (useful to see the speedup from multi-threading)

On my machine rendering with 1 core takes: ~8s, and with 4 cores: ~2s
*/
std::chrono::high_resolution_clock clock;
auto timeStamp = clock.now();


#pragma omp parallel for
for (int j = 0; j < ny ; j++) {
for (int i = 0; i < nx; i++) {
vec3 col(0, 0, 0);
for (int s=0; s < ns; s++) {
float u = float(i + random_double()) / float(nx);
float v = float(j + random_double()) / float(ny);
float u = float(i + random()) / float(nx);
float v = float(j + random()) / float(ny);
ray r = cam.get_ray(u, v);
col += color(r, world,0);
}
col /= float(ns);
col = vec3( sqrt(col[0]), sqrt(col[1]), sqrt(col[2]) );
int ir = int(255.99*col[0]);
int ig = int(255.99*col[1]);
int ib = int(255.99*col[2]);
std::cout << ir << " " << ig << " " << ib << "\n";

// flat array indexing, perform the flip here j' = ny-1-j
image[i + nx * (ny-1-j)] = col; // store in memory
}
}

std::chrono::duration<float> elapsedTime = clock.now() - timeStamp;
std::cout << "Rendering took: " << elapsedTime.count() << "s.\n";

/*
Addresses issue: #18
std::ofstream rather than std::cout, so one doesn't need to redirect the output
*/
std::ofstream file;
const char* outputFilename = "output_image.ppm";
file.open(outputFilename);
if (!file.good()) std::cerr << "Failed to open file " << outputFilename << std::endl;
file << "P3\n" << nx << " " << ny << "\n255\n";
for (int i = 0; i < nx * ny; ++i)
{
vec3 col = image[i];

// gamma correction
col = vec3(sqrt(col[0]), sqrt(col[1]), sqrt(col[2]));

// map from [0,1] to {0,1,...,255} (quantization)
int ir = int(255.99 * col.r());
int ig = int(255.99 * col.g());
int ib = int(255.99 * col.b());

// save pixel to disk
file << ir << " " << ig << " " << ib << "\n";
}
file.close();
delete[] image;



return 0;
}
Loading