Fixed bugs in RayCast routines, which resulted in incorrect hit test results for scaled or rotated collision meshes.
Added implementation to stub function , KRAABB::intersectsRay, to enable performance boost for RayCast routines
This commit is contained in:
@@ -208,8 +208,75 @@ bool KRAABB::intersectsLine(const KRVector3 &v1, const KRVector3 &v2) const
|
||||
|
||||
bool KRAABB::intersectsRay(const KRVector3 &v1, const KRVector3 &dir) const
|
||||
{
|
||||
// FINDME, TODO - Need to implement this
|
||||
return true;
|
||||
/*
|
||||
Fast Ray-Box Intersection
|
||||
by Andrew Woo
|
||||
from "Graphics Gems", Academic Press, 1990
|
||||
*/
|
||||
|
||||
// FINDME, TODO - Perhaps there is a more efficient algorithm, as we don't actually need the exact coordinate of the intersection
|
||||
|
||||
enum {
|
||||
RIGHT = 0,
|
||||
LEFT = 1,
|
||||
MIDDLE = 2
|
||||
} quadrant[3];
|
||||
|
||||
bool inside = true;
|
||||
KRVector3 maxT;
|
||||
KRVector3 coord;
|
||||
double candidatePlane[3];
|
||||
|
||||
// Find candidate planes; this loop can be avoided if rays cast all from the eye(assume perpsective view)
|
||||
for (int i=0; i<3; i++)
|
||||
if(v1.c[i] < min.c[i]) {
|
||||
quadrant[i] = LEFT;
|
||||
candidatePlane[i] = min.c[i];
|
||||
inside = FALSE;
|
||||
}else if (v1.c[i] > max.c[i]) {
|
||||
quadrant[i] = RIGHT;
|
||||
candidatePlane[i] = max.c[i];
|
||||
inside = FALSE;
|
||||
}else {
|
||||
quadrant[i] = MIDDLE;
|
||||
}
|
||||
|
||||
/* Ray v1 inside bounding box */
|
||||
if(inside) {
|
||||
coord = v1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/* Calculate T distances to candidate planes */
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (quadrant[i] != MIDDLE && dir[i] !=0.) {
|
||||
maxT.c[i] = (candidatePlane[i]-v1.c[i]) / dir[i];
|
||||
} else {
|
||||
maxT.c[i] = -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get largest of the maxT's for final choice of intersection */
|
||||
int whichPlane = 0;
|
||||
for (int i = 1; i < 3; i++) {
|
||||
if (maxT.c[whichPlane] < maxT.c[i]) {
|
||||
whichPlane = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check final candidate actually inside box */
|
||||
if (maxT.c[whichPlane] < 0.0f) return false;
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (whichPlane != i) {
|
||||
coord[i] = v1.c[i] + maxT.c[whichPlane] *dir[i];
|
||||
if (coord[i] < min.c[i] || coord[i] > max.c[i])
|
||||
return false;
|
||||
} else {
|
||||
coord[i] = candidatePlane[i];
|
||||
}
|
||||
}
|
||||
return true; /* ray hits box */
|
||||
}
|
||||
|
||||
void KRAABB::encapsulate(const KRAABB & b)
|
||||
|
||||
@@ -99,7 +99,10 @@ bool KRCollider::lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &h
|
||||
loadModel();
|
||||
if(m_models.size()) {
|
||||
if(getBounds().intersectsLine(v0, v1)) {
|
||||
KRHitInfo hitinfo_model_space = KRHitInfo(KRMat4::Dot(getInverseModelMatrix(), hitinfo.getPosition()), KRMat4::DotNoTranslate(getInverseModelMatrix(), hitinfo.getNormal()), hitinfo.getNode());
|
||||
KRHitInfo hitinfo_model_space;
|
||||
if(hitinfo.didHit()) {
|
||||
hitinfo_model_space = KRHitInfo(KRMat4::Dot(getInverseModelMatrix(), hitinfo.getPosition()), KRMat4::DotNoTranslate(getInverseModelMatrix(), hitinfo.getNormal()), hitinfo.getNode());
|
||||
}
|
||||
KRVector3 v0_model_space = KRMat4::Dot(getInverseModelMatrix(), v0);
|
||||
KRVector3 v1_model_space = KRMat4::Dot(getInverseModelMatrix(), v1);
|
||||
if(m_models[0]->lineCast(v0_model_space, v1_model_space, hitinfo_model_space)) {
|
||||
@@ -118,10 +121,13 @@ bool KRCollider::rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &h
|
||||
loadModel();
|
||||
if(m_models.size()) {
|
||||
if(getBounds().intersectsRay(v0, dir)) {
|
||||
KRHitInfo hitinfo_model_space = KRHitInfo(KRMat4::Dot(getInverseModelMatrix(), hitinfo.getPosition()), KRVector3::Normalize(KRMat4::DotNoTranslate(getInverseModelMatrix(), hitinfo.getNormal())), hitinfo.getNode());
|
||||
KRHitInfo hitinfo_model_space;
|
||||
if(hitinfo.didHit()) {
|
||||
hitinfo_model_space = KRHitInfo(KRMat4::Dot(getInverseModelMatrix(), hitinfo.getPosition()), KRVector3::Normalize(KRMat4::DotNoTranslate(getInverseModelMatrix(), hitinfo.getNormal())), hitinfo.getNode());
|
||||
}
|
||||
KRVector3 v0_model_space = KRMat4::Dot(getInverseModelMatrix(), v0);
|
||||
KRVector3 dir_model_space = KRMat4::DotNoTranslate(getInverseModelMatrix(), dir);
|
||||
if(m_models[0]->rayCast(v0_model_space, dir, hitinfo_model_space)) {
|
||||
KRVector3 dir_model_space = KRVector3::Normalize(KRMat4::DotNoTranslate(getInverseModelMatrix(), dir));
|
||||
if(m_models[0]->rayCast(v0_model_space, dir_model_space, hitinfo_model_space)) {
|
||||
hitinfo = KRHitInfo(KRMat4::Dot(getModelMatrix(), hitinfo_model_space.getPosition()), KRVector3::Normalize(KRMat4::DotNoTranslate(getModelMatrix(), hitinfo_model_space.getNormal())), this);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,9 @@ KRHitInfo::KRHitInfo()
|
||||
KRHitInfo::KRHitInfo(const KRVector3 &position, const KRVector3 &normal, KRNode *node)
|
||||
{
|
||||
m_position = position;
|
||||
if(m_position == KRVector3::Zero()) {
|
||||
fprintf(stderr, "Zero position hitinfo\n");
|
||||
}
|
||||
m_normal = normal;
|
||||
m_node = node;
|
||||
}
|
||||
|
||||
@@ -836,7 +836,11 @@ bool KRMesh::rayCast(const KRVector3 &line_v0, const KRVector3 &dir, const KRVec
|
||||
|
||||
float new_hit_distance_sqr = (hit_point - line_v0).sqrMagnitude();
|
||||
float prev_hit_distance_sqr = (hitinfo.getPosition() - line_v0).sqrMagnitude();
|
||||
if(new_hit_distance_sqr < prev_hit_distance_sqr) {
|
||||
|
||||
// ---===--- hit_point is in triangle ---===---
|
||||
|
||||
|
||||
if(new_hit_distance_sqr < prev_hit_distance_sqr || !hitinfo.didHit()) {
|
||||
// Update the hitinfo object if this hit is closer than the prior hit
|
||||
|
||||
// Interpolate between the three vertex normals, performing a 3-way lerp of tri_n0, tri_n1, and tri_n2
|
||||
@@ -850,9 +854,10 @@ bool KRMesh::rayCast(const KRVector3 &line_v0, const KRVector3 &dir, const KRVec
|
||||
KRVector3 normal = KRVector3::Normalize(tri_n0 * (1.0 - distance_v0) + tri_n1 * (1.0 - distance_v1) + tri_n2 * (1.0 - distance_v2));
|
||||
|
||||
hitinfo = KRHitInfo(hit_point, normal);
|
||||
return true;
|
||||
} else {
|
||||
return false; // Either no hit, or the hit was farther than an existing hit
|
||||
}
|
||||
|
||||
return true; // hit_point is in triangle
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user