DDA Graphical Algorithm: Find the Length of a Vector

Mampac

New member
Joined
Nov 20, 2019
Messages
48
Hi there,

I'm doing a project for my programming school which concerns ray-casting to render images for a game.

The game is defined on a 2D-grid map, where the squares are either empty spaces, where the player can freely move, or solid walls.

Therefore the Player is always standing inside an empty square. They are looking in a direction defined by a direction vector, whose X and Y, called dirX and dirY, are in range [-1, 1].

The Player, then, emits a number of rays from its position to look to the left and to the right of their direction vector.

The program has to understand when the ray hits a wall. Since adding a constant value is inefficient (the ray can "skip" the wall; thus an infinitely small constant has to be added, which is impossible), there's an algorithm to add a value which will jump exactly on square sides:

1616482246219.png

The material I was provided with proposes the following algorithm:

1616482350817.png

Where deltaDistY is the distance from one horizontal, y-side to another and deltaDistX is the distance from one vertical, x-side to another (sideDistX, sideDistY are the initial distance from the player's location, but it's not the matter in this case).

The author states that geometrically, the deltas, using Pythagoras, are equal to:

[MATH]deltaDistX = \sqrt{1 + {\dfrac{rayDirY^2}{rayDirX^2}}}[/MATH][MATH]deltaDistY = \sqrt{1 + {\dfrac{rayDirX^2}{rayDirY^2}}}[/MATH]
What I do see is that the deltas are essentially the hypotenuses of the triangles; one of their sides is always 1 (the side of a square), but how is the other leg found? Why are the coordinates squared and divided by each other? This doesn't fit in any formulae I know about vectors (say norm of a vector, distance between points etc.) The author simplifies the formula further, by stating that

[MATH]deltaDistX = |{\dfrac{|v|}{rayDirX}}|[/MATH][MATH]deltaDistY = |{\dfrac{|v|}{rayDirY}}|[/MATH]
where [MATH]v[/MATH] is the length of the ray's direction vector (which depends on the player's direction vector, which is a variable), and is equal to [MATH]\sqrt{rayDirX^2 + rayDirY^2}[/MATH].

The author didn't go into math deeply, because they were rather focused on the coding aspect of the guide, so I'm stuck at this point and can't proceed. I'm taking Linear Algebra class this semester; it surely did aid me in grasping the material but I, including a couple of my friends I asked for help, failed to recall such formulae. Can anyone help me?
 
This diagram might help you to find the formula for deltaDistX (length 0E)...

similarTris.png

First find length EF (hint: can you see any similar triangles?). Then, can you continue to find 0E?

When you've got this, then please post back and I (or someone else) will try to help with your next question.
 
This diagram might help you to find the formula for deltaDistX (length 0E)...

View attachment 25948

First find length EF (hint: can you see any similar triangles?). Then, can you continue to find 0E?

When you've got this, then please post back and I (or someone else) will try to help with your next question.
Indeed, [MATH]0BC[/MATH] and [MATH]0EF[/MATH] are similar, therefore [MATH]{\dfrac{0F}{0C}} = {\dfrac{E0}{B0}}[/MATH], which in this case means [MATH]{\dfrac{1}{rayDirX}} = {\dfrac{E0}{|rayDir|}}[/MATH]. The length of the ray's direction vector is found by the formula [MATH]\sqrt{rayDirX^2 + rayDirY^2}[/MATH]. This proportion implies that [MATH]E0 = {\dfrac{|rayDir|}{rayDirX}} = {\dfrac{\sqrt{rayDirX^2 + rayDirY^2}}{rayDirX}} = \sqrt{{\dfrac{rayDirX^2 + rayDirY^2}{rayDirX^2}}} = \sqrt{1 + {\dfrac{rayDirY^2}{rayDirX^2}}}[/MATH]It seems like I finally understood it, thanks! but i still have a doubt. This particular case is when the player's direction vector's components are equal (so that the angle is 45 degrees). Will this handle different angles as well?
 
...This particular case is when the player's direction vector's components are equal (so that the angle is 45 degrees). Will this handle different angles as well?

Your post looks good to me, well done! I can't see anything there that relies on a 45° angle, which step gives you this doubt? The similar triangle step doesn't rely on any angles being 45°.

You should program some exceptions for cases when rayDirX=0 and rayDirY=0, but hopefully your book will cover this.
 
Your post looks good to me, well done! I can't see anything there that relies on a 45° angle, which step gives you this doubt? The similar triangle step doesn't rely on any angles being 45°.
I tried some examples and it works out with different angles as well. Thanks!
You should program some exceptions for cases when rayDirX=0 and rayDirY=0, but hopefully your book will cover this.
This however bugs me. The book provides this solution:
1616565716198.png
Hope you're familiar with programming (these are ternary operators)
I can't see, however, why is one of them set to 0 while the other to 1.
Say I have a direction vector (-1, 0) which makes the player look West.
Then I emit a ray from this position to see if there's a wall to the West to draw a line on the screen. rayDirX = -1, rayDirY = 0
in the first line, the first ternary condition evaluates to true, thus deltaDistX = 0.
second line; the first ternary evaluates to false, thus the second ternary is executed: its condition evaluates to true, thus deltaDistY = 1.
Doesn't it have to be the other way around? This ray will never hit a horizontal line, and deltaDistY is the distance between horizontal lines (after the ray exits its initial square). deltaDistX, on the contrary, shows the distance between vertical lines, which has to be 1 (West-looking vector, huh!) but is set to 0.

Later on, these deltaDistX and deltaDistY are used in the algorithm which will calculate when a wall is hit by comparing lengths of the ray which is always incremented by either deltaDistX or deltaDistY (each incrementation moves one row up/down or one column left/right, and at the end of the loop that element of the matrix is checked such that if it's a 1 then the loop terminates).

Do you think I should post another thread about this one or you prefer replying here?
 
Doesn't it have to be the other way around?

I agree with your arguments, this code is probably incorrect, but I can't say for sure because I haven't seen the code that comes afterwards. But please don't post the whole routine - at least not until you've written a simple test function to see if the routine as a whole actually works under these circumstances. (I'm not sure what the moderators think about posting this code, since this is a math forum, but I guess this code is quite mathematical in nature).

I guess the author probably wants to concentrate on the common case of rayDirX and rayDirY being non-zero. If you can understand how the 2d code works (or hopefully works!) , then it shouldn't be too hard for you to code something yourself that deals with the 1d exceptional cases...

if (rayDirX==0 && rayDirY==0) { error }
else if (rayDirX==0) { just look along Y }
else if (rayDirY==0) { just look along X }
else { look along both X and Y }

...but to be honest, if this is just for a simple project, then I'd be inclined to give rayDir a VERY small rotation (when this happens) to ensure that X and Y components can never be zero.
 
Top