Skip to content

A modified version of Raycasting Basics with JavaScript of GUSTAVO PEZZI from https://www.pikuma.com

License

Notifications You must be signed in to change notification settings

HardCoreCodin/Rational-Ray-Casting

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Rational Ray Casting

This is a modified version of the one detailed in: Raycasting Basics with JavaScript
By: Gustavo Pezzi

This work is meant to be a practical demonstration of how transcendental functions can be avoided completely
in a computer graphics rendering programs, while at the same time making the code simpler and faster.

This work is inspired by the work of professor Norman J. Wildberger of the University of New South Wales
In particular: WildTrig: Intro to Rational Trigonometry

This implementation does not make use of any angles or measures of distances(!)
It intentionally avoids any transcendental functions such as:

  1. sin()
  2. cos()
  3. tan()
  4. sqrt()

It does not achieve that through traditional means such as substitution with tables or approximation.
Instead, a purely rational approach is taken all throughout.

This implementation relies heavily on the rational parameterization of the unit circle
by projecting 2D position coordinates onto a unit circle to be used as pure directional unit vectors.
These are then used to represent the orientation of the player and the rays,
as well as for constructing 2D rotation matrices for re-orienting them.

The original implementation had 2 distances computed for the horizontal and vertical hits.
They were positive distance measures which were subsequently used for each ray to:

  1. Determine which of the horizontal vs. vertical hits is the closest.
  2. Compute the height of each pixel column in the 3D viewport.

The 2 hit distances were computed using the pythagorean theorem (involving a square root).
They were then compared to determine which of the 2 hits is closest.
Given how these distances are always positive, as long as their only use is for comparing them,
their squares can be compared instead, avoiding the square root.
However that was not possible in the original implementation, because these distances were also
used to compute the height of each pixel column: To get at a perpendicular distance for each ray,
a trigonometric cos() function was applied onto the closest distance of the two.
To that end, a square root was needed to be taken to get at that actual closest distance measure.

This alternative implementation represents orientations as 2D unit-vectors, as opposed to angles.
The same perpendicular distance is attained by projecting each ray's vector onto the
player's orientation vector by taking their dot product (a.k.a: Inner Product).
This avoids both the square root and the cos function (both of which are transcendentals).
And given how the only use left for the ray hit point distances is to compare them,
the squares of the distances are used for the comparison instead, avoiding the square root entirely.

The original implementation used the tan() function to get at the horizontal and vertical steps.
That was convenient given how the orientation of the rays was represented as angles.

Given how this alternative implementation represents these orientations as unit vectors,
the same ratio represented by the tan() is attained by a simple division of the vector's components.

Lastly, the original implementation used an angle for the field of view (a.k.a: FOV).
This determines the spread between the origin and the projection plane.
Using an angle to represent this spread is a very common practice in computer graphics programs.
For a given projection plane, changing this angle affects the strength of the perspective distortion.
However, what this angle is invariably used for is just for getting at a certain ratio:
In a pin-hole camera model, the distance of the pin-hole to the projection plane is the focal length.
The ratio between this focal length and (half-of)the width of the projection plane,
is the actual factor that determines the spread (the strength of the perspective distortion)
This ratio (which can be termed the FOV-ratio) can be changed by changing either
the focal length or the width of the projection plane. An FOV angle is just one way to represent this ratio,
independently from the actual mesurements of the focal length and projection plane width.

This alternative implementation avoid using an FOV-angle, by having the focal length as the input instead.
A normalized coordinate system for the projection plane would have it set with a width of 2 (-1 to 1).
A focal length of 1 in such a case would yield an FOV-ratio of 1:1, since half of the width of 2 is 1.
This would be equivalent to a field of view angle of 90 degrees (or a half-angle of 45 degrees).
Given such a projection plane of fixed size, the focal length is inversely proportional to the strength
of the perspective distortion, such that a longer focal length is equivalent to a narrower field of view.
The FOV-ratio can thus be computed very simply by dividing half of the width (1) by the focal length.

In this implementation ray directions are produced using the parametric form of the unit circle.
However this requires a focal length of 1. When the focal length is defined as a number other than 1,
the projection plane could instead be scaled by an inverse amount to complensate.
This maintains the same FOV-ratio (perspective sterngth), while keeping the focal length at 1.
It is a very common practice for perspective projection in graphics APIs (such as OpenGL or Direct3D).

About

A modified version of Raycasting Basics with JavaScript of GUSTAVO PEZZI from https://www.pikuma.com

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages