Package: tracerr
TracerrA simple raytracing programOverviewThis program was done as the final project for the Udacity C++ Nanodegree.The program supports rendering of spheres, triangles and rectangles as basic primitive shapes. It also includes the capability to render .obj 3D models.The program is capable of simulating not only the basic Phong illumination model (ambient, diffusion and specular light) but also shadows, reflections and refractionsThe scenes to render are stored in text protobufs that can be used to modify said scenes.The code is inspired bytinytracerby Dimitry Sokolov (specially some of the math behind raytracing). The rest of the code was done to practice the stuff that was covered during the nanodegree.I also chose to use Eigen for the linear algebra due to its easy to use, speed and built-in methods.Install dependenciesThe instructions here are aimed forUbuntu(tested on 20.04), for other platforms please check the respective library sitesDependencies:GitCMake 3.16Eigen 3.3.7Protobuf 3.6.1Python>=3.6 if using pythonTo install them run the following command:$sudoapt-yinstallgitbuild-essentialcmakelibprotobuf-devprotobuf-compilerlibeigen3-devIt also uses theSTB libraryto encode the image files. The required files are already included in the repo (includedirectory)NOTE: If you want (NOT REQUIRED) to force the generation of the C++ header and source files fromscene.protofile, you can run the following command within the main project folder$protoc-I=./proto--cpp_out=./proto./proto/scene.protoHow to buildOnce you have all the dependencies installed you can compile the program with CMake and MakePython$gitclonehttps://github.com/DLopezMadrid/tracerr.git$cdtracerr
$pipinstall.C++NOTE: This code uses C++17 features$gitclonehttps://github.com/DLopezMadrid/tracerr.git$cdtracerr
$mkdirbuild$cdbuild$cmake..$makeHow to runTo render a scene, the program is launched from the terminal and takes the-roption and the path to a prototext file describing the scene.$./tracerr-r{PATH_TO_PROTOTEXT_FILE}Example:$./tracerr-r./../scenes/simple.textprotoThe scene parameters are explained in the next section.In order to create a new the scene, you will need to make a new prototext file. You can ask the program to create an example scene, a commented empty template and a non-commented empty template with the following commands-tSAVEFILE_FOR_TEMPLATE_FILE->GeneratesanemptyTemplatewithcommentsforascene-uSAVEFILE_FOR_UNCOMMENTED_TEMPLATE_FILE->GeneratesanemptyTemplateWITHOUTcommentsforascene-eSAVEFILE_FOR_EXAMPLE_SCENE->GeneratesatextprotofileofaExamplesceneandsavesittothespecifiedfileExample to create a commented template file:$./tracerr-umy_new_scene.textprotoYou can also find some predefined scenes in the./scenefoldersimple.textproto: random scene that contains an element of every shape and an obj filesimple_spheres.textproto: another example with just a few spheres and a custom background colorsphere_field_with_duck.textproto: built on top of simple_spheres one but with 400 randomly generated smaller spheres and a duck 3D modelsuzanne.textproto: just a simple obj 3D model on a plain backgroundNOTE: In a i7 Skylake machine it takes around 25s to render the demo scene (./scenes/sphere_field_with_duck.textproto) shown in the cover image above (2000px x 1000px) (400 randomly generated spheres + 3D duck model)Forfaster executionyou can reduce the resolution (width&heightparameters). You can also comment out any of the shapes in the scene config fileThe resulting image will be saved in the build directory under the filename that you specify in the prototext file (fnameparameter)PythonThe Python module follows the same functionality as C++ and provides the following functions:tracerr.GenerateExample()
tracerr.GenerateTemplateNoComment()
tracerr.GenerateTemplate()
tracerr.RenderScene()The Python module can be used as follows:import tracerr
tracerr.RenderScene('PATH_TO_PROTOTEXT_FILE')Scene definitionScene configurationThe protobuf schema for the scene files is defined in the./proto/scene.protofileThe following fields are mandatoryint32 width;
 int32 height;
 bool saveFile [default = true];width: image width in pixelsheight: image height in pixelssaveFile: bool to specify if you wish to save the imageThere are also other scene configuration attributes that are optionalstring fname [default = "RenderTest.png"];
 bool show_elapsed_time [default = true];
 bool show_checkerboard [default = false];
 Color background_color;
 float ambient_light;fname: filename for the saved imageshow_elapsed_time: prints the time taken to render the scene to the consoleshow_checkerboard: draws the checkerboard floor planebackground_color: specifies a custom background color using the Color type (see below)ambient_light: specifies the ambient light level (values 0 - 1)Supporting typesThere is a number of types created to make the object definition more structuredmessage Pos {
    required float x = 1;
    required float y = 2;
    required float z = 3;
  }
 message Color{
   required int32 r = 1;
   required int32 g = 2;
   required int32 b = 3;
 }
 message Material{
   message Color_diff{
     required int32 r = 1;
     required int32 g = 2;
     required int32 b = 3;
   }
   message Albedo{
     required float a0 = 1;
     required float a1 = 2;
     required float a2 = 3;
     required float a3 = 4;
   }
   required Color_diff color = 1;
   required Albedo albedo = 2;
   required float specular_comp = 3;
   required float refractive_index = 4;
 }
 enum MaterialType{
   ivory = 0;
   red_rubber = 1;
   green_rubber = 2;
   blue_rubber = 3;
   orange_rubber = 4;
   pink_rubber = 5;
   red_plastic = 6;
   black_plastic = 7;
   mirror = 8;
   glass = 9;
   chessboard = 10;
 }Pos: defines a cartesian (X, Y, Z) position in spaceColor: defines an RGB color (0 - 255)Material: describes a new material containing custom diffuse color, albedo, specular component and refractive index componentsMaterialType: if you wish to use one of the predefined materialsLight sourcesTo define a light source:message Light{
   required Pos position = 1;
   required float intensity = 2;
 }Example:light{
  position{
    x: 0
    y: 5
    z: 0
  }
  intensity: 1.5
}Spheres, triangles and rectanglesTo define primitive shapesmessage Sphere{
    required Pos position = 1;
    required float radius = 2;
    optional MaterialType material = 3;
    optional bool custom_material_enabled = 4 [default = false];
    optional Material custom_material = 5;
  }
  message Triangle{
    required Pos p0 = 1;
    required Pos p1 = 2;
    required Pos p2 = 3;
    optional MaterialType material = 4;
    optional bool custom_material_enabled = 5 [default = false];
    optional Material custom_material = 6;
  }
  message Rectangle{
    required Pos p0 = 1;
    required Pos p1 = 2;
    required Pos p2 = 3;
    required Pos p3 = 4;
    optional MaterialType material = 5;
    optional bool custom_material_enabled = 6 [default = false];
    optional Material custom_material = 7;
  }Examples:sphere{
  position{
    x: 3
    y: 0
    z: -4
  }
  radius: 0.5
  material: blue_rubber
}

triangle{
  p0{
    x: 3
    y: 3
    z: -6
  }
  p1{
    x: 3
    y: 1
    z: -6
  }
  p2{
    x: 2
    y: 2
    z: -6
  }
  material: green_rubber
}

rectangle{
  p0{
    x: -3
    y: -3
    z: -6
  }
  p1{
    x: -3
    y: -1
    z: -6
  }
  p2{
    x: -2
    y: -2
    z: -6
  }
  p3{
    x: -2
    y: -4
    z: -6
  }
  custom_material_enabled: true
  custom_material {
    color {
      r: 14
      g: 147
      b: 98
    }
    albedo {
      a0: 0.6
      a1: 0.1
      a2: 0
      a3: 0
    }
    specular_comp: 10
    refractive_index: 1
  }
}Obj filesYou can load 3D models in .obj format using the following formatmessage Obj{
    required string fname = 1;
    optional MaterialType material = 2;
    optional Pos translation = 3;
    optional bool custom_material_enabled = 4 [default = false];
    optional Material custom_material = 5;
  }Example:obj{
  fname: "./../obj/suzanne.obj"
  translation{
    x: -1
    y: 1
    z: -5
  }
  material: pink_rubber
}Code OverviewThe include folder contains the STB library filesThe obj folder contains sample 3D models to test the triangle mesh renderingThe src folder contains most of the codeThe proto folder contains the proto file defining the protobuf schema (scene.proto) and the generated C++ libraries to use it in the program (scene.pb.cc&scene.pb.h)The scenes folder contains sample prototext files with different scenesThe tests folder contains the gtest tests (WIP)ClassesRenderMain class for the raytracingIt owns the shapes to be rendered (stored in the heap)It casts a ray using an origin point + a direction unit vectorThen it checks if the ray intersects with anything in the sceneIf no object is hit, the render saves the background color as the value for that pixelIf an object is hit, the render calculates the reflections and refractions from that object recursively by casting rays from the hit point at the reflected and refracted anglesTo calculate shadows it checks if the hit point has line of sight with the different light sources, if not it is in a shadowThe final calculation is done by taking into account thePhong illumination model(ambient, diffused and specular) values and reflections and refractions hitsThe raytracing can be run in series, in parallel usingOpenMPor in parallel using our own thread pool implementationSceneManagerThe scene manager is in charge of reading the scene from the protobuf text file, parse it, generate the required shapes sets up the render environment and call the render classIt can also write to text protobufs but this is not a user facing feature yet. It was implemented for learning and debugging purposes onlyIt is a friend class of Render, so it can access all the private members on itImageHolds & owns the image bitmap (pixels_) in the heapIt is in charge of writing the color values to every pixel and to save the image to disk using an instance of ImageFileLightRepresents a point light source with a given intensityMaterialRepresents a given material with certain properties relating to its color, diffusivity, specularity, reflectivity and refractivityShapePure virtual class to define the interface for all other shapesUsed for dynamic polymorphism for the calculate intersection and calculate normal methodsSphereShape child class that represents a sphere centered around a given point, with a certain radius and materialSince its the child of a pure virtual class it defines the relevant methods to be able to be instantiatedTriangleShape child class that represents a triangle with three given points and a certain material. Similarly to sphere it implements its own intersection and normal calculation methodsRectangleShape child class made out of two triangles. Takes advantage of composition to represent a more complex shapeObjLoaderReads and parses a .obj file and creates the respective triangles for the render (including material and an optional translation)ImageFileRAII file handler for writing png image file. Opens the file in the constructor and frees the resource in the destructorObjFileRAII file handler for reading the .obj file. Opens the file in the constructor and frees the resource in the destructorThreadPoolThread pool design patternImplements a queue of work packages for a pool of threadsThreads take a task from the queue, run it and when they are finished, return the result and check if there are any more tasks in the queue to performLicenseThis project is distributed under theDO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE.