Ah, the power of fresh eyes.
I was stumped as to why my physics ray query wasn’t colliding with the concave prism. I reviewed my diff and that led to me looking up the docs for PhysicsRayQueryParameters2D and there it was, collide_with_area property, default value: false. That was all it took, all within 30 seconds of sitting down.
Getting closer. This is pretty but it’s very very wrong.
Okay, that’s solved. I threw away any intersections with the circle which were on the other side of the line between the prism corners.
Next problem. I’m getting flickering between the next two images.
Or here’s another one.
The scale is getting inverted? It shouldn’t… I’m not setting that anywhere, I’m just setting the rotation.
Why does that sound familiar?
Oh my bad, it’s not inverted, just rotated 180°.
Hmm.
Okay, I know why. I’ve got a block like this:
# Adjust the circle's normal polarity to match the original rectangle normal.
var collision_normal: Vector2 = (circle_center - collision_point).normalized()
if collision.normal.dot(collision_normal) < 0:
collision_normal = - collision_normal
This made sense when I was still using a big ol’ rectangle to check for collisions but now it’s—wait, no, that’s weird. It should still work even though I’m using a polygon to more closely model the curve of the prism.
Don’t actually need to do that adjustment at all and then the problem is fixed.
It’s getting harder to find problematic situations but here’s one:
I added some more debug output so I can track which branch of the ray processing is being traversed at each inflection point.
The case above is the expected behaviour. An external ray hits the prism at point 0 and refracts, producing an internal ray. That internal ray hits the curved surface at a shallow angle at 1 so it gets processed as an internal reflection. Same goes for the collision at 2. When the ray gets to the flat edge at 3 it’s refracted and produces an external ray.
Now.
This is only a slightly different angle but the results are not good. The internal reflection at 1 is going the wrong way. It looks like it’s actually going 180° from where it should. Same at 2.
I think it’s because I’m just getting the nearest intersection with a circle but I need to get the nearest intersection with a circle in the forward direction. Discard any intersections that are behind the laser. Man that’s crazy.
That was tricky but yeah, that was it. A quick change to the function that finds the intersections and we good.
Here’s one that’s been around for ages. Ever since I first introduced prisms.
Since it’s right at the tip, the reverse cast fails to find an exit point. I think I should just continue the ray, calling it an external ray, as opposed to the current behaviour of terminating the ray.
Here we go. Much better.
One more challenge.
I noticed a comment in my code: “Prevent child laser from colliding with the body where it originates.”
All my prisms were convex until now. For my new concave prism this restriction is going to be a problem.
It was tricky to arrange a situation that exposed this error but here it is:
I remember I needed to introduce this because when a ray exited the prism it would often just collide again with the same prism at basically the same point. It must have come from a tiny error but the effect was huge. So if I remove the collision exception I need some other mechanism to prevent the “re-collision” issue.
If I do just remove the exception the test case works fine.
But now I have other problems like this:
I can’t get Godot to ignore collisions within a certain area but I could move the ray a little forward.
Been dragging the prism around for a while looking for problems and I’m not finding any. Moving the ray a little forward (3 pixels) has created a visual gap but I can accommodate for that separately from the raycast.
Here’s an interesting situation. On the third bounce, the ray exits at a very shallow angle just skimming the surface of the curve and re-enters. If that entry angle changes even just a little it would instead refract and exit or reflect internally.
Here’s a problem, though:
At first it doesn’t look like it’s doing anything wrong but actually at 1 it should refract into the prism like the example below.
It’s not working because it think it’s an internal ray. Internal reflection is a thing but not external reflection.
It only happens right at that corner. If the ray has a chance to travel inside the prism and make contact with the curved surface then things work correctly:
So how can I detect that the ray has entered and exited the prism at the same point?
I guess rays could double check that they’re actually internal rays. Maybe see if the mid point is actually inside the prism. If not, declare itself an external ray re-entering.