Make an empty list of pointsAdd all polygon points that have an unobstructed line to the eye (or light source)Add all polygon intersection points that have an unobstructed line to the eyeAdd all points on the sight polygon (or field of view) that have an unobstructed line to the eyeSort the list by the angle of each point relative to the eye, from the x-axisSearch through the points and find any polygon points that are 'end points' which would cast a shadow.Cast a ray from these points away from the eye, and find the intersection of this ray with the nearest polygon or the nearest edge of the sight polygon.Add the intersection to the list, before or after the 'end point' depending on which side the end point is on.

It took a lot of trial and error to arrive at this method. I tried lots of other ways but they weren't stable. This one works fine so long as the eye is never collinear with any edges of the polygons, which i enforce by making the player unable to penetrate a slightly larger polygon, which i create using JTS. You pointed me to that so cheers

Cool, but then you'd lose the soft shadows. I was thinking about how to get soft shadows using this method - maybe you could do it by looking for the shadow-casting points and making a thin triangle polygon from the shadow-casting point, then you could fill that triangle with a smooth gradient.

Ah, that makes sense. I've thought about the "sort by angle and then walk around" approach before, but whenever I've gone over it in my head I've never managed to come up with a robust algorithm. I might have to have a crack at implementing it.

I'm also wondering whether it'd be possible to add soft shadows to it, it feels like it should be possible but again there's probably a whole bunch of extra edge cases it adds.

For soft shadows you could move the eye a little and recompute the LOS.

That's not very soft. Or fast.

For non-sucky soft shadows you have to calculate the penumbra wedge at the edge of each shadow. For the inner half this is easy (since you're just drawing part of the existing light geometry with a gradient), the outer half is more problematic as you need to expand the existing light geometry while taking into account any extra occulders that are behind the shadow casting one.

Make an empty list of pointsAdd all polygon points that have an unobstructed line to the eye (or light source)Add all polygon intersection points that have an unobstructed line to the eyeAdd all points on the sight polygon (or field of view) that have an unobstructed line to the eyeSort the list by the angle of each point relative to the eye, from the x-axisSearch through the points and find any polygon points that are 'end points' which would cast a shadow.Cast a ray from these points away from the eye, and find the intersection of this ray with the nearest polygon or the nearest edge of the sight polygon.Add the intersection to the list, before or after the 'end point' depending on which side the end point is on.

So I'm having a crack at doing this but can't seem to make it handle all the edge cases - could you elaborate on exactly how you're determining if a point is a casting edge or not?

I've been testing to see if the vertex is sharing an edge with faces pointing away and towards thel light but this has issues when you've got faces exactly parallel with the light (and other quirks).

Lol, I know, the corner cases are a pain. The way i solved the parallel problem was to do a line-line intersection test of each shadow-casting point to see if it can be used. The floating point imprecision of that calculation actually helped since it cut out lines that were exactly parallel

When casting the shadow ray from the point, I cast it against all lines of all polygons, except for the 2 lines of the polygon from the point at which the ray emanates from.

You'll have to look at the code, it's too hard to explain in english. Here's the main bit:

Nice! Like in Nate's pictures, I can make it go haywire if I put the mouse cursor on the left edge of any square. The same thing happens in my implementation, that's why I don't allow the player to go on any edges.

It seems pretty stable and quick. Have you tried optimising it and doing an FPS test?

I knew there'd be an edge case or two that I'd missed, cheers. Probably just a precision problem, I'll try hacking in CommanderKeith's fix for that and upload a new version.

Algorithmically it's pretty terrible (there's *tons* of line vs. line collision checks going on) but it runs a lot faster than I though - here at least the bottleneck is the Java2D drawing rather than the casting. Plus I new a lot of objects and duplicate a lot of calculations, so there's lots that could be done faster.

I think next I need to put it into a game-like environment to see how it holds up - I'm worried that in a tile map level a lot of the 'funny' edge cases will occur a lot more frequently and might make it unusable.

I've reposted a faster version which - minimises calls to Math.sqrt (by using distanceSq rather than distance) and Math.atan2. I tried Riven's FastMath class too but it turns out that the innacuracies cause errors in the algorithm.- classifies occluding polygons into a quadrant based on its position relative to the eye (or light source) which allows the algorithm to avoid line-line intersections

It makes me want to have a go at soft shadows, but I'm hesitant to begin because I know it'll take so long to get right.

I also tried to make a version out of LWJGL since I was getting frustrated with java2D's slow performance when it comes to translucent fills. But I don't know how to fill concave polygons. I looked at how Kev Glass's Slick API does it, and it seems to triangulate/tesselate the polygon in software before rendering. But then some seem to use GLUT to triangulate automatically. Can anyone help?

I've reposted a faster version which - minimises calls to Math.sqrt (by using distanceSq rather than distance) and Math.atan2. I tried Riven's FastMath class too but it turns out that the innacuracies cause errors in the algorithm.- classifies occluding polygons into a quadrant based on its position relative to the eye (or light source) which allows the algorithm to avoid line-line intersections

It makes me want to have a go at soft shadows, but I'm hesitant to begin because I know it'll take so long to get right.

I also tried to make a version out of LWJGL since I was getting frustrated with java2D's slow performance when it comes to translucent fills. But I don't know how to fill concave polygons. I looked at how Kev Glass's Slick API does it, and it seems to triangulate/tesselate the polygon in software before rendering. But then some seem to use GLUT to triangulate automatically. Can anyone help?

Thanks Keith

Yeah, you're going to want to divide the polygon into an array of triangles, and then you can use glDrawArrays(GL_TRIANGLES, myVertices, myTriangleCount) in order to draw the polygon with one draw call. Basically you can do this using a pretty simple algorithm where you find vertices that have obtuse angles and then draw triangles to every other vertex from that one. Have a look at this:

Thanks a lot Eli, that's a big help. So I take it that's the fastest way to get OGL to fill a concave polygon in a solid colour, but what about to do a tricky gradient fill, doesn't that require you to specify boundary edges? I've got no idea how to do that.

Thanks a lot Eli, that's a big help. So I take it that's the fastest way to get OGL to fill a concave polygon in a solid colour, but what about to do a tricky gradient fill, doesn't that require you to specify boundary edges? I've got no idea how to do that.

Hm, that's a good question. I wouldn't be surprised if you can do it in hardware - I've mostly messed with OpenGL ES (stripped for mobile devices) so I don't know about a lot of the upper level capabilities it has. In my experience glDrawArrays is fast (and usually faster than glBegin and glEnd) and probably the fastest option if you're not using textures or normals (in which case you should probably use glDrawElements). But like I said I'm no expert on OpenGL's full capabilities - so I could very well be wrong.

GLU utilities and in particular triangulation of polys is usually not done in hardware. For the simple reason the hardware only knows about triangles (and perhaps quads). As for NURBS and other "evaluators", i have no idea, nobody seems to talk about them anymore.

There is however geometry shaders for newer hardware. But triangulation sounds like a bit of overkill for something that only needs to be done once.

I have no special talents. I am only passionately curious.--Albert Einstein

java-gaming.org is not responsible for the content posted by its members, including references to external websites,
and other references that may or may not have a relation with our primarily
gaming and game production oriented community.
inquiries and complaints can be sent via email to the info‑account of the
company managing the website of java‑gaming.org