hashbrown

09-26-2016, 01:22 AM

I'm learning how OBB Raycasting works from this great site (http://www.opengl-tutorial.org/miscellaneous/clicking-on-objects/picking-with-custom-ray-obb-function/). I'm testing against a cube and managed to get everything up and running (intersection test works), but I can't seem to figure out how to get the point of intersection. I'd love to return the exact position the ray first hit the box, or in other words: what position on the target box's normal local space was hit. I'd use these coordinates to stick another game object there. Think sticking c4 on a wall (in a game).

Right now what I do is:

hitpoint.x = targetWorldspace.x + (-delta.x / distance);

hitpoint.y = targetWorldspace.y; // Nothing special

hitpoint.z = targetWorldspace.z + (-delta.z / distance);

... this happens after intersection test passed.

This barely works, the hit point definitely ends up on the right side of the cube, and somewhat close to the correct face. If I don't give the hitpoint some offset, the hitpoint would be in the middle of the target box obviously. I'm very sure I'm doing it wrong. This is what I'm using to test intersection:

bool Collision::OBBIntersection(

Vec3 origin,

Vec3 dir,

Vec3 aabbMin,

Vec3 aabbMax,

GameObject &target,

float &distance,

Vec3 &hitpoint){

float tMin = 0.0f;

float tMax = 100000.0f;

Mat4 model = target.GetTransform().GetModel();

Vec3 targetWorldspace;

targetWorldspace.x = model.mat[0][3];

targetWorldspace.y = model.mat[1][3];

targetWorldspace.z = model.mat[2][3];

Vec3 delta = (targetWorldspace - origin);

{

Vec3 xAxis(model.mat[0][0], model.mat[1][0], model.mat[2][0]);

float e = Trig::Dot(xAxis, delta);

float f = Trig::Dot(dir, xAxis);

if (fabs(f) > 0.001f) {

float t1 = (e + aabbMin.x)/f;

float t2 = (e + aabbMax.x)/f;

if (t1 > t2) {

float w = t1;

t1 = t2;

t2 = w;

}

if (t2 < tMax) {

tMax = t2;

}

if (t1 > tMin) {

tMin = t1;

}

if (tMax < tMin) {

return false;

}

}

else {

if (-e + aabbMin.x > 0.0f || -e + aabbMax.x < 0.0f) {

return false;

}

}

}

{

Vec3 yAxis(model.mat[0][1], model.mat[1][1], model.mat[2][1]);

float e = Trig::Dot(yAxis, delta);

float f = Trig::Dot(dir, yAxis);

if (fabs(f) > 0.001f) {

float t1 = (e + aabbMin.y)/f;

float t2 = (e + aabbMax.y)/f;

if (t1 > t2) {

float w = t1;

t1 = t2;

t2 = w;

}

if (t2 < tMax) {

tMax = t2;

}

if (t1 > tMin) {

tMin = t1;

}

if (tMax < tMin) {

return false;

}

}

else {

if (-e + aabbMin.y > 0.0f || -e + aabbMax.y < 0.0f) {

return false;

}

}

}

{

Vec3 zAxis(model.mat[0][2], model.mat[1][2], model.mat[2][2]);

float e = Trig::Dot(zAxis, delta);

float f = Trig::Dot(dir, zAxis);

if (fabs(f) > 0.001f) {

float t1 = (e + aabbMin.z)/f;

float t2 = (e + aabbMax.z)/f;

if (t1 > t2) {

float w = t1;

t1 = t2;

t2 = w;

}

if (t2 < tMax) {

tMax = t2;

}

if (t1 > tMin) {

tMin = t1;

}

if (tMax < tMin) {

return false;

}

}

else {

if (-e + aabbMin.z > 0.0f || -e + aabbMax.z < 0.0f) {

return false;

}

}

}

distance = tMin;

hitpoint.x = targetWorldspace.x + (-delta.x / distance);

hitpoint.y = targetWorldspace.y;

hitpoint.z = targetWorldspace.z + (-delta.z / distance);

return true;

}

Right now what I do is:

hitpoint.x = targetWorldspace.x + (-delta.x / distance);

hitpoint.y = targetWorldspace.y; // Nothing special

hitpoint.z = targetWorldspace.z + (-delta.z / distance);

... this happens after intersection test passed.

This barely works, the hit point definitely ends up on the right side of the cube, and somewhat close to the correct face. If I don't give the hitpoint some offset, the hitpoint would be in the middle of the target box obviously. I'm very sure I'm doing it wrong. This is what I'm using to test intersection:

bool Collision::OBBIntersection(

Vec3 origin,

Vec3 dir,

Vec3 aabbMin,

Vec3 aabbMax,

GameObject &target,

float &distance,

Vec3 &hitpoint){

float tMin = 0.0f;

float tMax = 100000.0f;

Mat4 model = target.GetTransform().GetModel();

Vec3 targetWorldspace;

targetWorldspace.x = model.mat[0][3];

targetWorldspace.y = model.mat[1][3];

targetWorldspace.z = model.mat[2][3];

Vec3 delta = (targetWorldspace - origin);

{

Vec3 xAxis(model.mat[0][0], model.mat[1][0], model.mat[2][0]);

float e = Trig::Dot(xAxis, delta);

float f = Trig::Dot(dir, xAxis);

if (fabs(f) > 0.001f) {

float t1 = (e + aabbMin.x)/f;

float t2 = (e + aabbMax.x)/f;

if (t1 > t2) {

float w = t1;

t1 = t2;

t2 = w;

}

if (t2 < tMax) {

tMax = t2;

}

if (t1 > tMin) {

tMin = t1;

}

if (tMax < tMin) {

return false;

}

}

else {

if (-e + aabbMin.x > 0.0f || -e + aabbMax.x < 0.0f) {

return false;

}

}

}

{

Vec3 yAxis(model.mat[0][1], model.mat[1][1], model.mat[2][1]);

float e = Trig::Dot(yAxis, delta);

float f = Trig::Dot(dir, yAxis);

if (fabs(f) > 0.001f) {

float t1 = (e + aabbMin.y)/f;

float t2 = (e + aabbMax.y)/f;

if (t1 > t2) {

float w = t1;

t1 = t2;

t2 = w;

}

if (t2 < tMax) {

tMax = t2;

}

if (t1 > tMin) {

tMin = t1;

}

if (tMax < tMin) {

return false;

}

}

else {

if (-e + aabbMin.y > 0.0f || -e + aabbMax.y < 0.0f) {

return false;

}

}

}

{

Vec3 zAxis(model.mat[0][2], model.mat[1][2], model.mat[2][2]);

float e = Trig::Dot(zAxis, delta);

float f = Trig::Dot(dir, zAxis);

if (fabs(f) > 0.001f) {

float t1 = (e + aabbMin.z)/f;

float t2 = (e + aabbMax.z)/f;

if (t1 > t2) {

float w = t1;

t1 = t2;

t2 = w;

}

if (t2 < tMax) {

tMax = t2;

}

if (t1 > tMin) {

tMin = t1;

}

if (tMax < tMin) {

return false;

}

}

else {

if (-e + aabbMin.z > 0.0f || -e + aabbMax.z < 0.0f) {

return false;

}

}

}

distance = tMin;

hitpoint.x = targetWorldspace.x + (-delta.x / distance);

hitpoint.y = targetWorldspace.y;

hitpoint.z = targetWorldspace.z + (-delta.z / distance);

return true;

}