Introduction

  • The project focus on creating a 3D enivernment and rendering an image based on the enivernment we created using Ray-Tracing algorthim. To make the image looks more realistic, the following shading technique and lighting effects have been implemented including, Phong shading, Lambert shading, Point-light, Spot-light, Area-light, and mirror reflection effect. The project is implemented by OpenFrameWork, which is a C++ toolkit. In order to run this project, you may download the OpenFrameWork toolkit by cliking following link: Link To Download OpenFrameWork

Creating an OpenFrameWork Project on your computer(You may skip this steps if you are familiar with OpenFrameWork).

  • After you downloaded the OpenFrameWork to your computer, you may unzip the zip file you just downloaded. Then, in the same directory, you may find a folder that containes all the necessarily files for the OpenFrameWork (e.g The name of the folder should appear as the following formate : of_XXXXXXXXX_XXX_release). Screen Shot 2021-01-25 at 11 19 10 PM
  • Once you open that folder, you may find another folder called projectGenerator. Screen Shot 2021-01-25 at 11 25 47 PM
  • Open the folder, than you may find a file called projectGenerator. Screen Shot 2021-01-25 at 11 27 58 PM
  • If it is your first time to run projectGenerator file, you may have to run the runMeFirst.command file first. First Select the runMeFirst.command the file. Then, right clik the file and run the file in Terminal. Screen Shot 2021-01-25 at 11 29 50 PM
  • Open the projectGenerator. Then, you may name the project with anyname you want. Then, in the addons area, you need to add ofxassimpmodelloader and ofxgui addons to your project in order to run all source codes of this project. Finally, creating the project by cliking the Generate button.
    Screen Shot 2021-01-25 at 11 40 45 PM

Copy all the source code to your project.

  • After generating the poject, you may go to the privious folder. Then, go to the folder, which is named apps. Then, open the folder called myApps. Then, find the project you just generated. Screen Shot 2021-01-25 at 11 56 41 PM
  • Then, you may download src and bin folders from this GitHub page. Then copy and replace both of the folders that you just downloaded into your project's directory. Screen Shot 2021-01-26 at 12 03 17 AM Screen Shot 2021-01-26 at 1 40 00 AM

Copy the reference of source code to your IDE

  • Now open your project using Xcode. Screen Shot 2021-01-26 at 9 15 52 PM
  • You may select the src folder from the left side bar area. Then, right click the folder and select Add Files to .. Screen Shot 2021-01-26 at 9 26 23 PM
  • Finally, add all the .cpp and .h files exclude ofApp.cpp, ofApp.h, and main.cpp to your project. Screen Shot 2021-01-26 at 9 45 57 PM

View objects explaination

  • Now if you compile and run the project, you will have a Window as the following picture. First, all the small spheres in yellow and black color are representing the point light, which emits light ray in 360 degree. Then, the two small spheres in yellow and white color with arrows are representing the spot-light. The two panels in yellow and blue colors with many arrows are representing the area-light. The three big spheres in blue,yellow,and red colors are defined as the sceneObject. The rabbit, which is sitting on the yellow sphere is a Mesh object. Finally, the wall panels and the table panels are defined as plane object, which is inherited from the SceneObject. Screen Shot 2021-01-26 at 9 56 25 PM

Explanation of addSceneObject function in RayTracingSystem

  • The addSceneObject function in RayTracingSystem is taking only one parameter, which is a pointer to SceneObject.

    A SceneObject object can be one of the following object:
  • SceneObject, which is the base object that can be added to RayTracingSystem.
  • Plane, which is inherited from SceneObject.
  • Sphere, which is inherited from SceneObject.
  • MeshObj, which is inherited from SceneObject.

Adding renderable scene object into the RayTracingSystem

  • In setup function at ofApp.cpp file, you may add floor plane/wall plane object to the System. The following code are an examples to add Plane object to RayTracingSystem.
this->_ray_tracing_system->addSceneObject(new Plane(glm::vec3(0,-2,0),glm::vec3(0,1,0),ofColor::lightCyan,40,40, nullptr,true)); // A mirror reflectable Plane with not texture.
this->_ray_tracing_system->addSceneObject(new Plane(glm::vec3(0,18,-20),glm::vec3(0,0,1),ofColor::skyBlue,40,40, new ofImage("wallPlaneTexter.jpeg"))); //A plane with texture but no mirror reflectable.
this->_ray_tracing_system->addSceneObject(new Plane(glm::vec3(0,18,-20),glm::vec3(0,0,1),ofColor::skyBlue,40,40))); // A plane with no texture and is no mirror reflectbale. 

Each parameter in the constructor of Plane object as following:
The First : position of the plane.
The second : normal vector of the plane.
The thrid(optional) : the color of the plane.
The fourth(optional) : the width of the plane.
The fifth(optional): the length of the plane.
The sixth(optional): the pointer to ofImage object.
The last(optional): a boolean value stands if the plane is mirror reflectable or not.

Note: if you don't pass value to a optional parameter, the constructor of the Plane object will provide default value for it. Screen Shot 2021-01-28 at 2 38 39 AM

  • In setup function at ofApp.cpp file, you may add Sphere to System. The following code is an example to add Sphere object to RayTracingSystem.
this->_ray_tracing_system->addSceneObject(new Sphere(glm::vec3(-4,2,0),3.0f,ofColor::blue)); // A sphere.
this->_ray_tracing_system->addSceneObject(new Sphere(glm::vec3(-6,2,0),3.0f)); // A sphere with default color.
this->_ray_tracing_system->addSceneObject(new Sphere(glm::vec3(-6,2,0),3.0f,ofColor::white,true)); // A mirror reflectable sphere.

Each parameter in the constructor of Sphere object as following:
The First : position of the sphere.
The second : the raduis of the sphere.
The thrid(optional) : the color of the sphere.
The fourth(optional) : a boolean value stands if the sphere is mirror reflectable or not.
Note: if you don't pass value to a optional parameter, the constructor of the Sphere object will provide default value for it. Screen Shot 2021-01-28 at 3 13 43 AM

  • In setup function at ofApp.cpp file, you may add MeshObj object by importing information from an obj file, which is a geometry definition file format. To render image perfectly, the obj file should only contains information of Triangle Mesh. The following link is showing you how to convert Polygon faces to Triangle Mesh using AutoDesk Maya.
    Convert Polygon faces to Triangle Mesh

    The following code is an example to add MeshObj object to RayTracingSystem.
this->_obj_file = new ofxAssimpModelLoader();
if(_obj_file->loadModel("Rabbit_Lowpoly_1.obj"))
{
    this->_ray_tracing_system->addSceneObject(new MeshObj(glm::vec3(0, 6, 2), _obj_file, ofColor::saddleBrown, ofColor::gray));
}
else
{
    std::cout<<"Can't not load the obj file"<<std::endl;
    return;
}

Each parameter in the constructor of MeshObj object as following:
The first parameter: the position for obj file.
The second: the pointer to ofxAssimpModelLoader, which is used to load obj file.
The thrid(optional): the diffuse color for each Triangle Mesh in the obj file.
The fourth(optional): the special color for each Triangle Mesh in the obj file.
Screen Shot 2021-01-28 at 4 32 07 AM

Explanation of addLightSource function in RayTracingSystem.

  • The addLightSource function in the RayTracingSystem takes three parameters, a pointer to one type of light, and two boolean vaule. The first parameter is mandatory while second and the thrid are optional. The first parameters is a pointer to one of lightscoure object as following:
  • LightSource, which is normal point light with 360 illumination angle.
  • SpotLight, which is inherited from LightSource, and it has limited illumination angle.
  • AreaLight, which is inherited from LightSource, and it is considered as integration of many of point light object in one panel.

The second of boolean parameter:

  • It represents if the light being added to the RayTracingSystem is a SpotLight object or not. It is a optional parameter. If you don't provide a value to this parameter, the default value for this parameter is false.

The thrid pf boolean parameter:

  • It represents if the light being added to the RayTracingSystem is a AreaLight object or not. It is a optional paramter. If you don't provide a value to this parameter, the default value for this parameter is false.

Adding different type of light source to the rendering system.

  • In setup function at ofApp.cpp file, you may add normal LightSource object, which is a point light, to rendering system. The following code is an example to add LightSource object to RayTracingSystem.
this->_ray_tracing_system->addLightSource(new LightSource(glm::vec3(-16,23,-17),5.0f,ofColor::yellow));

Each parameter in the constructor of LightSource object as following: The first: the position of LightSource.
The second: the intensity of the LightSource.
The thrid: the color of the LightSource.
The fourth(optional): the coefficient of Phong power of the LightSource.
Screen Shot 2021-01-29 at 2 49 43 AM

  • In setup function at ofApp.cpp file, you may add SpotLight object to rendering system. The following code is an example to add SpotLight object to RayTracingSystem.A SpotLight is inherited from LightSource.
// Note: The boolean parameter in the function addLightSource function is representing that 
//       if the lightsource being added is a SpotLightSource object or not. 
this->_ray_tracing_system->addLightSource(new SpotLightSource(glm::vec3(8,10,12),5.0f,15.0f,glm::vec3(-4,2,0),ofColor::white),true);

Each parameter in the constructor of SpotLight object as following: The First: position of the SpotLight.
The second: the intensity of the SpotLight.
The thrid: the illumination angle of SpotLight.
The fourth: the direction vector that SpotLight is pointing to.
The fifth(optional): the color of the SpotLight.

Note: The last boolean parameter in addLightSource function is repersenting for if the light being added is a SpotLightSource object or not.

Screen Shot 2021-01-29 at 3 01 36 AM

  • In setup function at ofApp.cpp file, you may add AreaLight object to rendering system. The following code is an example to add AreaLight object to RayTracingSystem.
// Note: The second boolean parameter in the addLightSource function is representing 
//       if the lightsouce being added is a spotlight or not. 
//       In this case, you want to add a arealight, therefore it value of that boolean parameter is false.
//       The last boolean parameter in the addLightSource function is representing 
//       if the lightsouce being added is a arealight or not. 
//       In this case, the value of the boolean parameter is true. 
this->_ray_tracing_system->addLightSource(new AreaLight(glm::vec3(-15,5,0),glm::vec3(1,0,0),100.0f,-40.0f,ofColor::yellow,3.0f,3.0f,5),false,true);

Each parameter in the constructor of AreaLight object as following:
The first : position of the AreaLight.
The second : the outer normal of the AreaLight.
The thrid : the intensity coefficient of AreaLight.
The fourth : the rotation angle relative to axis, which is parallel to the plane of AreaLight.

(e.g) For instance, if an AreaLight object has a outer normal (1,0,0), the illumination dirction of the AreaLight is to the positive x axis.
Then, rotation angle for this AreaLight is relatvie to positvie y axis.

The fifth : the color of the AreaLight.
The sixth : the length of the AreaLight.
The seventh : the width of the AreaLight.
The last : number of n by n pointLight has been integraled in AreaLight.
(e.g) if the value of the last parameter is 5, it means there are number of 5x5, which is 25, pointLight objects has been included in the AreaLight

Note: The last boolean parameter in addLightSource function is repersenting for if the light being added is a AreaLight object or not. Screen Shot 2021-01-29 at 7 41 04 PM

GUI

  • When you run the project, you may use the GUI panel, which located at the left top corner of window, to adjust information for different type of light source. You may change the postion for SpotLight and AreaLight. Also, you may change the coefficient intensity and power for each lights. Finally, you may change the illumination angle for the SpotLight and the rotation angle for the AreaLight. Screen Shot 2021-01-29 at 9 51 37 PM

Adding more controller to GUI

  • If you wish to add more controller to GUI panel, you may begin with reviewing following link to obtain a basic understanding about ofxGUI object.Tutorial of using GUI

  • Now following steps show your an example to add another controller to changed position of an additional AreaLight. Step 1:
    In the ofApp.h file, you may define a new ofxVec3Slider variable, which is one of component can be add to GUI panel. Screen Shot 2021-01-29 at 10 35 06 PM

Step 2:
In the setup function at ofApp.cpp file, you may add the component that you just defined into the GUI panel.
Following code is showing you an example to do so

this->_gui.add(this->_thrid_area_light_position.setup("Thrid(New Added) area-light position: ",ofVec3f(15,5,0),ofVec3f(-20,-20,-20), ofVec3f(20,20,20)));

Note: Each parameter for the setup function of the component object you just defined as following.

First parameter: Initial value for the component.
Second parameter: The minimum(Min) value for the component.
Thrid parameter: The maximum(Max) value for the component.

That is to say, the code shown above, give you a component, which it initial values for x, y, and z are 15, 5,and 0. The Min values for x,y, and z are -20, -20, and -20. The Max values for x, y, and z are 20, 20, and 20. Screen Shot 2021-01-29 at 10 48 30 PM Screen Shot 2021-01-29 at 10 59 15 PM

Step 3: In the update function at ofApp.cpp file, you may call updateAreaLightPosition in the RayTracingSystem to update the position of a AreaLight object. Following code are an example to update the position for an area light.

this->_ray_tracing_system->updateAreaLightPosition(this->_thrid_area_light_position, 2);

The updateAreaLightPosition function takes two parameter. The first parameter is an ofxVec3Slider object, which containe the inforamtion of new position that the AreaLight object will be shift to. The second parameter is the index of the AreaLight object in the RayTracingSystem. In this example, since there were two AreaLight objects were already added in the RayTracingSystem, the index of the latest AreaLight that has been added in the RayTracingSystem is 2 (index starts from 0). Screen Shot 2021-01-30 at 12 40 02 AM

(Important) How to rendering an Image.

  • After you add renderable object and different type of lights to the RenderingSystem, you may recompile and run the code again. Then you may press "s" key from keyboard to begin the process of rendering. After the process of rendering completed, you may press "F4" from keyboard to review the image that just been generated.

Images

  • Now here is some image, which is rendered by this project.

  • An image with table plane, Point light, AreaLight, and Spot Light. myImage_3

  • An image with wall plane, table plane, textrue, Point light, AreaLight, Spot Light, and Mirror reflection. myImage

Credit

Hing Li