# Fisheye effect on 3D projection

When I'm far away, the walls look nice, but when I'm near the walls they get a weird fisheye effect:

Here is the code for the raycasting:

And the code for drawing:

As mentioned in the comments, there are other posts here about solving this problem in other frameworks; I'm having difficulty translating those answers into the Scratch.

• We have quite a bit of existing Q&A about how to correct for this effect in raycasting, including the thread Theraot linked above, this one, another, and another, and more. Usual culprits are stepping your rays in equal angular increments, and using the length of the ray instead of its forward depth. Your code makes both these mistakes. Commented Mar 12, 2023 at 13:25

Although as noted above we have lots of past Q&A about solving this problem in other frameworks, I think it's understandable if a Scratch user would have difficulty translating that code into the equivalent LEGO-block representation.

Here's the corrected raycasting routine:

1. I've added a "linear offset" variable, representing the position of the column of the screen this ray represents: -48 for the left-most column, +48 for the right-most, and 0 in the middle.

2. The "repeat 96" loop now increments linear offset, not angular offset. As I explain in this answer and this one, incrementing by angle only makes sense if you're rendering on a curved screen that wraps around your head, so the columns of pixels have equal angular spacing.

When we're rendering on a flat monitor, columns of pixels have equal linear spacing, which means the angular spacing is non-uniform: columns of pixels are further apart in the angular space of our eye where the surface of the monitor is perpendicular to our gaze, and they bunch up as the monitor recedes away to either side, through foreshortening. So...

3. We calculate the "angular offset" from the linear offset, using the trigonometric arctangent function to get this non-uniformity. You can think of the divisor there as being the distance from the monitor to your eye: smaller divisors = sitting closer to the window = seeing more at the edges (wider field of view), though this can also make the image look distorted if the player is actually viewing from farther away.

4. The depth value we use to draw the walls should measure only the forward component of the depth. Things don't get shorter in linear perspective when they move left and right parallel to the image plane, even through the distance the ray has to travel diagonally to reach them increases. So we multiply by cosine (adjacent divided by hypotenuse) to extract just the forward component of the ray's length.

Now we get nice straight-line walls:

You can see the walls stay straight (to within the limited resolution of the discrete ray hops) even up-close.