YassineEddyb / miniRT_42

My first RayTracer

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

MiniRT

This project is 42 project that aimes to introduce us to the beautiful world of Raytracing

1337 image generated by miniRT

What is ray tracing

In 3D computer graphics, ray tracing is a technique for modeling light transport for use in a wide variety of rendering algorithms for generating digital images.

Install

Clone this repository:

git clone https://github.com/YassineEddyb/miniRT_42 && cd miniRT_42 && make

Then run the program with a file as an argument from the scenes folder:

./miniRT ./scenes/1337.rt

How to use it:

You can also create your own scene, Just create a file with .rt extention and configure it.
There is three conifg object that are mandatory to have:

  • Ambient
  • Light
  • Camera

And four basic shapes that are (optional, will not entirely cause if you leave it empty you will only see a black window):

  • Plane
  • Sphere
  • Cylinder
  • Cube

Position: 20,3,0 => x,y,z coordinates
Oreintation: 0,1,0 => 3d normalized orientation vector. In range [-1,1] for each x,y,z axis
Color: 255,0,255 => R,G,B colors in range [0,255]
Shininess: 200 => how much the surface shine in range [0,200]
Reflection: 1 => how much the surface reflect in range [0,1]

Images generated by miniRT

How it works?

in case you're wondering how all this works? just loop over all pixels and generate a ray for each one, then see if intersects with any object and calculate the color for this pixel, sounds simple isn't it, well it's not.

Here is some resourses:

My explanation

Some things you have to know

  • First of all you should be familiar with matrixes and vectors, Check this article from scratchapixel geometry.

  • Structures needed for this lesson

ray {
  vector origin # start of the ray
  vector dir # direction of the ray
}

sphere {
  vector pos # position of the sphere
  matrix transform # transformation matrix of the sphere
}
  • in this lesson well draw a sphere and the same method go for other basic shapes.
  • Intersection of the sphere will be in object space then we will transform it to world space see Object space vs World space.

1- Generating rays

In orther to generate rays in real life you would have to implement a camera but we'll keep thing simple here.

General configurations

Width = 150
Height = 100

ray.pos = point(0, 0, -5)
sphere.pos = point(0,0,0)
sphere.transform = identity_matrix;
  
fov = PI/2

We'll implement a function that calculates the direction of the ray

fucntion get_ray_direction(Width, Height, x, y, fov)
  # get the aspect ratio
  if Widht > Height
    AspectRatio = Width / Height;
  else 
    AspectRatio = Width / Height;

  # compute the world y coordinate
  world_x = (2 * ((x + 0.5) / Width) - 1) * tan(fov / 2 * M_PI / 180) * AspectRatio; 

  # compute the world x coordinate
  world_y = (1 - 2 * ((y + 0.5) / Height) * tan(fov / 2 * M_PI / 180);

  # describe the point that the ray will target
  vector position = point(world_x, world_y, 0)

  # get ray direction
  return normalize(ray_dir - ray_origin);
end function

2- Ray Sphere intersection

After generating rays we'll see if they intersect with a sphere.

We know the equation of a line:

P = O + tD

Where :

  • P: a point on the line
  • O: the origin on the line
  • t: the scaler just think of it a number
  • D: the direction of the line

We also know the equation of a sphere:

(x - a)2 + (y - b)2 + (z - c)2 = r2

Where:

  • a,b,c: the position of the sphere
  • x,y,z: a point from the sphere
  • r: the raduis of the shpere

Assuming that the sphere postion is on 0,0,0.

(x - 0)2 + (y - 0)2 + (z - 0)2 = r2
x2 + y2 + z2 = r2
x2 + y2 + z2 - r2 = 0

Remember that x,y,z are the cordinates of a point in the sphere so we can write it as

P2 - r2 = 0

If we replace P with it's value from the equation of a line we get:

|O + tD|2 - r2 = 0

When we expand this equation we get:

O2 + (Dt)2 + 2ODt − r2 = 0
D2t2 + 2ODt + O2 - r2 = 0

It looks like:

ax2 + bx + c = 0

Where:

  • a => D2
  • b => 2OD
  • c => O2 - r2

So we can solve it using the Quadratic Formula

t1,2 = (-b ± √Δ) / 2a

Where:

Δ = b2 - 4ac
  • if Δ > 0 => the ray intersects the sphere in two points
  • if Δ = 0 => the ray intersects the sphere in one points
  • if Δ < 0 => the ray does not intersects with the sphre

Now we can implement the ray sphere intersection function In pseudocode

function ray_sphere_intersection(sphere, ray)
  # first transform the ray by the inverse of transform matrix
  transformed_ray.origin = ray.pos * sphere.transform
  transformed_ray.dir = ray.dir * sphere.transform
  
  # convert the origin of the ray to a vector
  origin = trasformed_ray.origin - sphere.pos

  # D2
  a = dot(transformed_ray.dir, transformed_ray.dir)

  # 2OD
  b = 2 * dot(orgin, transformed_ray.dir)
  
  # O2 - r2 // r = 1
  c = dot(origin, origin) - 1
  
  # b2 - 4ac
  discriminant = b * b - 4 * a * c
  
  if (discriminant < 0)
    return false
  else
    return true
  end if
end function

finaly we can draw something by merging what we learnd so far

# for each row of pixels in the canvas
for y = 0 to Width - 1
  # for each pixel in the row
  for x = 0 to Height - 1
    ray.dir = get_ray_direction(Width, Hight, x, y, fov)

    if ray_sphere_intersection(sphere, ray)
      put_pixel_to_window(x, y, red)

  end for
end for

You will get something like this:

Working on it...

About

My first RayTracer


Languages

Language:C 97.0%Language:Makefile 3.0%