Casting light with newMesh
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
Re: Casting light with newMesh
I'm just curious, but why are you going with a CPU side system for this? Using OpenGL for lighting would be far more efficient and far simpler to implement, so why not go that route?
- Ranguna259
- Party member
- Posts: 911
- Joined: Tue Jun 18, 2013 10:58 pm
- Location: I'm right next to you
Re: Casting light with newMesh
I'm starting to realize that programming lightning is like programming physics, it's never perfect and sooner or later everyone runs into the same problem.Gravy wrote:Monocle was very difficult for me, and I'm sort of surprised I even got it working. The process laid out in that blog post is fairly straightforward, but I ran into edge case after edge case.
The problem you're having with the 'sweeping' was the hardest part and took most of the work. I had to keep track of the 'previous' and 'next' edge for each edge, which gets complicated fast when you are casting the rays and splitting the edges into new ones, or when your projection hits a corner.
If you want to implement something like this, I really suggest trying to use Monocle. It took me dozens of hours to get working. Germanunkol's version cleans up the callbacks very nicely and makes it easy to use.
If you want, I could help you understand the code. But there's really no way to unravel the add_projection_edge function. All the complexity in there is due to special cases.
EDIT: I just read the Red Blob article. This method does seem a bit simpler, but I haven't looked very hard at the code.
I'm not very good at interperting other people's code and since you're telling me that the function that does what I want right know from monocle has special cases then it'd make interpertation even harder so instead of looking throught your code might I ask you how you did it ? Specialy how you kept track of all previouse and next edges.
And could you link me to a Monocle version that you think that is most stable ?
Indeed, most post and articles that I've read always miss something, some are the sources of used statments and others miss detailed explanations, Amit does a really good job with his articles but he could go a little more technical on this one, other than that the post was great, he explained several methods and he showed quite a few demos demonstrating his explanations.kikito wrote:Amit (the author of the redblob article) is a terrific article writer and library implementor. His articles are usually top quality.
Don't mis his post about the blog post, in which he lists similar techniques that he's found.
I've looked into those but I haven't yet found a good explanation for the sweeping part. Found some GLSL codes thought, those might be useful.
You mean using GLSL for lightning ? The problem is that I don't know much about GLSL, I really haven't tried it yet but coding light might be a good start, do you know of any good tutorials for shaders based lightning ?styves wrote:I'm just curious, but why are you going with a CPU side system for this? Using OpenGL for lighting would be far more efficient and far simpler to implement, so why not go that route?
Re: Casting light with newMesh
I'll write more about the method I used when I have a bit more time, but the latest version is here: https://github.com/kennethdamica/Monocle
Again, Germanunkol's version has a much better interface, but I had a few issues with some of the changes he made (or I might just have not understood them), so I never merged in his fork. https://github.com/Germanunkol/Monocle
EDIT: Okay, here goes:
1) Get the forward-facing edges and put them in a table. I didn't use a border edge and assumed that the world is enclosed because I got lazy. (Monocle:get_forward_edges)
2) Set the 'next' and 'previous' attributes of each edge based on the grid or some other way, if your edges are not grid based. (Monocle:link_edges)
3) Now, loop through your edges, and wherever an edge is missing a 'next' or 'previous', cast a ray. Store the info about the projected edges in a separate table 'edges_to_add'.
4) Sort 'edges_to_add' by their distance to the light (shortest distance). (3 & 4: Monocle:add_projections)
(Now the hard part)
5) In that order, add the projected edges to the table of edges. Whichever edge the far end of the projection hits, drop that edge from the table and insert two new edges, split by where the projection hit.
6) Depending on whether is was a 'back' edge or a 'front' edge (meaning, when you move clockwise, whether the edge is the first or second to be hit), set the previous and next attributes of the projected edge, the edge it was projected from, and the new edges that were created by the split. (5 & 6: add_projection_edge)
NOTES:
-Do not lose any information about the previous and next edges that were already attached. That backward edge that gets hit may seem useless right now, but another projection could hit it later, so it needs to be there.
-The special case here is when the projection hits an endpoint precisely. In this case, you do not need to split the edge. The 'precisely' part of this gave me some issues.
(Now it's easy again)
7) Now, starting from the closest edge to the player (which is guaranteed to be a forward edge) follow the 'next' attributes all the way around until you get back to your starting place. Each edge forms a triangle with the third point being the light source. I leave it to you to decide how you want to use these points. I just drew a bunch of white triangles onto a black canvas and multiplicatively drew it on my other canvas. Germanunkol does it differently (this method is where I disagreed with him. One is not necessarily better, it's just a matter of how you intend to use it). (Monocle:draw_triangles)
And that's basically it. This probably shouldn't have taken me as long as it did, but I made a few very subtle yet fatal errors in my initial design that took me a long time to figure out. Also, I never fully figured out the special case where the projection hits the corner. Sometimes it still messes up, so as a band-aid I just added a tiny random number to the light's position. The addition is not enough to be visible. This way, I could add a check in my game for when Monocle fails to return a complete polygon, and run it again in the next frame rather than wait for the light to move.
Hopefully this helps. Happy to answer more questions.
Again, Germanunkol's version has a much better interface, but I had a few issues with some of the changes he made (or I might just have not understood them), so I never merged in his fork. https://github.com/Germanunkol/Monocle
EDIT: Okay, here goes:
1) Get the forward-facing edges and put them in a table. I didn't use a border edge and assumed that the world is enclosed because I got lazy. (Monocle:get_forward_edges)
2) Set the 'next' and 'previous' attributes of each edge based on the grid or some other way, if your edges are not grid based. (Monocle:link_edges)
3) Now, loop through your edges, and wherever an edge is missing a 'next' or 'previous', cast a ray. Store the info about the projected edges in a separate table 'edges_to_add'.
4) Sort 'edges_to_add' by their distance to the light (shortest distance). (3 & 4: Monocle:add_projections)
(Now the hard part)
5) In that order, add the projected edges to the table of edges. Whichever edge the far end of the projection hits, drop that edge from the table and insert two new edges, split by where the projection hit.
6) Depending on whether is was a 'back' edge or a 'front' edge (meaning, when you move clockwise, whether the edge is the first or second to be hit), set the previous and next attributes of the projected edge, the edge it was projected from, and the new edges that were created by the split. (5 & 6: add_projection_edge)
NOTES:
-Do not lose any information about the previous and next edges that were already attached. That backward edge that gets hit may seem useless right now, but another projection could hit it later, so it needs to be there.
-The special case here is when the projection hits an endpoint precisely. In this case, you do not need to split the edge. The 'precisely' part of this gave me some issues.
(Now it's easy again)
7) Now, starting from the closest edge to the player (which is guaranteed to be a forward edge) follow the 'next' attributes all the way around until you get back to your starting place. Each edge forms a triangle with the third point being the light source. I leave it to you to decide how you want to use these points. I just drew a bunch of white triangles onto a black canvas and multiplicatively drew it on my other canvas. Germanunkol does it differently (this method is where I disagreed with him. One is not necessarily better, it's just a matter of how you intend to use it). (Monocle:draw_triangles)
And that's basically it. This probably shouldn't have taken me as long as it did, but I made a few very subtle yet fatal errors in my initial design that took me a long time to figure out. Also, I never fully figured out the special case where the projection hits the corner. Sometimes it still messes up, so as a band-aid I just added a tiny random number to the light's position. The addition is not enough to be visible. This way, I could add a check in my game for when Monocle fails to return a complete polygon, and run it again in the next frame rather than wait for the light to move.
Hopefully this helps. Happy to answer more questions.
Last edited by Gravy on Sat Jan 18, 2014 1:34 am, edited 1 time in total.
- Ranguna259
- Party member
- Posts: 911
- Joined: Tue Jun 18, 2013 10:58 pm
- Location: I'm right next to you
Re: Casting light with newMesh
Once you post about your method please PM me and thanks for the links, weekend work: look into Monocle's add_projection_edge function
Who is online
Users browsing this forum: Bing [Bot] and 13 guests