KRAABB line cast culling algorithm is more intelligent now
Implemented ray casts and KRAABB ray intersections --HG-- extra : convert_revision : svn%3A7752d6cf-9f14-4ad2-affc-04f1e67b81a5/trunk%40196
This commit is contained in:
@@ -234,37 +234,48 @@ float KRAABB::longest_radius() const
|
||||
|
||||
bool KRAABB::intersectsLine(const KRVector3 &v1, const KRVector3 &v2) const
|
||||
{
|
||||
// http://www.3dkingdoms.com/weekly/bbox.h
|
||||
KRVector3 dir = KRVector3::Normalize(v2 - v1);
|
||||
float length = (v2 - v1).magnitude();
|
||||
|
||||
/*
|
||||
// Put line in box space
|
||||
KRMat4 MInv = m_M.InvertSimple();
|
||||
KRVector3 LB1 = MInv * L1;
|
||||
KRVector3 LB2 = MInv * L2;
|
||||
|
||||
// Get line midpoint and extent
|
||||
KRVector3 LMid = (LB1 + LB2) * 0.5f;
|
||||
KRVector3 L = (LB1 - LMid);
|
||||
KRVector3 LExt = KRVector3( fabs(L.x), fabs(L.y), fabs(L.z) );
|
||||
|
||||
// Use Separating Axis Test
|
||||
// Separation vector from box center to line center is LMid, since the line is in box space
|
||||
if ( fabs( LMid.x ) > m_Extent.x + LExt.x ) return false;
|
||||
if ( fabs( LMid.y ) > m_Extent.y + LExt.y ) return false;
|
||||
if ( fabs( LMid.z ) > m_Extent.z + LExt.z ) return false;
|
||||
// Crossproducts of line and each axis
|
||||
if ( fabs( LMid.y * L.z - LMid.z * L.y) > (m_Extent.y * LExt.z + m_Extent.z * LExt.y) ) return false;
|
||||
if ( fabs( LMid.x * L.z - LMid.z * L.x) > (m_Extent.x * LExt.z + m_Extent.z * LExt.x) ) return false;
|
||||
if ( fabs( LMid.x * L.y - LMid.y * L.x) > (m_Extent.x * LExt.y + m_Extent.y * LExt.x) ) return false;
|
||||
// No separating axis, the line intersects
|
||||
// EZ cases: if the ray starts inside the box, or ends inside
|
||||
// the box, then it definitely hits the box.
|
||||
// I'm using this code for ray tracing with an octree,
|
||||
// so I needed rays that start and end within an
|
||||
// octree node to COUNT as hits.
|
||||
// You could modify this test to (ray starts inside and ends outside)
|
||||
// to qualify as a hit if you wanted to NOT count totally internal rays
|
||||
if( contains( v1 ) || contains( v2 ) )
|
||||
return true ;
|
||||
|
||||
*/
|
||||
return false;
|
||||
// the algorithm says, find 3 t's,
|
||||
KRVector3 t ;
|
||||
|
||||
// LARGEST t is the only one we need to test if it's on the face.
|
||||
for(int i = 0 ; i < 3 ; i++) {
|
||||
if( dir[i] > 0 ) { // CULL BACK FACE
|
||||
t[i] = ( min[i] - v1[i] ) / dir[i];
|
||||
} else {
|
||||
t[i] = ( max[i] - v1[i] ) / dir[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool KRAABB::intersectsRay(const KRVector3 &v1, const KRVector3 &v2) const
|
||||
int mi = 0;
|
||||
if(t[1] > t[mi]) mi = 1;
|
||||
if(t[2] > t[mi]) mi = 2;
|
||||
if(t[mi] >= 0 && t[mi] <= length) {
|
||||
KRVector3 pt = v1 + dir * t[mi];
|
||||
|
||||
// check it's in the box in other 2 dimensions
|
||||
int o1 = ( mi + 1 ) % 3 ; // i=0: o1=1, o2=2, i=1: o1=2,o2=0 etc.
|
||||
int o2 = ( mi + 2 ) % 3 ;
|
||||
|
||||
return pt[o1] >= min[o1] && pt[o1] <= max[o1] && pt[o2] >= min[o2] && pt[o2] <= max[o2];
|
||||
}
|
||||
|
||||
return false ; // the ray did not hit the box.
|
||||
}
|
||||
|
||||
bool KRAABB::intersectsRay(const KRVector3 &v1, const KRVector3 &dir) const
|
||||
{
|
||||
// TODO - Implementation needed
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ public:
|
||||
bool contains(const KRVector3 &v) const;
|
||||
bool visible(const KRMat4 &matViewProjection) const;
|
||||
bool intersectsLine(const KRVector3 &v1, const KRVector3 &v2) const;
|
||||
bool intersectsRay(const KRVector3 &v1, const KRVector3 &v2) const;
|
||||
bool intersectsRay(const KRVector3 &v1, const KRVector3 &dir) const;
|
||||
|
||||
KRAABB& operator =(const KRAABB& b);
|
||||
bool operator ==(const KRAABB& b) const;
|
||||
|
||||
@@ -89,14 +89,14 @@ bool KRCollider::lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &h
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KRCollider::rayCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo)
|
||||
bool KRCollider::rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hitinfo)
|
||||
{
|
||||
if(m_models.size()) {
|
||||
if(getBounds().intersectsRay(v0, v1)) {
|
||||
if(getBounds().intersectsRay(v0, dir)) {
|
||||
KRHitInfo hitinfo_model_space = KRHitInfo(KRMat4::Dot(getInverseModelMatrix(), hitinfo.getPosition()), KRMat4::DotNoTranslate(getInverseModelMatrix(), hitinfo.getNormal()), hitinfo.getNode());
|
||||
KRVector3 v0_model_space = KRMat4::Dot(getModelMatrix(), v0);
|
||||
KRVector3 v1_model_space = v0_model_space + KRMat4::DotNoTranslate(getModelMatrix(), KRVector3::Normalize(v1 - v0));
|
||||
if(m_models[0]->lineCast(v0_model_space, v1_model_space, hitinfo_model_space)) {
|
||||
KRVector3 dir_model_space = KRMat4::DotNoTranslate(getModelMatrix(), dir);
|
||||
if(m_models[0]->rayCast(v0_model_space, dir, hitinfo_model_space)) {
|
||||
hitinfo = KRHitInfo(KRMat4::Dot(getModelMatrix(), hitinfo_model_space.getPosition()), KRMat4::DotNoTranslate(getModelMatrix(), hitinfo_model_space.getNormal()), this);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -741,12 +741,12 @@ KRModel::model_format_t KRModel::getModelFormat() const
|
||||
return (model_format_t)getHeader()->model_format;
|
||||
}
|
||||
|
||||
bool KRModel::rayCast(const KRVector3 &line_v0, const KRVector3 &line_v1, const KRVector3 &tri_v0, const KRVector3 &tri_v1, const KRVector3 &tri_v2, const KRVector3 &tri_n0, const KRVector3 &tri_n1, const KRVector3 &tri_n2, KRHitInfo &hitinfo)
|
||||
bool KRModel::rayCast(const KRVector3 &line_v0, const KRVector3 &dir, const KRVector3 &tri_v0, const KRVector3 &tri_v1, const KRVector3 &tri_v2, const KRVector3 &tri_n0, const KRVector3 &tri_n1, const KRVector3 &tri_n2, KRHitInfo &hitinfo)
|
||||
{
|
||||
// algorithm based on Dan Sunday's implementation at http://geomalgorithms.com/a06-_intersect-2.html
|
||||
const float SMALL_NUM = 0.00000001; // anything that avoids division overflow
|
||||
KRVector3 u, v, n; // triangle vectors
|
||||
KRVector3 dir, w0, w; // ray vectors
|
||||
KRVector3 w0, w; // ray vectors
|
||||
float r, a, b; // params to calc ray-plane intersect
|
||||
|
||||
// get triangle edge vectors and plane normal
|
||||
@@ -756,7 +756,6 @@ bool KRModel::rayCast(const KRVector3 &line_v0, const KRVector3 &line_v1, const
|
||||
if (n == KRVector3::Zero()) // triangle is degenerate
|
||||
return false; // do not deal with this case
|
||||
|
||||
dir = line_v1 - line_v0; // ray direction vector
|
||||
w0 = line_v0 - tri_v0;
|
||||
a = -KRVector3::Dot(n, w0);
|
||||
b = KRVector3::Dot(n,dir);
|
||||
@@ -817,12 +816,12 @@ bool KRModel::rayCast(const KRVector3 &line_v0, const KRVector3 &line_v1, const
|
||||
return true; // hit_point is in triangle
|
||||
}
|
||||
|
||||
bool KRModel::rayCast(const KRVector3 &line_v0, const KRVector3 &line_v1, int tri_index0, int tri_index1, int tri_index2, KRHitInfo &hitinfo) const
|
||||
bool KRModel::rayCast(const KRVector3 &line_v0, const KRVector3 &dir, int tri_index0, int tri_index1, int tri_index2, KRHitInfo &hitinfo) const
|
||||
{
|
||||
return rayCast(line_v0, line_v1, getVertexPosition(tri_index0), getVertexPosition(tri_index1), getVertexPosition(tri_index2), getVertexNormal(tri_index0), getVertexNormal(tri_index1), getVertexNormal(tri_index2), hitinfo);
|
||||
return rayCast(line_v0, dir, getVertexPosition(tri_index0), getVertexPosition(tri_index1), getVertexPosition(tri_index2), getVertexNormal(tri_index0), getVertexNormal(tri_index1), getVertexNormal(tri_index2), hitinfo);
|
||||
}
|
||||
|
||||
bool KRModel::rayCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo) const
|
||||
bool KRModel::rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hitinfo) const
|
||||
{
|
||||
bool hit_found = false;
|
||||
for(int submesh_index=0; submesh_index < getSubmeshCount(); submesh_index++) {
|
||||
@@ -830,12 +829,12 @@ bool KRModel::rayCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitin
|
||||
switch(getModelFormat()) {
|
||||
case KRENGINE_MODEL_FORMAT_TRIANGLES:
|
||||
for(int triangle_index=0; triangle_index < vertex_count / 3; triangle_index++) {
|
||||
if(rayCast(v0, v1, getVertexPosition(triangle_index*3), getVertexPosition(triangle_index*3+1), getVertexPosition(triangle_index*3+2), getVertexNormal(triangle_index*3), getVertexNormal(triangle_index*3+1), getVertexNormal(triangle_index*3+2), hitinfo)) hit_found = true;
|
||||
if(rayCast(v0, dir, getVertexPosition(triangle_index*3), getVertexPosition(triangle_index*3+1), getVertexPosition(triangle_index*3+2), getVertexNormal(triangle_index*3), getVertexNormal(triangle_index*3+1), getVertexNormal(triangle_index*3+2), hitinfo)) hit_found = true;
|
||||
}
|
||||
break;
|
||||
case KRENGINE_MODEL_FORMAT_STRIP:
|
||||
for(int triangle_index=0; triangle_index < vertex_count - 2; triangle_index++) {
|
||||
if(rayCast(v0, v1, getVertexPosition(triangle_index), getVertexPosition(triangle_index+1), getVertexPosition(triangle_index+2), getVertexNormal(triangle_index), getVertexNormal(triangle_index+1), getVertexNormal(triangle_index+2), hitinfo)) hit_found = true;
|
||||
if(rayCast(v0, dir, getVertexPosition(triangle_index), getVertexPosition(triangle_index+1), getVertexPosition(triangle_index+2), getVertexNormal(triangle_index), getVertexNormal(triangle_index+1), getVertexNormal(triangle_index+2), hitinfo)) hit_found = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -848,7 +847,8 @@ bool KRModel::rayCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitin
|
||||
bool KRModel::lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo) const
|
||||
{
|
||||
KRHitInfo new_hitinfo;
|
||||
if(rayCast(v0, v1, new_hitinfo)) {
|
||||
KRVector3 dir = KRVector3::Normalize(v1 - v0);
|
||||
if(rayCast(v0, dir, new_hitinfo)) {
|
||||
if((new_hitinfo.getPosition() - v0).sqrMagnitude() <= (v1 - v0).sqrMagnitude()) {
|
||||
// The hit was between v1 and v2
|
||||
hitinfo = new_hitinfo;
|
||||
|
||||
@@ -186,12 +186,12 @@ public:
|
||||
model_format_t getModelFormat() const;
|
||||
|
||||
bool lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo) const;
|
||||
bool rayCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo) const;
|
||||
bool rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hitinfo) const;
|
||||
|
||||
static int GetLODCoverage(const std::string &name);
|
||||
private:
|
||||
bool rayCast(const KRVector3 &line_v0, const KRVector3 &line_v1, int tri_index0, int tri_index1, int tri_index2, KRHitInfo &hitinfo) const;
|
||||
static bool rayCast(const KRVector3 &line_v0, const KRVector3 &line_v1, const KRVector3 &tri_v0, const KRVector3 &tri_v1, const KRVector3 &tri_v2, const KRVector3 &tri_n0, const KRVector3 &tri_n1, const KRVector3 &tri_n2, KRHitInfo &hitinfo);
|
||||
bool rayCast(const KRVector3 &line_v0, const KRVector3 &dir, int tri_index0, int tri_index1, int tri_index2, KRHitInfo &hitinfo) const;
|
||||
static bool rayCast(const KRVector3 &line_v0, const KRVector3 &dir, const KRVector3 &tri_v0, const KRVector3 &tri_v1, const KRVector3 &tri_v2, const KRVector3 &tri_n0, const KRVector3 &tri_n1, const KRVector3 &tri_n2, KRHitInfo &hitinfo);
|
||||
|
||||
int m_lodCoverage; // This LOD level is activated when the bounding box of the model will cover less than this percent of the screen (100 = highest detail model)
|
||||
vector<KRMaterial *> m_materials;
|
||||
|
||||
@@ -110,17 +110,17 @@ bool KROctree::lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hit
|
||||
return hit_found;
|
||||
}
|
||||
|
||||
bool KROctree::rayCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo)
|
||||
bool KROctree::rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hitinfo)
|
||||
{
|
||||
bool hit_found = false;
|
||||
for(std::set<KRNode *>::iterator outer_nodes_itr=m_outerSceneNodes.begin(); outer_nodes_itr != m_outerSceneNodes.end(); outer_nodes_itr++) {
|
||||
KRCollider *collider = dynamic_cast<KRCollider *>(*outer_nodes_itr);
|
||||
if(collider) {
|
||||
if(collider->rayCast(v0, v1, hitinfo)) hit_found = true;
|
||||
if(collider->rayCast(v0, dir, hitinfo)) hit_found = true;
|
||||
}
|
||||
}
|
||||
if(m_pRootNode) {
|
||||
if(m_pRootNode->lineCast(v0, v1, hitinfo)) hit_found = true;
|
||||
if(m_pRootNode->lineCast(v0, dir, hitinfo)) hit_found = true;
|
||||
}
|
||||
return hit_found;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public:
|
||||
std::set<KRNode *> &getOuterSceneNodes();
|
||||
|
||||
bool lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo);
|
||||
bool rayCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo);
|
||||
bool rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hitinfo);
|
||||
|
||||
private:
|
||||
KROctreeNode *m_pRootNode;
|
||||
|
||||
@@ -205,24 +205,24 @@ bool KROctreeNode::lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo
|
||||
return hit_found;
|
||||
}
|
||||
|
||||
bool KROctreeNode::rayCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo)
|
||||
bool KROctreeNode::rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hitinfo)
|
||||
{
|
||||
bool hit_found = false;
|
||||
if(hitinfo.didHit()) {
|
||||
// Optimization: If we already have a hit, only search for hits that are closer
|
||||
hit_found = lineCast(v0, hitinfo.getPosition(), hitinfo); // Note: This is purposefully lineCast as opposed to RayCast
|
||||
} else {
|
||||
if(getBounds().intersectsRay(v0, v1)) {
|
||||
if(getBounds().intersectsRay(v0, dir)) {
|
||||
for(std::set<KRNode *>::iterator nodes_itr=m_sceneNodes.begin(); nodes_itr != m_sceneNodes.end(); nodes_itr++) {
|
||||
KRCollider *collider = dynamic_cast<KRCollider *>(*nodes_itr);
|
||||
if(collider) {
|
||||
if(collider->rayCast(v0, v1, hitinfo)) hit_found = true;
|
||||
if(collider->rayCast(v0, dir, hitinfo)) hit_found = true;
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i<8; i++) {
|
||||
if(m_children[i]) {
|
||||
if(m_children[i]->rayCast(v0, v1, hitinfo)) {
|
||||
if(m_children[i]->rayCast(v0, dir, hitinfo)) {
|
||||
hit_found = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
bool m_activeQuery;
|
||||
|
||||
bool lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo);
|
||||
bool rayCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo);
|
||||
bool rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hitinfo);
|
||||
private:
|
||||
|
||||
KRAABB m_bounds;
|
||||
|
||||
@@ -447,7 +447,7 @@ bool KRScene::lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hiti
|
||||
return m_nodeTree.lineCast(v0, v1, hitinfo);
|
||||
}
|
||||
|
||||
bool KRScene::rayCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo)
|
||||
bool KRScene::rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hitinfo)
|
||||
{
|
||||
return m_nodeTree.rayCast(v0, v1, hitinfo);
|
||||
return m_nodeTree.rayCast(v0, dir, hitinfo);
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ public:
|
||||
KRLight *getFirstLight();
|
||||
|
||||
bool lineCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo);
|
||||
bool rayCast(const KRVector3 &v0, const KRVector3 &v1, KRHitInfo &hitinfo);
|
||||
bool rayCast(const KRVector3 &v0, const KRVector3 &dir, KRHitInfo &hitinfo);
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
|
||||
Reference in New Issue
Block a user