EDIT: Solved, but i have another issue with floor rendering using meshes (found below)
Hi all!
I've started working on a raycasting engine in love2d but i'm facing my first problem: sometimes when i get too close to a wall the screen won't render correctly. I'm still at the untextured stage of the engine, but i think that adding textures won't solve the problem... It looks like the player's face is sinking in the wall
Can anybody help me spotting the problem?
Thank you in advance!
Problem with raycasting (floor tiles)
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
Problem with raycasting (floor tiles)
- Attachments
-
- raycaster.love
- (5.82 MiB) Downloaded 195 times
Last edited by Tabaqui on Sat Feb 06, 2021 7:37 pm, edited 2 times in total.
Re: Problem with raycasting
It looks like a problem with Löve's line algorithm; not sure if it's a bug or just an expected loss of precision. Here is a test case, not sure if it can be reproduced everywhere:
These two lines should be rendered as one thick line, but the one at x=70 is rendered at x=69, causing a black line in between.
You can fix it in two ways: by drawing the lines using the pixel centres (i.e. just add 0.5 to every x and y coordinate in love.graphics.line), or by drawing 1-pixel rectangles instead of lines, which will probably be less computationally expensive.
Code: Select all
love.graphics.setLineStyle("rough")
function love.draw()
love.graphics.line(70, 49138.421592350249, 70, -48658.421592350249)
love.graphics.line(71, 49295.143758940096, 71, -48815.143758940096)
end
You can fix it in two ways: by drawing the lines using the pixel centres (i.e. just add 0.5 to every x and y coordinate in love.graphics.line), or by drawing 1-pixel rectangles instead of lines, which will probably be less computationally expensive.
Code: Select all
-- option 1:
love.graphics.line(x+.5, y1+.5, x+.5, y2+.5)
-- option 2:
love.graphics.rectangle("fill", x, y1, 1, y2-y1)
Last edited by pgimeno on Fri Feb 05, 2021 1:28 pm, edited 1 time in total.
Re: Problem with raycasting
Oh God, you are right! I thought it was an error in the raycasting algorithm and i was going crazy! Thank you, pgimeno!pgimeno wrote: ↑Fri Feb 05, 2021 1:17 pm It looks like a problem with Löve's line algorithm; not sure if it's a bug or just an expected loss of precision. Here is a test case, not sure if it can be reproduced everywhere:
These two lines should be rendered as one thick line, but the one at x=70 is rendered at x=69, causing a black line in between.Code: Select all
love.graphics.setLineStyle("rough") function love.draw() love.graphics.line(70, 49138.421592350249, 70, -48658.421592350249) love.graphics.line(71, 49295.143758940096, 71, -48815.143758940096) end
You can fix it in two ways: by drawing the lines using the pixel centres (i.e. just add 0.5 to every x and y coordinate in love.graphics.line), or by drawing 1-pixel rectangles instead of lines, which will probably be less computationally expensive.Code: Select all
-- option 1: love.graphics.line(x+.5, y1+.5, x+.5, y2+.5) -- or maybe y2-.5, otherwise it may be one pixel too high -- option 2: love.graphics.rectangle("fill", x, y1, 1, y2-y1)
Re: Problem with raycasting
Okay, i've successfully added textures for walls, but i'm having some troubles with the floor: the math is more or less done, but when i try to draw floor tiles (using meshes) i get this strange effect:
I've tried drawing a texture using meshes stripe by stripe and it's distorted too (but not as distorted as the floor):
Am i doing something wrong with the mesh?
I'll attach an updated .love file too.
I've tried drawing a texture using meshes stripe by stripe and it's distorted too (but not as distorted as the floor):
Am i doing something wrong with the mesh?
I'll attach an updated .love file too.
- Attachments
-
- textured_raycaster.love
- (13.61 KiB) Downloaded 200 times
Re: Problem with raycasting (floor tiles)
That looks a lot like lack of perspective correction applied to the mesh. Squeezing a quad without applying perspective distorts the triangles that form the quad like that.
Edit: Here's an example to demonstrate the distortion, using your floor.png texture:
(click and drag the vertices to see the issue)
I can think of two solutions: use the floor rendering technique used in ray casting for the floor too, instead of meshes, or ditch the ray casting completely and go full 3D. After all, Löve uses OpenGL, and for OpenGL it's probably cheaper to do perspective-correct 3D than to render one polygon per horizontal pixel column. Here's a quick demo I made (mainly intended to illustrate how to do 3D): https://love2d.org/forums/viewtopic.php ... 45#p219345
A third possibility would be to render the floor in full 3D and the walls with ray casting, but I'm not sure how that would work.
Edit: I forgot, there's a fourth possibility, which is to use this shader: https://love2d.org/forums/viewtopic.php?f=5&t=12483 which basically takes the four vertices of a quad as input, and applies perspective correction to them. However, it's pretty computationally expensive.
Edit: Here's an example to demonstrate the distortion, using your floor.png texture:
Code: Select all
love.graphics.setDefaultFilter("nearest", "nearest")
local tex = love.graphics.newImage("floor.png")
local mesh = love.graphics.newMesh(4, "strip", "stream")
mesh:setTexture(tex)
local grabbed = false
local vertices = {{100, 100, 0, 0}, {100, 400, 0, 1},
{400, 100, 1, 0}, {400, 400, 1, 1}}
function love.mousepressed(x, y, b)
if b == 1 then
local closestD, closestV
for v = 1, 4 do
local dx = vertices[v][1] - x
local dy = vertices[v][2] - y
local d2 = dx * dx + dy * dy
if closestD == nil or closestD > d2 then
closestD = d2
closestV = v
end
end
grabbed = closestV
vertices[grabbed][1] = x
vertices[grabbed][2] = y
end
end
function love.mousemoved(x, y)
if grabbed then
vertices[grabbed][1] = x
vertices[grabbed][2] = y
end
end
function love.mousereleased(x, y, b)
if grabbed then
vertices[grabbed][1] = x
vertices[grabbed][2] = y
end
if b == 1 then
grabbed = false
end
end
function love.update(dt)
for i = 1, 4 do
mesh:setVertex(i, vertices[i])
end
end
function love.draw()
love.graphics.draw(mesh)
end
I can think of two solutions: use the floor rendering technique used in ray casting for the floor too, instead of meshes, or ditch the ray casting completely and go full 3D. After all, Löve uses OpenGL, and for OpenGL it's probably cheaper to do perspective-correct 3D than to render one polygon per horizontal pixel column. Here's a quick demo I made (mainly intended to illustrate how to do 3D): https://love2d.org/forums/viewtopic.php ... 45#p219345
A third possibility would be to render the floor in full 3D and the walls with ray casting, but I'm not sure how that would work.
Edit: I forgot, there's a fourth possibility, which is to use this shader: https://love2d.org/forums/viewtopic.php?f=5&t=12483 which basically takes the four vertices of a quad as input, and applies perspective correction to them. However, it's pretty computationally expensive.
Re: Problem with raycasting (floor tiles)
Thank you, pgimeno! I'll probably give your 3D example a try soon! I was trying raycasting instead of real 3D just for fun (and to learn something maybe).pgimeno wrote: ↑Sun Feb 07, 2021 11:37 am That looks a lot like lack of perspective correction applied to the mesh. Squeezing a quad without applying perspective distorts the triangles that form the quad like that.
Edit: Here's an example to demonstrate the distortion, using your floor.png texture:(click and drag the vertices to see the issue)Code: Select all
love.graphics.setDefaultFilter("nearest", "nearest") local tex = love.graphics.newImage("floor.png") local mesh = love.graphics.newMesh(4, "strip", "stream") mesh:setTexture(tex) local grabbed = false local vertices = {{100, 100, 0, 0}, {100, 400, 0, 1}, {400, 100, 1, 0}, {400, 400, 1, 1}} function love.mousepressed(x, y, b) if b == 1 then local closestD, closestV for v = 1, 4 do local dx = vertices[v][1] - x local dy = vertices[v][2] - y local d2 = dx * dx + dy * dy if closestD == nil or closestD > d2 then closestD = d2 closestV = v end end grabbed = closestV vertices[grabbed][1] = x vertices[grabbed][2] = y end end function love.mousemoved(x, y) if grabbed then vertices[grabbed][1] = x vertices[grabbed][2] = y end end function love.mousereleased(x, y, b) if grabbed then vertices[grabbed][1] = x vertices[grabbed][2] = y end if b == 1 then grabbed = false end end function love.update(dt) for i = 1, 4 do mesh:setVertex(i, vertices[i]) end end function love.draw() love.graphics.draw(mesh) end
I can think of two solutions: use the floor rendering technique used in ray casting for the floor too, instead of meshes, or ditch the ray casting completely and go full 3D. After all, Löve uses OpenGL, and for OpenGL it's probably cheaper to do perspective-correct 3D than to render one polygon per horizontal pixel column. Here's a quick demo I made (mainly intended to illustrate how to do 3D): https://love2d.org/forums/viewtopic.php ... 45#p219345
A third possibility would be to render the floor in full 3D and the walls with ray casting, but I'm not sure how that would work.
Edit: I forgot, there's a fourth possibility, which is to use this shader: https://love2d.org/forums/viewtopic.php?f=5&t=12483 which basically takes the four vertices of a quad as input, and applies perspective correction to them. However, it's pretty computationally expensive.
By the way i've managed to draw floors using only scale, rotate, ox, oy and scissors but it's still buggy as you can see from the screenshot (still have to figure out why):
Basically, for each floor stripe i'm finding the points P1 and P2 where P1 is the first point of the tile encountered by the ray and P2 is the last one. I'll then calculate the angle between the two points (needed to rotate the texture) and the scale factor (thanks to the two perpendicular distances from the points to the projection plane) and then, using scissors, i'm drawing only the vertical stripe i need to view.
I'm leaving also the updated .love file in the attachments in case anybody wants to see how i've tried to implement such things.
- Attachments
-
- scaling_scissor_raycaster.love
- (14.04 KiB) Downloaded 200 times
Who is online
Users browsing this forum: Bing [Bot] and 58 guests