Protofall / Crayon-Game-Framework

My own library for making games on the Dreamcast
BSD 3-Clause "New" or "Revised" License
5 stars 0 forks source link

Crayon: Enhance OOB to handle any degree rotation #192

Closed Protofall closed 3 years ago

Protofall commented 4 years ago

I can easily detect any-degree rotated poly by getting the highest/lowest x/y and constructing a new list from that.

for(i = 0 ... 3){
   if(vert[i].x < min_x){min_x = vert[i].x;}
   //etc
}
Protofall commented 4 years ago

The reason this works is because the min/max can form a bigger box that will return the same result for OOB. Take this image as an example

The original sprite is the red box and the black outline is the new min/max box. If one of these boxes is OOB, then we know the other is as well. Since the OOB checker already handles AABB sprites, we can just pass it the black box and it will work.

Protofall commented 4 years ago

This isn't strict enough. I was wrong and there are cases where the red box doesn't clip and the black box does. Instead I will need to use a different method for OOB. Google what to do here

Protofall commented 4 years ago

Here's a few examples of possible situations where the black box is the camera window and the red box is the sprite

Something I'm noticing is that you can detect if OOB with the following pseudo code

a = (any sprite vert is within the camera view) ? 1 : 0
b = (the line between any 2 sprite verts intersect a camera edge) ? 1 : 0
if(a || b){return inbounds;}
return OOB;

This satisfies all of the above 9 cases, however this 10th case wouldn't be classified correctly

I think condition b needs to be stricter to catch case 10

Protofall commented 4 years ago

These can also be useful (Probably 1st and 3rd):

http://www.jeffreythompson.org/collision-detection/poly-rect.php http://www.jeffreythompson.org/collision-detection/object_oriented_collision.php http://www.jeffreythompson.org/collision-detection/matrix-transformations.php https://www.sevenson.com.au/actionscript/sat/

Protofall commented 4 years ago

https://gamedev.stackexchange.com/questions/25397/obb-vs-obb-collision-detection

Two shapes only intersect if they have overlap when "projected" onto every normal axis of both shapes.

Its hard to imagine, but here's basically how it works. For the 2 main sides (Since these are rects) we generate the normal (Which is just the next side) and treat it like an axis. and then "crush" all the verts onto the axis so we have a bunch of points on the line. If there is an overlap then that means all of the normal-axis tests had verts from both polys mixed together/overlapping. Below is what happens when we perform this test on the left (Or right) side of the rectangle on the left

If a "No overlap" occurs we end early and return OOB. A user from SO has suggested possible optimisations I can make since one of my rectangles is axis aligned. https://stackoverflow.com/questions/58787120/how-to-determine-if-two-rectangles-overlap-at-angle/58823947#58823947

Protofall commented 4 years ago

When doing a SAT test with one of the camera's sides, since its axis is aligned we just check to make sure all the verts of the other poly aren't just < the Left/Top vert or > the Right/Bottom vert. Else it means they're intersecting.

Might need an internal function when given a list of verts it finds the min and max X or Y to make that simpler.

Protofall commented 4 years ago

For the sprite's SAT tests, I'll generate the normal from one of the other sides (That are already perpendicular). Then project all the min/max verts (Should be 4 in total) onto that line and check for overlap. Not sure how I'll project it yet.

Protofall commented 4 years ago
Boolean overlap(float[] x, float[] y, float[] camera_x, float[] camera_y){
  //Checking Camera's normals
  float[] range_x = get_range(x);  //Returns min and max
  if(range_x[1] < camera_x[0] || range_x[0] > camera_x[1]){
    return false;
  }
  float[] range_y = get_range(y);
  if(range_y[1] < camera_y[0] || range_y[0] > camera_y[2]){
    return false;
  }

  //checking sprite's normals
  ;

  return true;
}

Almost there, doesn't detect all cases of OOB yet

Protofall commented 4 years ago

This proved to be very useful. Turns out the if statement for checking the 2 mins and maxes was incorrect. This code is pretty good. https://gist.github.com/nyorain/dc5af42c6e83f7ac6d831a2cfd5fbece

I have already created a working prototype in Processing, next up porting it to Crayon

Protofall commented 3 years ago

This isn't strict enough. I was wrong and there are cases where the red box doesn't clip and the black box does. Instead I will need to use a different method for OOB. Google what to do here

While its true that this method would falsely detect some red boxes that are fully OOB as partially in-bounds (Nov 7th post, 3rd row 2nd column), it does however check if its OOB || needs cropping. That might be useful.

Protofall commented 3 years ago

I've re-read my code and re-understood it and the logic is sound. I also cleaned up the code to hopefully be more optimised. The only divisions/sqrts that happen are in the unit test, but they don't always happen (Only if the Camera normal SATs fail). I'll close this issue once the code is integrated into one of the crayon renderers (Most likely the untexted one #176)

Protofall commented 3 years ago

It turns out theres a bug in the code. Sometimes it says its OOB when its clearly in bounds. I should do stuff like render the normals and other things to figure out why.

The SAT function is incorrectly returning false when it should return true. It seems the first 2 checks in the aabb_obb function (Camera "normals") are fine.

Protofall commented 3 years ago

Turns out there was still a bug. There were "else if's" in the min/max code that should have been ifs, otherwise sometimes we didn't get the true max value.