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
|
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)
|
void KRAABB::encapsulate(const KRAABB & b)
|
||||||
|
|||||||
@@ -99,7 +99,10 @@ bool KRCollider::lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &h
|
|||||||
loadModel();
|
loadModel();
|
||||||
if(m_models.size()) {
|
if(m_models.size()) {
|
||||||
if(getBounds().intersectsLine(v0, v1)) {
|
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 v0_model_space = KRMat4::Dot(getInverseModelMatrix(), v0);
|
||||||
KRVector3 v1_model_space = KRMat4::Dot(getInverseModelMatrix(), v1);
|
KRVector3 v1_model_space = KRMat4::Dot(getInverseModelMatrix(), v1);
|
||||||
if(m_models[0]->lineCast(v0_model_space, v1_model_space, hitinfo_model_space)) {
|
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();
|
loadModel();
|
||||||
if(m_models.size()) {
|
if(m_models.size()) {
|
||||||
if(getBounds().intersectsRay(v0, dir)) {
|
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 v0_model_space = KRMat4::Dot(getInverseModelMatrix(), v0);
|
||||||
KRVector3 dir_model_space = KRMat4::DotNoTranslate(getInverseModelMatrix(), dir);
|
KRVector3 dir_model_space = KRVector3::Normalize(KRMat4::DotNoTranslate(getInverseModelMatrix(), dir));
|
||||||
if(m_models[0]->rayCast(v0_model_space, dir, hitinfo_model_space)) {
|
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);
|
hitinfo = KRHitInfo(KRMat4::Dot(getModelMatrix(), hitinfo_model_space.getPosition()), KRVector3::Normalize(KRMat4::DotNoTranslate(getModelMatrix(), hitinfo_model_space.getNormal())), this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,9 @@ KRHitInfo::KRHitInfo()
|
|||||||
KRHitInfo::KRHitInfo(const KRVector3 &position, const KRVector3 &normal, KRNode *node)
|
KRHitInfo::KRHitInfo(const KRVector3 &position, const KRVector3 &normal, KRNode *node)
|
||||||
{
|
{
|
||||||
m_position = position;
|
m_position = position;
|
||||||
|
if(m_position == KRVector3::Zero()) {
|
||||||
|
fprintf(stderr, "Zero position hitinfo\n");
|
||||||
|
}
|
||||||
m_normal = normal;
|
m_normal = normal;
|
||||||
m_node = node;
|
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 new_hit_distance_sqr = (hit_point - line_v0).sqrMagnitude();
|
||||||
float prev_hit_distance_sqr = (hitinfo.getPosition() - 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
|
// 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
|
// 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));
|
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);
|
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