diff --git a/KREngine/kraken/KRAABB.cpp b/KREngine/kraken/KRAABB.cpp index eea361f..2532d26 100644 --- a/KREngine/kraken/KRAABB.cpp +++ b/KREngine/kraken/KRAABB.cpp @@ -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) diff --git a/KREngine/kraken/KRCollider.cpp b/KREngine/kraken/KRCollider.cpp index 167bca4..ef58845 100644 --- a/KREngine/kraken/KRCollider.cpp +++ b/KREngine/kraken/KRCollider.cpp @@ -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; } diff --git a/KREngine/kraken/KRHitInfo.cpp b/KREngine/kraken/KRHitInfo.cpp index b0bde92..3e0d048 100644 --- a/KREngine/kraken/KRHitInfo.cpp +++ b/KREngine/kraken/KRHitInfo.cpp @@ -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; } diff --git a/KREngine/kraken/KRMesh.cpp b/KREngine/kraken/KRMesh.cpp index 970e8e1..ed3190e 100644 --- a/KREngine/kraken/KRMesh.cpp +++ b/KREngine/kraken/KRMesh.cpp @@ -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 } /*