Developing ray tracing render from scratch.
- Using k-d tree for fast traversal of 3D scene objects
- Using Surface Area Heuristic for building optimal k-d tree
- Rendering entire scene in parallel (using OpenMP)
- Texture mapping (using libpng)
- Saving rendered image to file (using libpng)
- Loading 3D models from *.obj format
- Phong shading
- Antialiasing: throwing 4 rays per each pixel, which belongs to edge (using Sobel operator to detect edges)
- Phong reflection model
- Two types of primitives: triangle and sphere
- Reflections, shadows, fog effect, multiple light sources
Requires libpng to be installed.
Tested on Mac OS 10.8 with gcc 4.2, gcc 4.7, gcc 4.9 and gcc 5 (as far as OpenMP is required - currently, Clang can't be
used).
All rendering routines are performing by this render, not OpenGL. Just using GLUT to display rendered image.
make run_demo_gl
or something like this (in case if Homebrew installed GCC 5 - under its own alias):
make CC=gcc-5 run_demo_gl
- Use controls ← ↑ → ↓ to rotate camera
- Use CTRL + ↑ or CTRL + ↓ to move camera forward or backward
- Use SHIFT + ↑ or SHIFT + ↓ to move camera up or down
- Use SHIFT + ← or SHIFT + → to move camera left or right
- Use ALT + ↑ or ALT + ↓ to change focus of camera
- Use ESC to exit
Lets create example application from scratch :) You will get following image:
#include <stdio.h>
#include <canvas.h>
#include <render.h>
#include <obj_loader.h>
#define CANVAS_W 400
#define CANVAS_H 400
// Boost by rendering in parallel
#define THREADS_NUM 4
#define BACKGROUND_COLOR rgb(255, 255, 255)
#define MAX_OBJECTS_NUMBER 10000
#define MAX_LIGHT_SOURCES_NUMBER 5
int
main(void) {
// Allocating scene
Scene * scene = new_scene(MAX_OBJECTS_NUMBER,
MAX_LIGHT_SOURCES_NUMBER,
BACKGROUND_COLOR);
// Allocating new sphere
Float radius = 100;
Point3d center = point3d(0, 0, 0);
Color sphere_color = rgb(250, 30, 30);
Material sphere_material = material(1, 5, 5, 10, 0, 10);
Object3d * sphere = new_sphere(center,
radius,
sphere_color,
sphere_material);
// Adding sphere to the scene
add_object(scene,
sphere);
// Allocating new triangle
Object3d * triangle = new_triangle(point3d(-700, -700, -130), // vertex 1
point3d( 700, -700, -130), // vertex 2
point3d( 0, 400, -130), // vertex 3
rgb(100, 255, 30), // color
material(1, 6, 0, 2, 0, 0) // surface params
);
// Adding triangle to the scene
add_object(scene,
triangle);
// Loading 3D model of cow from *.obj file
// defining transformations and parameters of 3D model
// TODO: must be refactored...
SceneFaceHandlerParams load_params =
new_scene_face_handler_params(scene,
// scale:
40,
// move dx, dy, dz:
-150, -100, 30,
// rotate around axises x, y, z:
0, 0, 0,
// color
rgb(200, 200, 50),
// surface params
material(2, 3, 0, 0, 0, 0)
);
load_obj("./demo/models/cow.obj",
// default handler which adding polygons of 3D model to scene:
scene_face_handler,
&load_params);
// This function is requried (bulding k-d tree of entire scene)
prepare_scene(scene);
printf("\nNumber of polygons: %i\n", scene->last_object_index + 1);
// Allocating new light source
Color light_source_color = rgb(255, 255, 255);
Point3d light_source_location = point3d(-300, 300, 300);
LightSource3d * light_source = new_light_source(light_source_location,
light_source_color);
// Adding light source to the scene
add_light_source(scene,
light_source);
// Adding fog
Float density = 0.002;
set_exponential_fog(scene, density);
// Allocating camera
// TODO: It's a pity, but quaternions are not implemented yet :(
Point3d camera_location = point3d(0, 500, 0);
Float focus = 320;
Float x_angle = -1.57;
Float y_angle = 0;
Float z_angle = 3.14;
Camera * camera = new_camera(camera_location,
x_angle,
y_angle,
z_angle,
focus);
// Rotate camera if needed
// rotate_camera(camera, d_x_angle, d_y_angle, d_z_angle);
// Move camera if needed
// move_camera(camera, vector3df(d_x, d_y, d_z));
// Alocate new canvas, to render scene on it
Canvas * canvas = new_canvas(CANVAS_W,
CANVAS_H);
render_scene(scene,
camera,
canvas,
THREADS_NUM);
// Saving rendered image in PNG format
write_png("example.png",
canvas);
release_canvas(canvas);
release_scene(scene);
release_camera(camera);
return 0;
}
Launch it
make example && ./example
Define different values of maximal depth of Kd-tree and track average number of ray intersections per pixel:
make DEF="-DRAY_INTERSECTIONS_STAT -DMAX_TREE_DEPTH=25" run_demo_gl
make DEF="-DRAY_INTERSECTIONS_STAT -DMAX_TREE_DEPTH=25" example && ./example
Illustration of kd-tree boosting:
- Without kd-tree, and without bounding box:
make clean > /dev/null
make DEF="-DRAY_INTERSECTIONS_STAT -DNO_BOUNDING_BOX -DMAX_TREE_DEPTH=0" benchmark > /dev/null &&
./benchmark
make clean > /dev/null
- Without kd-tree, but with bounding box:
make clean > /dev/null
make DEF="-DRAY_INTERSECTIONS_STAT -DMAX_TREE_DEPTH=0" benchmark > /dev/null &&
./benchmark
make clean > /dev/null
- With kd-tree, but without bounding box:
make clean > /dev/null
make DEF="-DRAY_INTERSECTIONS_STAT -DNO_BOUNDING_BOX -DMAX_TREE_DEPTH=20" benchmark > /dev/null &&
./benchmark
make clean > /dev/null
- With kd-tree, and with bounding box:
make clean > /dev/null
make DEF="-DRAY_INTERSECTIONS_STAT -DMAX_TREE_DEPTH=20" benchmark > /dev/null &&
./benchmark
make clean > /dev/null