Skip to content

for now, a simple raytracer written on cpp lang.

Notifications You must be signed in to change notification settings

dantasl/raytracer

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

A Journey Through Ray Tracing

The amazing task to implement a Ray Tracer is at hand. Through the whole semester, prof. dr. Selan Rodrigues dos Santos, in his 2019.1's class of Computer Graphics I, will assign incremental projects towards this goal. Hopefully, by the end of it, I earn my degree as padawan in this fine art.

Chapter 1: Bootstrap

For the very firs Ray Tracer project, we must start with the basics. It consists simply on having a XML scene describer file, with informations regarding only the colors of the background, the size of the camera and the outputing of the resulting image.

So... what is a scene?

Putting in common words, a scene is the description of the image to be generated by the Ray Tracer. It consists of elements such as background, camera, etc.

For this simple project, a scene could have the following format:

<raytracer>
  <settings>
      <output_file type="PNG" name="images/saida.png"/>
  </settings>
  <background>
      <color r="0"   g="0"   b="51"/> <!-- bottom left  -->
      <color r="0"   g="255" b="51"/> <!-- top left     -->
      <color r="255" g="255" b="51"/> <!-- top right    -->
      <color r="255" g="0"   b="51"/> <!-- bottom right -->
  </background>
  <camera type="orthographic">
    <width value="500"/>
    <height value="500"/>
  </camera>
</raytracer>

There are a few tags in here that must be explained. The first one is <raytracer>. This is the root of the file and defines our scope. Everything, for now, must be inside of it.

<settings> contains informations about what should be done with the generated image. Right now we can only have a <output_file>. This will say the type (i.e. PPM or PNG) and the name/path for the image.

<background> is the real star here. It can have the maximum of four <color> tags inside it. But hey! No need for you to define all four colors. If you define only one, the remaining three will have the same value as the one you defined. If you define two, the remaining colors will have the same value as the last color you provided. This is a rule that applies to any number of colors provided, but you must provide at least one!

So, basically, if you provide more than one color, you'll have a gradient. If you want your background as a solid color, simply provide one color. For all cases, internally, my Background class implements bilinear interpolation (and that is a pretty dope thing).

<camera> is the last one. Right now we don't have much complexity on this one, so basically you should just provide the <width> and the <height> values, as described in the scene. This will tell how much of the digital world we will see.

Does it work?

Of course! Let me show you some examples.

The first one is quite pretty, is the resulting image of the scene described above:

img

Changing the background a litte bit like this:

<background>
  <color r="55"   g="59"   b="68"/> <!-- bottom left  -->
  <color r="55"   g="59"   b="68"/> <!-- top left     -->
  <color r="66"   g="134"  b="244"/> <!-- top right    -->
  <color r="66"   g="134"  b="244"/> <!-- bottom right -->
</background>

Will give us this horizontal gradient:

img

Now, generating a vertical gradient will look similar to this:

<background>
  <color r="16"   g="141"   b="199"/> <!-- bottom left  -->
  <color r="239"  g="142"   b="56"/> <!-- top left     -->
  <color r="239"  g="142"   b="56"/> <!-- top right    -->
  <color r="16"   g="141"   b="199"/> <!-- bottom right -->
</background>

And we generate this output:

img

And lastly, if we want a simple solid background, it can be done as this:

<background>
  <color r="60"   g="59"   b="63"/>
</background>

And the output will be:

img

Chapter 2: Cameras

In the previous project, we've created a bunch of beautiful background images using bilinear interpolation. Now, for the second project, we must implement cameras! Specifically two: the orthographic and the perspective ones.

Sadly, we don't have anything but the console to test them yet. So, after you run the code, you'll see on the prompt a message informing which ray was generated at a certain position.

How to describe a scene?

Its pretty much like in the previous chapter, but with a few additions on the tag . First I'm gonna show you and then I'll explain.

So, suppose you want to write the scene for a perspective camera. Here's a sample scene for you:

<raytracer>
  <settings>
    <output_file type="PNG" name="sky.png"/>
  </settings>
  <background>
      <color r="153"   g="204"   b="255"/> <!-- bottom left  -->
      <color r="18"   g="10"   b="143"/>   <!-- top left     -->
      <color r="18"   g="10"   b="143"/>   <!-- top right    -->
      <color r="153"   g="204"   b="255"/> <!-- bottom right -->
  </background>
  <camera type="perspective">
    <!--- The camera frame -->
    <position x="0" y="0" z="0"/> <!--- located at the origin -->
    <target x="0" y="0" z="-10"/> <!--- looking down the -Z axis -->
    <up x="0" y="1" z="1"/>       <!--- the camera's up vector -->
    <!--- Specific parameters for perspective -->
    <fovy value="45.0" />         <!--- The vertical field of view --> 
    <aspect value="1.33"/>        <!--- Optional parameter, aspect ratio W/H -->
    <fdistance value="1" />       <!--- The focal distance  -->
    <!--- Retina/image dimensions -->
    <width value="40"/>
    <height value="30"/>
  </camera>
</raytracer>

Chapter 3: Intersection Ray-Sphere

Previously on, we've implemented two types of cameras: perspective and orthogonal. Since we couldn't test them with something other than the console, things were a bit tedious. Now we finally have something (yet simple) to see: red spheres on a blue sky (or any color you want on your sky to be).

Scenes and how to describe them

Before going further in the description, please read how to describe the cameras, this will give all the previous details you need.

There's only a simple addition, which is the tag <scene> and the <object>.

A sample scene for a perspective camera would be:

<raytracer>
  <settings>
      <output_file type="PNG" name="images/red_spheres.png"/>
  </settings>
  <background> <!-- This defines an interpolated background -->
          <color r="153"  g="204"   b="255"/> <!-- bottom left  -->
          <color r="18"   g="10"    b="143"/> <!-- top left     -->
          <color r="18"   g="10"    b="143"/> <!-- top right    -->
          <color r="153"  g="204"   b="255"/> <!-- bottom right -->
  </background>
  <camera type="perspective">
      <!--- The camera frame -->
      <position x="0" y="0" z="0"/> <!--- located at the origin -->
      <target x="0" y="0" z="-10"/> <!--- looking down the -Z axis -->
      <up x="0" y="1" z="1"/>       <!--- the camera's up vector -->
      <!--- Specific parameters for perspective projection -->
      <fovy value="65.0" />         <!--- The vertical field of view -->
      <aspect value="1.33"/>        <!--- Optional parameter, aspect ration W/H -->
      <fdistance value="1" />       <!--- The focal distance  -->
      <!--- Retina/image dimensions -->
      <width value="800"/>
      <height value="600"/>
  </camera>
  <scene>
       <object type="sphere" name="sphere1">
          <radius value="0.4"/>
          <center x="-1.0" y="0.5" z="-5"/>
       </object>
       <object type="sphere" name="sphere2">
          <radius value="0.4"/>
          <center x="1.0" y="-0.5" z="-8"/>
       </object>
       <object type="sphere" name="sphere3">
          <radius value="0.4"/>
          <center x="-1.0" y="-1.5" z="-3.5"/>
       </object>
  </scene>
</raytracer>

And a sample scene for an orthographic camera would be:

<raytracer>
  <settings>
      <output_file type="PNG" name="images/red_spheres.png"/>
  </settings>
  <background> <!-- This defines an interpolated background -->
          <color r="153"  g="204"   b="255"/> <!-- bottom left  -->
          <color r="18"   g="10"    b="143"/> <!-- top left     -->
          <color r="18"   g="10"    b="143"/> <!-- top right    -->
          <color r="153"  g="204"   b="255"/> <!-- bottom right -->
  </background>
  <camera type="orthographic">
      <!--- The camera frame -->
      <position x="0" y="0" z="0"/> <!--- located at the origin -->
      <target x="0" y="0" z="-10"/> <!--- looking down the -Z axis -->
      <up x="0" y="1" z="1"/>       <!--- the camera's up vector -->
      <!--- Specific parameters for orthographic projection -->
      <vpdim l="-3" r="3" b="-2.25" t="2.25" /> <!--- View plane dimensions [left right bottom top] -->
      <!--- Retina/image dimensions -->
      <width value="800"/>
      <height value="600"/>
  </camera>
   <scene>
       <object type="sphere" name="sphere1">
          <radius value="0.4"/>
          <center x="-1.0" y="0.5" z="-5"/>
       </object>
       <object type="sphere" name="sphere2">
          <radius value="0.4"/>
          <center x="1.0" y="-0.5" z="-8"/>
       </object>
       <object type="sphere" name="sphere3">
          <radius value="0.4"/>
          <center x="-1.0" y="-1.5" z="-3.5"/>
       </object>
  </scene>
</raytracer>

Where <scene> contains all the things (in lack of a proper word) that are going to be rendered in the image. These things are basically an arbitray (up to you) number of <object> tags.

An object must have a type and a name. For now, there's only implementation for sphere as type.

Each of the spheres must have a <radius> with an specif value attribute and a <center>, with x, y and z as attributes.

For now, all the spheres will be painted red.

Does it work?

Of course! Let me show you some examples.

The first one was generated with the sample perspective camera scene, described above:

img

And this was was generated with the sample orthographic camera scene, also described above:

img

Feel free to change the scenes and generate different kinds of images.

Chapter 4: Integrators and Materials

Moving forwards, we're adding a little bit more dynamicity to our spheres. Now they can have different colors and/or show a simple depth aspect. Also, our objects can have materials, and each material deals differently with rays/lights. Up to this point, there's only a flat material, which outputs a diffuse color.

Scenes and how to describe them

Before going further in the description, please read the previous scene description, this will give all the previous details you need.

I've added a simply tag called <integrator> and <material> and moved a little the position of other tags. A sample scene and model for this project goes as follows:

<raytracer>
  <camera type="perspective" name="cam_flat">
      <!--- The camera frame -->
      <position x="0" y="0" z="2"/> <!--- located at the origin -->
      <target x="0" y="0" z="-10"/> <!--- looking down the -Z axis -->
      <up x="0" y="1" z="1"/>       <!--- the camera's up vector -->
      <!--- Specific parameters for perspective projection -->
      <fovy value="65.0" />         <!--- The vertical field of view -->
      <aspect value="1.33"/>        <!--- Optional parameter, aspect ration W/H -->
      <fdistance value="1" />       <!--- The focal distance  -->
      <!--- Retina/image dimensions -->
      <width value="800"/>
      <height value="600"/>
      <img_file name="images/flat_spheres.png" />
  </camera>
   <scene>
       <background> <!-- This defines an interpolated background -->
          <color r="153"  g="204"   b="255"/> <!-- bottom left  -->
          <color r="18"   g="10"    b="143"/> <!-- top left     -->
          <color r="18"   g="10"    b="143"/> <!-- top right    -->
          <color r="153"  g="204"   b="255"/> <!-- bottom right -->
       </background>
       <object type="sphere" name="sphere1" material="green" >
          <radius value="0.4"/>
          <center x="-1.0" y="0.5" z="-5"/>
       </object>
       <object type="sphere" name="sphere2" material="green">
          <radius value="0.4"/>
          <center x="1.0" y="-0.5" z="-8"/>
       </object>
       <object type="sphere" name="sphere3" material="gold">
          <radius value="0.4"/>
          <center x="-1.0" y="-1.5" z="-3.5"/>
       </object>
       <object type="sphere" name="sphere4" material="pink">
          <radius value="0.4"/>
          <center x="7.0" y="1.5" z="-10"/>
       </object>
       <!--- Library of materials -->
       <material type="flat" name="gold">
          <diffuse r="236" g="124" b="17"/>
       </material>
       <material type="flat" name="green">
          <diffuse r="42" g="201" b="51"/>
       </material>
       <material type="flat" name="pink">
          <diffuse r="253" g="153" b="253"/>
       </material>
  </scene>
  <running> <!--- Running setup -->
      <integrator type="flat">
          <spp value="1"/> <!--- Samples per pixel -->
      </integrator>
  </running>
</raytracer>

Notice now that the <object> possesses a material attribute. These materials must be declared and defined inside the scene file. A material has a type, a name and the color it reflects. For materials of type flat, there must be a tag diffuse in order to describe this.

Also, there's the tag <running>, which contains the <integrator> one. Currently, there are three types of integrators: Flat Integrator (this one simply outputs the diffuse color of a flat material), Normal Map Integrator (generates colors based on the normal map of the shape) and Depth Integrator (generates a color linear interpolated from a far and a near parameter).

Does it work?

Of course! This image was generated from the sample scene given above:

img

Now, if we change the contents of the <running> tag in order to test the same scene, but with a different integrator (say the Normal Map Integrator), we have this:

<running> <!--- Running setup -->
  <integrator type="normal_map">
    <spp value="1"/> <!--- Samples per pixel -->
  </integrator>
</running>

And the output produces:

img

Finally, testint the Depth Integrator:

<running> <!--- Running setup -->
  <integrator type="depth">
    <spp value="1"/> <!--- Samples per pixel -->
    <near_color r="0" g="0" b="0"/>
    <far_color r="255" g="255" b="255"/>
  </integrator>
</running>

Gives this:

img

Beware to not step on the eggs!

This is only the very first version of the project. I could not invest all my time on it, unfortunaly. So, if you try to break the program... it probably will. Its in my todo, actually, to implement exception handling and a more friendly interface to the user.

About

for now, a simple raytracer written on cpp lang.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages