Implementation/port of Lode Vandevenne´s Raycaster behaving weirdly

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
User avatar
NoreoAlles
Party member
Posts: 107
Joined: Mon Jan 03, 2022 5:42 pm

Implementation/port of Lode Vandevenne´s Raycaster behaving weirdly

Post by NoreoAlles »

I recently posted about having issues with a raycaster, to which i got very helpful answers and even a fully implemented raycaster. After looking at the website (https://lodev.org/cgtutor/raycasting.html) which Bigfoot showed me i tried implementing the dda algorithm which this site covers, but now i have almost the exact same issues as before, the rays being casted in the wrong direction and being kindof cluttered, which shouldnt happen. I suspect one of the issue lies in how i tried to "translate " these lines of c++ into lua :

Code: Select all

double deltaDistX = (rayDirX == 0) ? 1e30 : std::abs(1 / rayDirX);
double deltaDistY = (rayDirY == 0) ? 1e30 : std::abs(1 / rayDirY);
	|
        \/
 if rayDirx == 0 then 
            deltaDistX = 1e30 
        else 
            deltaDistX = math.abs(1 / rayDirx)
        end
        if rayDiry == 0 then 
            deltaDistY = 1e30 
        else 
            deltaDistY = math.abs(1 / rayDiry)
        end
there are probably even more mistakes which is why i´ll attach a .love
I hope its not against the rules for me to post about such a similar issue twice.

Edit:
i found a mistake in line 162 where i had to replace the second lineheight with the screenheight, so know i can see some rendering, but the other issues remain

Edit2: i fixed all the actual drawing code:
I think one of the issues is how i rotate the camera plane, as the world looks skewed just like in the example on the website, i´ll try fixing that, but i still have no clue why the rays spread like that

Code: Select all

if side == 0 then perpWallDist = (sideDistX - deltaDistX) 
        else perpWallDist = (sideDistY - deltaDistY) end
        local lineheight = math.floor(wall_height / perpWallDist)

        local drawStart = math.floor(-lineheight / 2 + screen_height / 2)
        if drawStart < 0 then drawStart = 0 end 
        local drawEnd = math.floor(screen_height / 2 + lineheight / 2 )
        if drawEnd > screen_height then drawEnd = screen_height - 1 end 
        love.graphics.setColor(1, 0, 0,1 )
        love.graphics.line(x, drawStart, x, drawEnd)
Edit 3:
I have found and fixed one more issue, my rotation code

Code: Select all


        if love.keyboard.isScancodeDown("d") then 
            --both camera direction and camera plane must be rotated
            local oldDirX = self.delX
            self.delX = self.delX * math.cos(-self.rotation_speed) - self.delY * math.sin(-self.rotation_speed)
            self.delY = oldDirX * math.sin(-self.rotation_speed) + self.delY * math.cos(-self.rotation_speed)
            local oldPlaneX = self.planeX
            self.planeX = self.planeX * math.cos(-self.rotation_speed) - self.planeY * math.sin(-self.rotation_speed)
            self.planeY = oldPlaneX * math.sin(-self.rotation_speed) + self.planeY * math.cos(-self.rotation_speed)
        end
        if love.keyboard.isScancodeDown("a") then 
            --both camera direction and camera plane must be rotated
            local oldDirX = self.delX
            self.delX = self.delX * math.cos(self.rotation_speed) - self.delY * math.sin(self.rotation_speed)
            self.delY = oldDirX * math.sin(self.rotation_speed) + self.delY * math.cos(self.rotation_speed)
            local oldPlaneX = self.planeX
            self.planeX = self.planeX * math.cos(self.rotation_speed) - self.planeY * math.sin(self.rotation_speed)
            self.planeY = oldPlaneX * math.sin(self.rotation_speed) + self.planeY * math.cos(self.rotation_speed)
        end
Attachments
dda-raycaster.love
Updatet it with all the stuff i could fix
(377.22 KiB) Downloaded 32 times
"Why do they call it oven when you of in the cold food of out hot eat the food?" - Jon Arbuckle
User avatar
Bigfoot71
Party member
Posts: 287
Joined: Fri Mar 11, 2022 11:07 am

Re: Implementation/port of Lode Vandevenne´s Raycaster behaving weirdly

Post by Bigfoot71 »

Your post made me want to do one too with Löve2d ^^

So I started again like you and here is where I am with the update function, it is functional but not yet cleaned:

Code: Select all

function Raycaster:update(px, py, dir_x, dir_y, plane_x, plane_y)

    -- Define local self values --

    local num_rays = self.num_rays
    local screen_height = self.screen_height
    local h_screen_height = self.h_screen_height

    local map = self.map

    local r = self.result
    r.px, r.py = px, py

    -- Perform raycasting --

    local j = 1 -- i: 11 by 11

    for i = 1, num_rays do

        local map_x, map_y = self:posToMap(px,py)   -- Initial position of the ray in the map table

        local cam_x = 2 * i / num_rays - 1          -- x coordinate in camera space
        local ray_dir_x = dir_x + plane_x * cam_x
        local ray_dir_y = dir_y + plane_y * cam_x

        -- We get the distance to the edge of the next square --

        local dx = (ray_dir_x == 0) and 1e30 or math.abs(1/ray_dir_x)
        local dy = (ray_dir_y == 0) and 1e30 or math.abs(1/ray_dir_y)

        -- We calculate the initial step and the length to the side --

        local step_x, side_dist_x;
        local step_y, side_dist_y;

        if ray_dir_x < 0 then step_x, side_dist_x = -1, (px-map_x)*dx
        else step_x, side_dist_x = 1, (map_x+1-px)*dx end

        if ray_dir_y < 0 then step_y, side_dist_y = -1, (py-map_y)*dy
        else step_y, side_dist_y = 1, (map_y+1-py)*dy end

        -- We launch the ray --

        local side; repeat  -- DDA

            if side_dist_x < side_dist_y then
                side_dist_x = side_dist_x + dx
                map_x = map_x + step_x
                side = 0
            else
                side_dist_y = side_dist_y + dy
                map_y = map_y + step_y
                side = 1
            end

        until not map[map_y] or map[map_y][map_x] ~= 0;

        -- Add ray data to result table --

        local distance_to_wall = (side == 0) and side_dist_x - dx or side_dist_y - dy
        local wall_height = screen_height / distance_to_wall -- Calculation of the wall height
        local wall_height_half = wall_height * .5

        r[j]    = px + ray_dir_x * distance_to_wall             -- HIT X
        r[j+1]  = py + ray_dir_y * distance_to_wall             -- HIT Y
        r[j+2]  = ray_dir_x                                     -- RAY DIR X
        r[j+3]  = ray_dir_y                                     -- RAY DIR Y
        r[j+4]  = distance_to_wall                              -- DIST TO WALL
        r[j+5]  = i                                             -- WALL X
        r[j+6]  = -wall_height_half + h_screen_height           -- WALL Y1
        r[j+7]  = wall_height_half + h_screen_height            -- WALL Y2
        r[j+8]  = wall_height                                   -- WALL H
        r[j+9]  = map[map_y][map_x]                             -- texNum
        r[j+10] = side                                          -- side

        -- We go to the next next ray --

        j = j + 11

    end

end
The code is still a bit rough, I'm working on it and some bugs are still to be fixed but the algorithm part of the DDA is almost finished (cleanliness level) and totally functional.

I also allow myself to share my complete project with you because I also want to warn you of its limits. You will also face this problem and I don't want you to waste your time. For the version with texture, I am currently using the love.graphics.points method to display each pixel by retrieving the color from the texture. However, this method is very slow with love2d, so I'm looking for a way to improve it using a shader. It turns out to be more complicated than expected.

For the moment you can recover the DDA algorithm part that I wrote and which is functional. If I manage to make the texture part work in an optimized way and you are interested in it, it will be with pleasure. Do what you want with my code, there is no problem on this side ^^

To test with texture remove the `raycaster:setTextures` from the comment in main.lua.

(sorry for the comments, I did not translate them and they are not very precise as I work on them.)

Edit: Otherwise as you can see compared to ternary operators like in C/C++ like this:

Code: Select all

double deltaDistX = (rayDirX == 0) ? 1e30 : std::abs(1 / rayDirX);
double deltaDistY = (rayDirY == 0) ? 1e30 : std::abs(1 / rayDirY);
You can write it like this in Lua:

Code: Select all

local deltaDistX = rayDirX == 0 and 1e30 or math.abs(1 / rayDirX)
local deltaDistY = rayDirY == 0 and 1e30 or math.abs(1 / rayDirY)
Attachments
Raycasting.love
(31.07 KiB) Downloaded 28 times
Last edited by Bigfoot71 on Wed Mar 29, 2023 10:44 pm, edited 1 time in total.
My avatar code for the curious :D V1, V2, V3.
User avatar
NoreoAlles
Party member
Posts: 107
Joined: Mon Jan 03, 2022 5:42 pm

Re: Implementation/port of Lode Vandevenne´s Raycaster behaving weirdly

Post by NoreoAlles »

Bigfoot71 wrote: Wed Mar 29, 2023 10:28 pm For the moment you can recover the DDA algorithm part that I wrote and which is functional. If I manage to make the texture part work in an optimized way and you are interested in it, it will be with pleasure. Do what you want with my code, there is no problem on this side ^^

(sorry for the comments, I did not translate them and they are not very precise as I work on them.)
That is very nice of you :) , ill try to patch up my code while looking at yours. I dont get what you mean with the comments, arent they in english?
Edit: ah i see, you translated them for me in the post, thank you
Last edited by NoreoAlles on Wed Mar 29, 2023 10:46 pm, edited 1 time in total.
"Why do they call it oven when you of in the cold food of out hot eat the food?" - Jon Arbuckle
User avatar
Bigfoot71
Party member
Posts: 287
Joined: Fri Mar 11, 2022 11:07 am

Re: Implementation/port of Lode Vandevenne´s Raycaster behaving weirdly

Post by Bigfoot71 »

In the .love file they are not all in English, some are in French
My avatar code for the curious :D V1, V2, V3.
User avatar
NoreoAlles
Party member
Posts: 107
Joined: Mon Jan 03, 2022 5:42 pm

Re: Implementation/port of Lode Vandevenne´s Raycaster behaving weirdly

Post by NoreoAlles »

Just saw that, funnily enough i can read most of really basic french because of my latin lessons and your code explains itself so it isnt a problem.
"Why do they call it oven when you of in the cold food of out hot eat the food?" - Jon Arbuckle
User avatar
Bigfoot71
Party member
Posts: 287
Joined: Fri Mar 11, 2022 11:07 am

Re: Implementation/port of Lode Vandevenne´s Raycaster behaving weirdly

Post by Bigfoot71 »

Do not base your French on me, as it is supposed to be read only by me there are surely mistakes.
Surprising otherwise, you understand thanks to Latin, I never understood anything personally ^^
My avatar code for the curious :D V1, V2, V3.
User avatar
NoreoAlles
Party member
Posts: 107
Joined: Mon Jan 03, 2022 5:42 pm

Re: Implementation/port of Lode Vandevenne´s Raycaster behaving weirdly

Post by NoreoAlles »

Bigfoot71 wrote: Wed Mar 29, 2023 10:56 pm Do not base your French on me, as it is supposed to be read only by me there are surely mistakes.
Surprising otherwise, you understand thanks to Latin, I never understood anything personally ^^
:ultrahappy: haha
"Why do they call it oven when you of in the cold food of out hot eat the food?" - Jon Arbuckle
User avatar
NoreoAlles
Party member
Posts: 107
Joined: Mon Jan 03, 2022 5:42 pm

Re: Implementation/port of Lode Vandevenne´s Raycaster behaving weirdly

Post by NoreoAlles »

I could fix all of my code, i think the only real issue was how my planeX and planeY were calculated, as it now works flawless, without really having touched the actual raycaster. Thanks again! :awesome:
"Why do they call it oven when you of in the cold food of out hot eat the food?" - Jon Arbuckle
User avatar
Bigfoot71
Party member
Posts: 287
Joined: Fri Mar 11, 2022 11:07 am

Re: Implementation/port of Lode Vandevenne´s Raycaster behaving weirdly

Post by Bigfoot71 »

NoreoAlles wrote: Wed Mar 29, 2023 11:11 pm I could fix all of my code, i think the only real issue was how my planeX and planeY were calculated, as it now works flawless, without really having touched the actual raycaster. Thanks again! :awesome:
Indeed I also had this problem which pulled my hair out a bit, so I did the `Raycaster:getPlaneFromDir(dir_x, dir_y)` function (in raycaster.lua) to automatically get the correct plane vector from the directions, hoping that it works well every time.

Good luck for the texture part!
My avatar code for the curious :D V1, V2, V3.
User avatar
marclurr
Party member
Posts: 101
Joined: Fri Apr 22, 2022 9:25 am

Re: Implementation/port of Lode Vandevenne´s Raycaster behaving weirdly

Post by marclurr »

Bigfoot71 wrote: Wed Mar 29, 2023 10:28 pm However, this method is very slow with love2d, so I'm looking for a way to improve it using a shader. It turns out to be more complicated than expected.
I've actually gone down this exact rabbit hole fairly recently, I'd started with a fully software rendered version and while I'd managed to optimise it to a reasonable level I wanted to try and make it even faster. The shader version can render at 4k resolution with virtually no performance impact. This topic documents how I did it, the github is on there too if you want some inspiration. There's probably ways to improve it even more viewtopic.php?f=5&t=93880

If anybody is interested in the fully software version I can probably dig it out, but it's likely not much different from the many raycasters already posted on the forum.
Post Reply

Who is online

Users browsing this forum: No registered users and 44 guests