This assignment is intended to make you have the first experience in creating a colored image and, at the same time, get ready to create a useful class for your Ray Tracing project: the Background
class.
This class is responsible for returning a RGB color (radiance) every time a rays is shot into a Three-dimensional (3D) scene and hits nothing.
Usually the scene file will have a set of four colors assigned to each of the four corners of the "background" and you have to linearly interpolate those colors to get a RGB color, say, at the (x,y)
location inside the background image.
But before designing the Background
class, we are going to play with some code and learn how to create an image (more precisely, a PPM image), and how to interpolate values on a linear scale.
In this part of the assignment you will need to create a program that sends to the standard output information describing a PPM image in ASCII format. The target image should have 400 x 200 (width x height) of resolution, and each RGB pixel will have values from 0 to 255.
As we move from left to right on the output image (regardless of the row) the red channel should increase from zero to fully on (255).
Similarly, as we move from bottom to top on the image, the green channel should go from zero (at the bottom) to fully on 255 (at the top).
The blue channel, however, should remain constant at 20%
intensity throughout the image.
The PPM image's Coordinate System has its origin located at the bottom left corner.
The positive X
goes from left to right, and the positive Y
goes from bottom to top.
Y ^
|
+------------+
| |
| Image |
| |
-+------------+-->
O | X
Therefore, the image's origin will be black (lower left corner), whereas the opposite corner (upper right corner) should be full green + full red + 20% blue. The expected result is the image below.
The basic PPM image format has the following header:
- One line with the so called magic number, which is an indication of the type of image. For PPM images in ASCII mode this magic number is
P3
. - One line with two integer values, indicating the width (
W
) and height (H
) of the image in pixels. - One line with the maximum value for a color,
MAX
. This is usually255
. - Then we have
W
$\times$ H
lines, each with three integer values (R, G, and B), varying from 0 toMAX
. These lines are the "body" of the image.
Of course, you do not need to place each of these information on a separate line, if you do not wish so. The only requirement is that these values should be separated with at least on white space. So technically, you could have all the image in a single line!
However, it's recommended that your program generate one information per line to make the file more human readable and, therefore, easy to debug. In the particular case of the pixels, you may print one pixel color (a RGB triplet) per line. See the PPM file example below, copied from the wikipedia.
P3 # "P3" means this is a RGB color image in ASCII
3 2 # "3 2" is the width and height of the image in pixels
255 # "255" is the maximum value for each color
# The part above is the header
# The part below is the image data: RGB triplets
255 0 0 # red
0 255 0 # green
0 0 255 # blue
255 255 0 # yellow
255 255 255 # white
0 0 0 # black
In the previous part, you had to generate a image based on a fixed interpolation strategy, with predefined values for each of the color channels. In this segment, we need to generalize this task by allowing the client (i.e. the scene file) to specify a different color for each of the four corners of the image. Then, we calculate the internal color of the image by performing a linear interpolation in each of the image dimensions.
A parametric line between two points A
and B
represents a weighted average between those two points.
In this case
Note, for instance, that when
To apply this concept to colors you need to interpolate each RGB channel separately. However, this will only work for one dimension. To generate an interpolated color inside the image plane we need to interpolate twice, which is called bilinear interpolation.
Suppose we need to find a interpolated color for a coordinate
- We first interpolate between
$A$ and$B$ , with input parameter$u$ , to get a temporary color$Xb$ (bottom). - Similarly, we interpolate between
$C$ and$D$ , with the same input paramter$u$ , which yields a temporary color$Xt$ (top). - Finally, we interpolate between
$Xb$ and$Xt$ , with input paramter$v$ , to get the final color$I$ .
Adapt the program developed in the Part 1 of this assignment so that
- You now instantiate a
Background
objectbkg
, assigning four RGB colors to each of its corners, and; - Generate a new PPM image by sampling each pixel of the image via methods of the
bkg
object.
Recall that the main purpose of the Background
class is to hide the bilinear interpolation described previously.
Here is a suggestion for the Background
class interface.
class BackgroundColor {
private:
/// Each corner has a color associated with.
RGBColor corners[4]={{0,0,0},{0,0,0},{0,0,0},{0,0,0}};
/// Corner indices.
enum Corners_e {
bl=0, //!< Bottom left corner.
tl, //!< Top left corner.
tr, //!< Top right corner.
br //!< Bottom right corner.
};
/// Return the linearly interpolated color in [A;B], based on the parameter \f$0\leq t \leq 1.\f$
RGBColor lerp( const RGBColor &A, const RGBColor &B, float t ) const;
public:
/// Ctro receives a list of four colors, for each corner.
BackgroundColor( const std::vector< RGBColor >& colors );
/// Dtro
~BackgroundColor() { };
/// Sample and returns a color, based on the raster coordinate.
RGBColor sampleUV( real_type u, real_type v ) const;
};
# Clone this repository
$ git clone https://github.com/ThiagoCordeiro52/GC-Proj-00-PPM.git
# Access the project folder in terminal/cmd
$ cd GC-Proj-00-PPM
# Access the src folder in terminal/cmd
$ cd src
# Compile the source code
$ g++ main.cpp -o main
# Generate the image from program execution
$ ./main > result.ppm
# Open the image with an image viewer
$ gimp result.ppm