Most efficient way to determine if a cube intersects a frustum - c++

I'm looking for a fast, efficient (even if sometimes false positive) way to determine if a cube intersects a frustum.
I've been using a brute force test of just seeing if all cube points are behind one of the planes, and rejecting on that basis, using this function:
inline char ClassifyPoint(Vector thePoint, char thePlane)
{
Vector aDir=mPlane[thePlane].mPos-thePoint;
float aD=aDir.Dot(mPlane[thePlane].mNormal);
if (aD<-0.0005f) return 1; // In front of plane
if (aD>0.0005f) return -1; // Behind plane
return 0; // "On" the plane
}
It also seems to work if I just use the center of each cube face, which saves me two tests.
But I wanted to know if there's a faster way, something more volume oriented.

Related

3D Collision resolution, moving AABB + polyhedron

I have been writing a game engine in my free time, but I've been stuck for a couple weeks trying to get collisions working.
Currently I am representing entities' colliders with AABBs, and the collider for a level is represented by a fairly simple (but not necessarily convex) polyhedron. All the drawing is sprite-based but the underlying collision code is 3D.
I've got AABB/triangle collision detection working using this algorithm, (which I can naively apply to every face in the level mesh), but I am stuck trying to resolve the collision after I have detected its existence.
The algorithm I came up with works pretty well, but there are some edge cases where it breaks. For example, walking straight into a sharp corner will always push the player to one side or the other. Or if a small colliding face happens to have a normal that is closer to the players direction of movement than all other faces, it will "pop" the player in that direction first, even though using the offset from a different face would have had a better result.
For reference, my current algorithm looks like:
Create list of all colliding faces
Sort list in increasing order of the angle between face normal and negative direction of entity movement (i.e. process faces with the most "stopping power" first)
For each colliding face in collision list:
scale = distance of collision along face normal
Entity position += face normal * scale
If no more collision:
break
And here's the implementation:
void Mesh::handleCollisions(Player& player) const
{
using Face = Face<int32_t>;
BoundingBox<float> playerBounds = player.getGlobalBounds();
Vector3f negPlayerDelta = -player.getDeltaPos(); // Negative because face norm should be opposite direction of player dir
auto comparator = [&negPlayerDelta](const Face& face1, const Face& face2) {
const Vector3f norm1 = face1.normal();
const Vector3f norm2 = face2.normal();
float closeness1 = negPlayerDelta.dot(norm1) / (negPlayerDelta.magnitude() * norm1.magnitude());
float closeness2 = negPlayerDelta.dot(norm2) / (negPlayerDelta.magnitude() * norm2.magnitude());
return closeness1 > closeness2;
};
std::vector<Face> collidingFaces;
for (const Face& face : _faces)
{
::Face<float> floatFace(face);
if (CollisionHelper::collisionBetween(playerBounds, floatFace))
{
collidingFaces.push_back(face);
}
}
if (collidingFaces.empty()) {
return;
}
// Process in order of "closeness" between player delta and face normal
std::sort(collidingFaces.begin(), collidingFaces.end(), comparator);
Vector3f totalOffset;
for (const Face& face : collidingFaces)
{
const Vector3f& norm = face.normal().normalized();
Point3<float> closestVert(playerBounds.xMin, playerBounds.yMin, playerBounds.zMin); // Point on AABB that is most negative in direction of norm
if (norm.x < 0)
{
closestVert.x = playerBounds.xMax;
}
if (norm.y < 0)
{
closestVert.y = playerBounds.yMax;
}
if (norm.z < 0)
{
closestVert.z = playerBounds.zMax;
}
float collisionDist = closestVert.vectorTo(face[0]).dot(norm); // Distance from closest vert to face
Vector3f offset = norm * collisionDist;
BoundingBox<float> newBounds(playerBounds + offset);
totalOffset += offset;
if (std::none_of(collidingFaces.begin(), collidingFaces.end(),
[&newBounds](const Face& face) {
::Face<float> floatFace(face);
return CollisionHelper::collisionBetween(newBounds, floatFace);
}))
{
// No more collision; we are done
break;
}
}
player.move(totalOffset);
Vector3f playerDelta = player.getDeltaPos();
player.setVelocity(player.getDeltaPos());
}
I have been messing with sorting the colliding faces by "collision distance in the direction of player movement", but I haven't yet figured out an efficient way to find that distance value for all faces.
Does anybody know of an algorithm that would work better for what I am trying to accomplish?
I'm quite suspicious with the first part of code. You modify the entity's position in each iteration, am I right? That might be able to explain the weird edge cases.
In a 2D example, if a square walks towards a sharp corner and collides with both walls, its position will be modified by one wall first, which makes it penetrate more into the second wall. And then the second wall changes its position using a larger scale value, so that it seems the square is pushed only by one wall.
If a collision happens where the surface S's normal is close to the player's movement, it will be handled later than all other collisions. Note that when dealing with other collisions, the player's position is modified, and likely to penetrate more into surface S. So at last the program deal with collision with surface S, which pops the player a lot.
I think there's a simple fix. Just compute the penetrations at once, and use a temporal variable to sum up all the displacement and then change the position with the total displacement.

OpenGL Raycasting with any object

I'm just wondering if there was any way which one can perform mouse picking detection onto any object. Whether it would be generated object or imported object.
[Idea] -
The idea I have in mind is that, there would be iterations with every object in the scene. Checking if the mouse ray has intersected with an object. For checking the intersection, it would check the mouse picking ray with the triangles that make up the object.
[Pros] -
I believe the benefit of this approach is that, every object can be detected with mouse picking since they all inherit from the detection method.
[Cons] -
I believe this drawbacks are mainly the speed and the method being very expensive. So would need fine tuning of optimization.
[Situation] -
In the past I have read about mouse picking and I too have implemented some basic form of mouse picking. But all those were crappy work which I am not proud of. So again today, I have re-read some of the stuff from online. Nowadays I see alot of mouse picking using color ids and shaders. I'm not too keen for this method. I'm more into a mathematical side.
So here is my mouse picking ray thingamajig.
maths::Vector3 Camera::Raycast(s32 mouse_x, s32 mouse_y)
{
// Normalized Device Coordinates
maths::Vector2 window_size = Application::GetApplication().GetWindowSize();
float x = (2.0f * mouse_x) / window_size.x - 1.0f;
float y = 1.0f;
float z = 1.0f;
maths::Vector3 normalized_device_coordinates_ray = maths::Vector3(x, y, z);
// Homogeneous Clip Coordinates
maths::Vector4 homogeneous_clip_coordinates_ray = maths::Vector4(normalized_device_coordinates_ray.x, normalized_device_coordinates_ray.y, -1.0f, 1.0f);
// 4D Eye (Camera) Coordinates
maths::Vector4 camera_ray = maths::Matrix4x4::Invert(projection_matrix_) * homogeneous_clip_coordinates_ray;
camera_ray = maths::Vector4(camera_ray.x, camera_ray.y, -1.0f, 0.0f);
// 4D World Coordinates
maths::Vector3 world_coordinates_ray = maths::Matrix4x4::Invert(view_matrix_) * camera_ray;
world_coordinates_ray = world_coordinates_ray.Normalize();
return world_coordinates_ray;
}
I have this ray plane intersection function which calculates if a certain ray as intersected with a certain plane. DUH!
Here is the code for that.
bool Camera::RayPlaneIntersection(const maths::Vector3& ray_origin, const maths::Vector3& ray_direction, const maths::Vector3& plane_origin, const maths::Vector3& plane_normal, float& distance)
{
float denominator = plane_normal.Dot(ray_direction);
if (denominator >= 1e-6) // 1e-6 = 0.000001
{
maths::Vector3 vector_subtraction = plane_origin - ray_origin;
distance = vector_subtraction.Dot(plane_normal);
return (distance >= 0);
}
return false;
}
There are many more out there. E.g. Plane Sphere Intersection, Plane Disk Intersection. These things are like very specific. So it feel that is very hard to do mouse picking intersections on a global scale. I feel this way because, for this very RayPlaneIntersection function. What I expect to do with it is, retrieve the objects in the scene and retrieve all the normals for that object (which is a pain in the ass). So now to re-emphasize my question.
Is there already a method out there which I don't know, that does mouse picking in one way for all objects? Or am I just being stupid and not knowing what to do when I have everything?
Thank you. Thank you.
Yes, it is possible to do mouse-picking with OpenGL: you render all the geometry into a special buffer that stores a unique id of the object instead of its shaded color, then you just look at what value you got at the pixel below the mouse and know the object by its id that is written there. However, although it might be simpler, it is not a particularly efficient solution if your camera or geometry constantly moves.
Instead, doing an analytical ray-object intersection is the way to go. However, you don't need to check the intersection of every triangle of every object against the ray. That would be inefficient indeed. You should cull entire objects by their bounding boxes, or even portions of the whole scene. Game engines have their own spacial index data structure to speed-up ray-object intersections. They need it not only for mouse picking, but also for collision-detection, physics simulations, AI, and what-not.
Also note that the geometry used for the picking might be different from the one used for rendering. One example that comes to mind is that of semi-transparent objects.

Wormhole effect: warp space with opengl [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I am looking for a way to do a wormhole effect like this:
- https://www.youtube.com/watch?v=WeOBXmLeJWo&feature=youtu.be&t=43s
I have already found nice tunnels in the examples, but here it is a little bit more involved. Actually the space appears to be warped somehow and the movement is high velocity, so it is not just entering into a simple tunnel. Any idea how to do the space warping part of it?
I decided to add more info because this was too broad:
I have a galaxy and each star has a 3d coord, size, etc. in this galaxy. I can visit these stars with a space ship. There are very distant stars and it would take a lot of time to get to them, that's why I need warp (faster than light) speed. This does not necessarily requires a wormhole according to physics, but this app does not have to be overly realistic. I don't want to solve this with pure OpenGL so ofc. we can use shaders. I'd like to warp the space in the middle of the screen when accelerating to warp speeds. After that a tunnel effect can come, because I think it would consume a lot of resources to update every star by very high speeds, so I'd like to update only the close stars. This can't be a prerendered animation, because the destination is not always certain, so this has sometimes exploration purposes and sometimes traveling purposes. I don't think warping only the sky box is enough, but I am not sure about this.
There are 2 things going on there:
space curvature around the hole
You need to construct equation that describe the curvature of space around hole parametrized by hole parameters (mass,position,orientation) and time so you can animate it. Then from this curvature you can compute relative displacement of pixel/voxel around it. I would start with cylindrical cones with radius modulated by sin of the distance from hole +/- some animation parameters (need experimentation).
Something like this:
and for example start with (in wormhole local coordinates LCS):
r = R * sin(z*0.5*M_PI/wormhole_max_depth)
Then modulate it by additional therms. The wormhole_max_depth,R should be functions of time even linear or with some periodic therm so it is pulsating a bit.
The displacement can be done by simply computing distance of concerned point to cone surface and push it towards it the more the closer to the cone it is (inside cone voxels are considered below surface so apply max displacement strength)
particle/light/matter bursting out of the hole
I would go for this only when #1 is alredy done. It should be simple particle effect with some nice circular blended alpha texture animated on the surface of the cone from #1. I see it as few for loops with pseudo random displacement in position and speed ...
Techniques
This topic depends on how you want to do this. I see these possibilities:
Distort geometry during rendering (3D vector)
So you can apply the cone displacement directly on rendered stuff. This would be best applicable in GLSL but the geometry rendered must have small enough primitives to make this work on vertex level ...
Distort skybox/stars only (3D vector or 2D raster but objects stay unaffected)
So you apply the displacement on texture coordinates of skybox or directly on the star positions.
Distort whole rendered scene in second pass (2D raster)
This need to use 2 pass rendering and in the second pass just wrap the texture coordinates near hole.
As you got different local stars in each sector I would use star background generated from star catalogue (list of all your stars) And apply the distortion on them directly in 3D vector space (so no skybox.. option #2). And also because my engines already use such representation and rendering for the same reasons.
[Edit1] cone geometry
I haven't much time for this recently until today so I did not make much of a progress. I decided to start with cone geometry so here it is:
class wormhole
{
public:
reper rep; // coordinate system transform matrix
double R0,R1,H,t; // radiuses,depth
wormhole(){ R0=10.0; R1=100.0; H=50.0; t=0.0; };
wormhole(wormhole& a){ *this=a; };
~wormhole(){};
wormhole* operator = (const wormhole *a) { *this=*a; return this; };
/*wormhole* operator = (const wormhole &a) { ...copy... return this; };*/
void ah2xyz(double *xyz,double a,double h) // compute cone position from parameters a=<0,2pi>, h=<0,1>
{
double r,tt;
tt=t; if (t>0.5) tt=0.5; r=2.0*R0*tt; // inner radius R0
tt=t; if (t>1.0) tt=1.0; r+=(R1-r)*h*h*tt; // outer radius R1
xyz[0]=r*cos(a);
xyz[1]=r*sin(a);
xyz[2]=H*h*tt;
rep.l2g(xyz,xyz);
}
void draw_cone()
{
int e;
double a,h,da=pi2*0.04,p[3];
glColor3f(0.2,0.2,0.2);
for (h=0.0;h<=1.0;h+=0.1){ glBegin(GL_LINE_STRIP); for (e=1,a=0.0;e;a+=da) { if (a>=pi2) { e=0; a=0.0; } ah2xyz(p,a,h); glVertex3dv(p); } glEnd(); }
for (e=1,a=0.0;e;a+=da){ glBegin(GL_LINE_STRIP); for (h=0.0;h<=1.0;h+=0.1) { if (a>=pi2) { e=0; a=0.0; } ah2xyz(p,a,h); glVertex3dv(p); } glEnd(); }
}
} hole;
Where rep is my class for homogenous 4x4 transform matrix (remembering both direct and inverse matrices at the same time) function l2g just transforms from local coordinates to global. The cone parameters are:
R0 - inner cone radius when fully grown
R1 - outer cone radius when fully grown
H - the height/depth of the cone when fully grown
t - is animation parameter values <0.0,1.0> are the growth and values above 1.0 are reserved for wormhole fully grown animation
Here how it looks like:
What I would do is simply calculate a vector from the texture coordinate of the screen center to the texture coordinate of the pixel you're shading.
Then modify that vector in any way you want (time based for example) and apply it to the texture coordinate of the pixel you're shading and then use the resulting coordinate to sample your texture.
In pseudocode this would be something like this:
vec2 vector_to_screen_center = vec2(0.5) - texture_coordinate;
texture_coordinate += vector_to_screen_center * sin(time) * 0.1; // Time based modulation of the vector.
gl_FragColor = texture2D(screen_texture, texture_coordinate);
Your question does not have a GLSL tag. If you plan to do this without shaders, this is going to be hard and/or inefficient.

Find the distance between a 3D point and an Orientated Ellipse in 3D space (C++)

To give some background to this question, I'm creating a game that needs to know whether the 'Orbit' of an object is within tolerance to another Orbit. To show this, I plot a Torus-shape with a given radius (the tolerance) using the Target Orbit, and now I need to check if the ellipse is within that torus.
I'm getting lost in the equations on Math/Stack exchange so asking for a more specific solution. For clarification, here's an image of the game with the Torus and an Orbit (the red line). Quite simply, I want to check if that red orbit is within that Torus shape.
What I believe I need to do, is plot four points in World-Space on one of those orbits (easy enough to do). I then need to calculate the shortest distance between that point, and the other orbits' ellipse. This is the difficult part. There are several examples out there of finding the shortest distance of a point to an ellipse, but all are 2D and quite difficult to follow.
If that distance is then less than the tolerance for all four points, then in think that equates to the orbit being inside the target torus.
For simplicity, the origin of all of these orbits is always at the world Origin (0, 0, 0) - and my coordinate system is Z-Up. Each orbit has a series of parameters that defines it (Orbital Elements).
Here simple approach:
Sample each orbit to set of N points.
Let points from first orbit be A and from second orbit B.
const int N=36;
float A[N][3],B[N][3];
find 2 closest points
so d=|A[i]-B[i]| is minimal. If d is less or equal to your margin/treshold then orbits are too close to each other.
speed vs. accuracy
Unless you are using some advanced method for #2 then its computation will be O(N^2) which is a bit scary. The bigger the N the better accuracy of result but a lot more time to compute. There are ways how to remedy both. For example:
first sample with small N
when found the closest points sample both orbits again
but only near those points in question (with higher N).
you can recursively increase accuracy by looping #2 until you have desired precision
test d if ellipses are too close to each other
I think I may have a new solution.
Plot the four points on the current orbit (the ellipse).
Project those points onto the plane of the target orbit (the torus).
Using the Target Orbit inclination as the normal of a plane, calculate the angle between each (normalized) point and the argument of periapse
on the target orbit.
Use this angle as the mean anomaly, and compute the equivalent eccentric anomaly.
Use those eccentric anomalies to plot the four points on the target orbit - which should be the nearest points to the other orbit.
Check the distance between those points.
The difficulty here comes from computing the angle and converting it to the anomaly on the other orbit. This should be more accurate and faster than a recursive function though. Will update when I've tried this.
EDIT:
Yep, this works!
// The Four Locations we will use for the checks
TArray<FVector> CurrentOrbit_CheckPositions;
TArray<FVector> TargetOrbit_ProjectedPositions;
CurrentOrbit_CheckPositions.SetNum(4);
TargetOrbit_ProjectedPositions.SetNum(4);
// We first work out the plane of the target orbit.
const FVector Target_LANVector = FVector::ForwardVector.RotateAngleAxis(TargetOrbit.LongitudeAscendingNode, FVector::UpVector); // Vector pointing to Longitude of Ascending Node
const FVector Target_INCVector = FVector::UpVector.RotateAngleAxis(TargetOrbit.Inclination, Target_LANVector); // Vector pointing up the inclination axis (orbit normal)
const FVector Target_AOPVector = Target_LANVector.RotateAngleAxis(TargetOrbit.ArgumentOfPeriapsis, Target_INCVector); // Vector pointing towards the periapse (closest approach)
// Geometric plane of the orbit, using the inclination vector as the normal.
const FPlane ProjectionPlane = FPlane(Target_INCVector, 0.f); // Plane of the orbit. We only need the 'normal', and the plane origin is the Earths core (periapse focal point)
// Plot four points on the current orbit, using an equally-divided eccentric anomaly.
const float ECCAngle = PI / 2.f;
for (int32 i = 0; i < 4; i++)
{
// Plot the point, then project it onto the plane
CurrentOrbit_CheckPositions[i] = PosFromEccAnomaly(i * ECCAngle, CurrentOrbit);
CurrentOrbit_CheckPositions[i] = FVector::PointPlaneProject(CurrentOrbit_CheckPositions[i], ProjectionPlane);
// TODO: Distance from the plane is the 'Depth'. If the Depth is > Acceptance Radius, we are outside the torus and can early-out here
// Normalize the point to find it's direction in world-space (origin in our case is always 0,0,0)
const FVector PositionDirectionWS = CurrentOrbit_CheckPositions[i].GetSafeNormal();
// Using the Inclination as the comparison plane - find the angle between the direction of this vector, and the Argument of Periapse vector of the Target orbit
// TODO: we can probably compute this angle once, using the Periapse vectors from each orbit, and just multiply it by the Index 'I'
float Angle = FMath::Acos(FVector::DotProduct(PositionDirectionWS, Target_AOPVector));
// Compute the 'Sign' of the Angle (-180.f - 180.f), using the Cross Product
const FVector Cross = FVector::CrossProduct(PositionDirectionWS, Target_AOPVector);
if (FVector::DotProduct(Cross, Target_INCVector) > 0)
{
Angle = -Angle;
}
// Using the angle directly will give us the position at th eccentric anomaly. We want to take advantage of the Mean Anomaly, and use it as the ecc anomaly
// We can use this to plot a point on the target orbit, as if it was the eccentric anomaly.
Angle = Angle - TargetOrbit.Eccentricity * FMathD::Sin(Angle);
TargetOrbit_ProjectedPositions[i] = PosFromEccAnomaly(Angle, TargetOrbit);}
I hope the comments describe how this works. Finally solved after several months of head-scratching. Thanks all!

3D intersection (Radiosity) - OpenGl

I am trying to compute the visibility between two planes or patches.
I have a wireframe of quads. Each quad has a normal vector with X, Y and Z coordinates. Each quad has 4 vertices. Each vertex has X, Y and Z coordinates.
Given two quads, how can I know if there is an occluder or another object in between these two patches (quads).
Therefore, I need to create a method that returns 1 if patches has no occluders or return 0 if patches has occluder.
The method I picture would be something like this:
GLint visibility(Patch i, Patch j) {
GLboolean isVisible;
vector<Patch> allPatches; // can be used to get all patches in the scene
// Check if there is any occluder between patch i and patch j
Some computations here
if(isVisible) {
return 1;
} else {
return 0;
}
}
I've heard of z-buffer algorithms and the hemicube implementation that would get this done. I already have the form-factors computed. I just need to finish this step to get shadows.
Make sure you give some form of answer with graphs or methods because I am not that genius
I found the solution. Basically I needed to use ray tracing techniques. Throw ray from one patch to another and check if ray intercepts the planes with barycentric equation computation. Once you find the control points you need to check if the control point lies on you quad.