4 ‐ Ray Casting - shoganaix/42Cub3d GitHub Wiki

Ray Casting

Rays are cast and traced in groups based on some geometric constraints.

For instance: on a 320×200 display resolution, a ray-caster traces only 320 rays (the number 320 comes from the fact that the display has 320 horizontal pixel resolution, hence 320 vertical column).

  • Faster but inexact.
  • Small storage.
  • Render on the fly.

Vs. RAY-TRACING

RAY-TRACING: each ray is traced separately, so that every point (usually a pixel) on the display is traced by one ray.

For instance: on a 320×200 display resolution, a ray-tracer needs to trace 320×200 (64,000) rays. (That is roughly 200 times slower than ray-casting.).

  • Slower, but exact.
  • Usually some renders are cached

Creating our world

Variables

  • cube size CxCxC (The larger the size of the cube, the blockier the world will look like, but smaller cube will make the rendering slower)
  • map as a grid

Projection attributes

  • player
    • height - C/2
    • FOV - field of view (60 deg)
    • POV: position (x, y) + orientation ( ALPHA deg)
  • Projection plane's dimension - the window's size: W * H = n_rays * H
  • Relationship between player and projection plane
    • angle between subsequent rays: ray_angle = FOV / n_rays
    • distance between the player and the projection plane. dist_to_plane = (n_rays/2) / tan(FOV /2)

image

INDEX

Based on the viewing angle, subtract 30 degrees (half of the FOV)

For each column (there's a ray for each column):

  1. From the player, trace the ray until it hits a wall. - FIND WALL COLLISION POINT
  2. Record the distance to the wall (the distance is equal to the length of the ray). - FIND DISTANCE TO WALL
  3. find projection wall height using the distance to the wall, distance to the projection plane and wall height. - FIND PROJECTION WALL
  4. Find p1 y p2 that define the wall slice in the projection slice.- DEFINE UPPER AND BOTTOM SLICE
  5. Map projection to wall texture : image_slice receives image and proportion
  6. Draw Slice (loop)-> draw slice on buffer: ceiling, image_slice, floor

STEPS

Starting from column 0, Suppose FOV = 60

A. Cast a ray.

B. Trace the ray until it hits a wall. (FINDING WALLS)

C. Record the distance to the wall (the distance is equal to the length of the ray). (FINDING DISTANCE TO WALLS + DRAWING WALLS + TEXTURE MAPPED WALLS)

D. Add the angle increment so that the ray moves to the right (we know from Figure 10 that the value of the angle increment is 60/320 degrees)

E. Repeat step 2 and 3 for each subsequent column until all 320 rays are cast.

#1. Based on the viewing angle, subtract 30 degrees (half of the FOV).
orientation = 90 # N=90, W=180, ..
ray_angle = orientation - FOV/2
For each ray_angle : # nrays = ncols = W

  # # DRAW WALL SLICE : sky | texture | floor -------
  # 1. FIND WALL COLLISION POINT
  wall_collision_point = ray_collides_wall(...)
  # 2. FIND DISTANCE TO WALL
  ray_len = dist_player_to_point(wall_collision_point) 
  # 3. FIND PROJ WALL HEIGHT
  projected_slice_height = get_proj_height()
  # 4. FIND DIVIDING POINTS
  get_wall_slice_points = ...
  # 5. MAP PROJECTION TO WALL TEXTURE
  image_slice =  # receives image and proportion
  # 6. DRAW SLICE ON IMAGE. draw slice on buffer: ceiling, image_slice, floor
  img ....
  angle ++

1. FINDING WALLS

process vertically and horizontally separated, get the closest one

dist_h, int_h = horizontal_intersection(...)
dist_v, int_v = vertical_intersection(...)
wall_inters = min(int_h, int_v, key=dist) # choose the closest one

2. FINDING DISTANCE TO WALLS

calculate real distance and refine

CAREFUL with “fishbowl effect” Fishbowl effect happens because ray-casting implementation mixes polar coordinate and Cartesian coordinate together. Therefore, using the above formula on wall slices that are not directly in front of the viewer will gives a longer distance. This is not what we want because it will cause a viewing distortion such as illustrated below.

How do we do refine:

The resulting distance obtained must be multiplied by cos(BETA)

figure17

where BETA is the angle of the ray that is being cast relative to the viewing angle

ALPHA is 90 degrees because the player is facing N. Because we have 60 degrees FOV, BETA is 30 degrees for the leftmost ray and it is -30 degrees for the rightmost ray

3. DRAWING WALLS

We draw each wall slice at a time. We use function draw_slice that receives an offset, the direction and the upper and bottom points(double pointer)

void draw_slice(t_game *game, int p_wall[2][2], t_card cardinal, int offset)

we know

d = the distance of the player to the wall slice (ray length) so we can calculate the projected slice height.

proj_slice_H = C / d * 277

dist_to_plane = 277

Slice
[--------[||||||||+||||||||]---------]
[ window height                      ]
         [ wall/2 + wall/2 ]
                centre

4. TEXTURE MAPPED WALLS

What is texture mapping?

Texture mapping refers to painting a bitmap/texture onto a surface.

For our cub3d world, we CAN use bitmaps that have the size of C by C pixels. It is possible to use different size bitmaps, but using the same size simplifies the process. To draw this on screen, is just a matter of scaling a slice (or column) of bitmap

The offset is the position of the ray relative to the grid. This offset can be found and used to determine which column of the bitmap is to be drawn as the wall slice.

if the slice is on a vertical collision 
 OFFSET = y % C
on horizontal collisions
 OFFSET = x % 64