2.1 The PPM Image Format
Whenever you start a renderer, you need a way to see an image. The most straightforward way is to write it to a file. The catch is, there are so many formats. Many of those are complex. I always start with a plain text ppm file.
Figure 1: PPM Example
Let’s make some C++ code to output such a thing:
#include <iostream>
int main() {
// Image
const int image_width = 256;
const int image_height = 256;
// Render
std::cout << “P3\n” << image_width << ‘ ‘ << image_height << “\n255\n”;
for (int j = image_height-1; j >= 0; –j) {
for (int i = 0; i < image_width; ++i) {
auto r = double(i) / (image_width-1);
auto g = double(j) / (image_height-1);
auto b = 0.25;
int ir = static_cast<int>(255.999 * r);
int ig = static_cast<int>(255.999 * g);
int ib = static_cast<int>(255.999 * b);
std::cout << ir << ‘ ‘ << ig << ‘ ‘ << ib << ‘\n’;
}}}
Listing 1: [main.cc] Creating your first image
There are some things to note in that code:
- The pixels are written out in rows with pixels left to right.
- The rows are written out from top to bottom.
- By convention, each of the red/green/blue components range from 0.0 to 1.0. We will relax that later when we internally use high dynamic range, but before output we will tone map to the zero to one range, so this code won’t change.
- Red goes from fully off (black) to fully on (bright red) from left to right, and green goes from black at the bottom to fully on at the top. Red and green together make yellow so we should expect the upper right corner to be yellow.
Creating an Image File
Because the file is written to the program output, you’ll need to redirect it to an image file. Typically this is done from the command-line by using the > redirection operator, like so:
build\Release\inOneWeekend.exe > image.ppm
This is how things would look on Windows. On Mac or Linux, it would look like this:
build/inOneWeekend > image.ppm
Opening the output file (in ToyViewer on my Mac, but try it in your favorite viewer and Google “ppm viewer” if your viewer doesn’t support it) shows this result:
Image 1: First PPM image
Hooray! This is the graphics “hello world”. If your image doesn’t look like that, open the output file in a text editor and see what it looks like. It should start something like this:
P3
256 256
255
0 255 63
1 255 63
2 255 63
3 255 63
4 255 63
5 255 63
6 255 63
7 255 63
8 255 63
9 255 63 …
Listing 2: First image output
If it doesn’t, then you probably just have some newlines or something similar that is confusing the image reader.
If you want to produce more image types than PPM, I am a fan of stb_image.h , a header-only image library available on GitHub at https://github.com/nothings/stb.