Skip to content

Fisheye fix

Vinicius Reif Biavatti edited this page Apr 16, 2021 · 20 revisions

Distorted view

After we implemented the RayCasting and ran the code, we could check that the walls of the projection were distorted. This occurs because the method to throw the ray that we used starts from player, so the side rays will be more distant then the middle rays. This effect is called Fisheye. To corret it, we need to translate the distance of the rays removing the distorted distance in relation of the player. Check the image below for understand:

Coparing of the fisheye and normal view

Based of the first example, we can see the right triangle between player position and wall position. The value of the angles needs to be processed to get the correction of the distorted distance. To make it, we can use trigonometry to find the value. Looks the image below:

SOH CAH TOA trigonometry formulas

These are the trigonometry formulas we can use to discover some trigonometry values. The situation we have is the same below (I used some fictional values to help the undertanding the formula later):

Demonstration of ray casting with distorted view and correct view

The view to the wall collision is a right triangle. The wrong distance is the "hypotenuse", the angle is the ray angle, and the correct distance is the adjacent side (that we need to discover). We have the hypotenuse value and the angle, so we can check the trygonometry formulas to try to find the value we want. Checking the SOH CAH TOA formulas, we conclude that we can use the CAH (cosine formula). For this example, I used some fictitious values.`

hypotenuse = 10
angle = 30
adjacent_side = x

// Formula
COS(angle) = adjacent_side / hypotenuse

// Rotate the formula to solve the problem
COS(angle) = adjacent_side / hypotenuse
COS(angle) * hypotenuse = (adjacent_side / hypotenuse) * hypotenuse // (Add multiplier)
COS(angle) * hypotenuse = adjacent_side // (Remove redundant)
adjacent_side = hypotenuse * COS(angle) // Right!

Note: Remmember to use angles as radians, not arcs (degrees)!

Now, we have our formula! But there is a problem. The angle we used is the entire angle (Player angle + ray angle). We have to use just the ray angle to get the correct adjacent side value (correct distance), so, the formula in the code will be:

Formula: adjacent side = hypotenuse * COS(ray angle - player angle)

Code: distance = distorted_distance * Math.cos(ray_angle - player_angle)

This formula will be applied after get the distance in rayCasting() function. The code will be:

// ...

// Pythagoras theorem
let distance = Math.sqrt(Math.pow(data.player.x - ray.x, 2) + Math.pow(data.player.y - ray.y, 2));

// Fish eye fix
distance = distance * Math.cos(degreeToRadians(rayAngle - data.player.angle));

// Wall height
let wallHeight = Math.floor(data.projection.halfHeight / distance);

// ...

After this fix, you can check the result running the code fixed.