# Ray Tracing in a Weekend Part 3 - The Ray Class

## The Ray Class

In part 2 I added a vec3 class to help with 3-dimensional vector calculations.

This chapter moves it one step further by introducing a new ray class. A ray can be thought of as a function

$p(t) = A + t * B$

where p is a 3D position along a line, A is the ray origin, B is the ray direction, and t is the ray parameter which moves p(t) along the ray. If t is positive you get the points in front of the origin A, also called a half-line or half-ray.

I’ll only include new and modified parts of the code. Please check my git-repository at https://github.com/celeph/ray-tracing-in-a-weekend for complete example code with makefiles.

The ray class is a literal implementation of the equation in 3D vectors:

ray.h

#ifndef RAYH
#define RAYH
#include "vec3.h"

class ray {
public:
vec3 A;
vec3 B;

ray() {}
ray(const vec3& a, const vec3& b) { A = a; B = b; }

vec3 origin() const { return A; }
vec3 direction() const { return B; }
vec3 point_at_parameter(float t) const { return A + t * B; }
};
#endif


The new loop moves the ray across the entire image and determines a color at each pixel. The color function only returns a gradient based on the y-position at this time.

The size of the image is set to 4 x 2, where the origin is set into the center of image (0,0,0), the lower left corner is at (-2,-1,-1), the upper right corner is at (2,1,-1). The z-coordinate is set at -1 into the screen to respect the convention of a right-handed coordinate system. The screen is 1 unit apart from the origin (eye or camera). Positive values for z are behind the origin.

ray-example.cpp

#include <iostream>
#include "vec3.h"
#include "ray.h"

vec3 color(const ray& r) {
vec3 unit_direction = unit_vector(r.direction());
float t = 0.5f * (unit_direction.y() + 1.0f);
return (1.0f - t) * vec3(1.0f, 1.0f, 1.0f) + t * vec3(0.5f, 0.7f, 1.0f);
}

int main() {
int nx = 200;
int ny = 100;

std::cout << "P3\n" << nx << " " << ny << "\n255\n";

vec3 lower_left_corner(-2.0, -1.0, -1.0);
vec3 horizontal(4.0, 0.0, 0.0);
vec3 vertical(0.0, 2.0, 0.0);
vec3 origin(0.0, 0.0, 0.0);

for (int j = ny-1; j >= 0; j--) {
for (int i = 0; i < nx; i++) {
float u = float(i) / float(nx);
float v = float(j) / float(ny);

ray r(origin, lower_left_corner + u * horizontal + v * vertical);
vec3 col = color(r);

int ir = int(255.99 * col[0]);
int ig = int(255.99 * col[1]);
int ib = int(255.99 * col[2]);

std::cout << ir << " " << ig << " " << ib << "\n";
}
}
}


## Javascript and 2D Canvas

Here’s also the same example in Javascript.

class ray {
constructor(a,b) { this.A = a; this.B = b; }

origin() { return this.A; }
direction() { return this.B; }
point_at_parameter(t) { return A + t * B; }
}

var example = {
color: function(r) {
var unit_direction = r.direction().unit_vector();
var t = 0.5 * (unit_direction.y + 1.0);
return (new vec3(1.0, 1.0, 1.0))
.mul(1.0 - t)
(new vec3(0.5, 0.7, 1.0)).mul(t)
);
},
main: function() {
var c = document.getElementById('example');
var ctx = c.getContext('2d');

var nx = 200;
var ny = 100;

var lower_left_corner = new vec3(-2.0, -1.0, -1.0);
var horizontal = new vec3(4.0, 0.0, 0.0);
var vertical = new vec3(0.0, 2.0, 0.0);
var origin = new vec3(0.0, 0.0, 0.0);

for (var j = ny-1; j >= 0; j--) {
for (var i = 0; i < nx; i++) {
var u = parseFloat(i) / parseFloat(nx);
var v = parseFloat(j) / parseFloat(ny);