134 lines
4.3 KiB
C++
134 lines
4.3 KiB
C++
#include "Object.h"
|
|
#include "Ray.h"
|
|
#include "Camera.h"
|
|
#include "Sphere.h"
|
|
#include "Plane.h"
|
|
#include "read_json.h"
|
|
#include "viewing_ray.h"
|
|
#include "first_hit.h"
|
|
#include <Eigen/Core>
|
|
#include <vector>
|
|
#include <iostream>
|
|
#include <memory>
|
|
#include <limits>
|
|
#include <functional>
|
|
|
|
// stb is a library commonly used when one wants to save an image in C++,
|
|
// since only one or two headers need to be included.
|
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
|
#include "stb_image_write.h"
|
|
|
|
|
|
int main(int argc, char * argv[])
|
|
{
|
|
// parse command line arguments
|
|
std::string path_to_json;
|
|
if (argc == 2) {
|
|
std::string args = argv[1];
|
|
// check if ends with .json
|
|
if (args.size() > 5 && args.substr(args.size() - 4, 4) == "json") {
|
|
path_to_json = args;
|
|
}
|
|
}
|
|
if (argc != 2 || path_to_json.empty()) {
|
|
printf(
|
|
"Error: received unexpected command line arguments. \n"
|
|
"Correct usage: \n"
|
|
" Linux: ./raycasting <path to json file> \n"
|
|
" Windows: raycasting.exe <path to json file> \n"
|
|
"For example: \n"
|
|
" Linux: ./raycasting ../data/sphere-and-plane.json \n"
|
|
" Windows: raycasting.exe ../../../data/sphere-and-plane.json \n"
|
|
);
|
|
return -1;
|
|
}
|
|
|
|
// list of colors used for per-object id coloring
|
|
const std::vector<unsigned char> color_map = {
|
|
228,26,28,
|
|
55,126,184,
|
|
77,175,74,
|
|
152,78,163,
|
|
255,127,0,
|
|
255,255,51,
|
|
166,86,40,
|
|
247,129,191,
|
|
153,153,153
|
|
};
|
|
|
|
Camera camera;
|
|
std::vector< std::shared_ptr<Object> > objects;
|
|
// Read a camera and scene description from given .json file
|
|
read_json(path_to_json,camera,objects);
|
|
|
|
int width = 640;
|
|
int height = 360;
|
|
std::vector<unsigned char> id_image(3*width*height);
|
|
std::vector<unsigned char> normal_image(3*width*height);
|
|
std::vector<unsigned char> depth_image(1*width*height);
|
|
|
|
// print a loading bar
|
|
for (int i = 0; i < 36; i++) printf("%c", 176);
|
|
printf("\r");
|
|
|
|
// For each pixel (i,j)
|
|
for(int i=0; i<height; ++i)
|
|
{
|
|
for(int j=0; j<width; ++j)
|
|
{
|
|
// Set background color
|
|
normal_image[0+3*(j+width*i)] = 0;
|
|
normal_image[1+3*(j+width*i)] = 0;
|
|
normal_image[2+3*(j+width*i)] = 0;
|
|
depth_image[j+width*i] = 0;
|
|
id_image[0+3*(j+width*i)] = 0;
|
|
id_image[1+3*(j+width*i)] = 0;
|
|
id_image[2+3*(j+width*i)] = 0;
|
|
|
|
// Compute viewing ray
|
|
Ray ray;
|
|
/* NOTE I flipped the vertical axis of the pixels, because in computer graphics we assume the bottom left pixel
|
|
* is (0,0), while traditional jpg assumes (0,0) to be the upper left pixel. */
|
|
viewing_ray(camera,height - i,j,width,height,ray);
|
|
|
|
// Find first visible object hit by ray and its surface normal n
|
|
double t;
|
|
Eigen::Vector3d n;
|
|
int hit_id;
|
|
if(first_hit(ray,1.0,objects,hit_id,t,n))
|
|
{
|
|
// object-id image
|
|
const int color_id = hit_id%(color_map.size()/3);
|
|
id_image[0+3*(j+width*i)] = color_map[0+3*color_id];
|
|
id_image[1+3*(j+width*i)] = color_map[1+3*color_id];
|
|
id_image[2+3*(j+width*i)] = color_map[2+3*color_id];
|
|
|
|
// depth image
|
|
const double zNear = camera.d;
|
|
double linearized_depth = zNear/(t*ray.direction.norm());
|
|
linearized_depth = linearized_depth<1?linearized_depth:1;
|
|
depth_image[(j + width * i)] = (uint8_t)(255.0*(linearized_depth));
|
|
|
|
// set pixel color to value computed from hit point, light, and n
|
|
// normal image
|
|
auto normal_to_rgb = [](const Eigen::Vector3d & n, unsigned char & r, unsigned char & g, unsigned char & b)
|
|
{
|
|
r = (unsigned char) (255.0*(n(0)*0.5+0.5));
|
|
g = (unsigned char) (255.0*(n(1)*0.5+0.5));
|
|
b = (unsigned char) (255.0*(n(2)*0.5+0.5));
|
|
};
|
|
normal_to_rgb(
|
|
n,
|
|
normal_image[0+3*(j+width*i)],
|
|
normal_image[1+3*(j+width*i)],
|
|
normal_image[2+3*(j+width*i)]);
|
|
}
|
|
}
|
|
if (i % 10 == 0) printf("%c", 178); // fill the loading bar
|
|
}
|
|
|
|
bool ret0 = stbi_write_png("normal.png", width, height, 3, normal_image.data(), width * 3);
|
|
bool ret1 = stbi_write_png("depth.png", width, height, 1, depth_image.data(), width);
|
|
bool ret2 = stbi_write_png("id.png", width, height, 3, id_image.data(), width * 3);
|
|
printf("\nDone! Wrote to normal.png (succes=%d), depth.png (succes=%d) and id.png (succes=%d) \n", ret0, ret1, ret2);
|
|
}
|