diff --git a/KREngine/kraken/KRAABB.cpp b/KREngine/kraken/KRAABB.cpp index e28aced..90e3797 100644 --- a/KREngine/kraken/KRAABB.cpp +++ b/KREngine/kraken/KRAABB.cpp @@ -11,6 +11,12 @@ #include "KRVector2.h" #include "assert.h" +KRAABB::KRAABB() +{ + min = KRVector3::Min(); + max = KRVector3::Max(); +} + KRAABB::KRAABB(const KRVector3 &minPoint, const KRVector3 &maxPoint) { min = minPoint; @@ -144,6 +150,11 @@ KRAABB KRAABB::Infinite() return KRAABB(KRVector3::Min(), KRVector3::Max()); } +KRAABB KRAABB::Zero() +{ + return KRAABB(KRVector3::Zero(), KRVector3::Zero()); +} + bool KRAABB::visible(const KRMat4 &matViewProjection) const { // test if bounding box would be within the visible range of the clip space transformed by matViewProjection @@ -277,6 +288,7 @@ 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; } @@ -289,4 +301,9 @@ void KRAABB::encapsulate(const KRAABB & b) if(b.max.x > max.x) max.x = b.max.x; if(b.max.y > max.y) max.y = b.max.y; if(b.max.z > max.z) max.z = b.max.z; -} \ No newline at end of file +} + +KRVector3 KRAABB::nearestPoint(const KRVector3 & v) const +{ + return KRVector3(KRCLAMP(v.x, min.x, max.x), KRCLAMP(v.y, min.y, max.y), KRCLAMP(v.z, min.z, max.z)); +} diff --git a/KREngine/kraken/KRAABB.h b/KREngine/kraken/KRAABB.h index 802dd6e..1505b59 100644 --- a/KREngine/kraken/KRAABB.h +++ b/KREngine/kraken/KRAABB.h @@ -20,6 +20,7 @@ class KRAABB { public: KRAABB(const KRVector3 &minPoint, const KRVector3 &maxPoint); KRAABB(const KRVector3 &corner1, const KRVector3 &corner2, const KRMat4 &modelMatrix); + KRAABB(); ~KRAABB(); void scale(const KRVector3 &s); @@ -48,8 +49,10 @@ public: KRVector3 max; static KRAABB Infinite(); + static KRAABB Zero(); float coverage(const KRMat4 &matVP, const KRVector2 viewportSize) const; float longest_radius() const; + KRVector3 nearestPoint(const KRVector3 & v) const; }; diff --git a/KREngine/kraken/KRDirectionalLight.cpp b/KREngine/kraken/KRDirectionalLight.cpp index bd35f07..960a131 100644 --- a/KREngine/kraken/KRDirectionalLight.cpp +++ b/KREngine/kraken/KRDirectionalLight.cpp @@ -138,3 +138,8 @@ void KRDirectionalLight::render(KRCamera *pCamera, std::vector &light } } } + +KRAABB KRDirectionalLight::getBounds() +{ + return KRAABB::Infinite(); +} diff --git a/KREngine/kraken/KRDirectionalLight.h b/KREngine/kraken/KRDirectionalLight.h index 37dee4f..455cc1d 100644 --- a/KREngine/kraken/KRDirectionalLight.h +++ b/KREngine/kraken/KRDirectionalLight.h @@ -24,6 +24,7 @@ public: KRVector3 getWorldLightDirection(); virtual void render(KRCamera *pCamera, std::vector &lights, const KRViewport &viewport, KRNode::RenderPass renderPass); + virtual KRAABB getBounds(); protected: diff --git a/KREngine/kraken/KRLODGroup.cpp b/KREngine/kraken/KRLODGroup.cpp index 9c04b17..c388f5c 100644 --- a/KREngine/kraken/KRLODGroup.cpp +++ b/KREngine/kraken/KRLODGroup.cpp @@ -13,7 +13,8 @@ KRLODGroup::KRLODGroup(KRScene &scene, std::string name) : KRNode(scene, name) { m_min_distance = 0.0f; m_max_distance = 0.0f; - m_referencePoint = KRVector3::Zero(); + m_reference = KRAABB(KRVector3::Zero(), KRVector3::Zero()); + m_use_world_units = true; } KRLODGroup::~KRLODGroup() @@ -30,9 +31,16 @@ tinyxml2::XMLElement *KRLODGroup::saveXML( tinyxml2::XMLNode *parent) e->SetAttribute("min_distance", m_min_distance); e->SetAttribute("max_distance", m_max_distance); - e->SetAttribute("reference_x", m_referencePoint.x); - e->SetAttribute("reference_y", m_referencePoint.y); - e->SetAttribute("reference_z", m_referencePoint.z); + e->SetAttribute("reference_min_x", m_reference.min.x); + e->SetAttribute("reference_min_y", m_reference.min.y); + e->SetAttribute("reference_min_z", m_reference.min.z); + + + e->SetAttribute("reference_max_x", m_reference.max.x); + e->SetAttribute("reference_max_y", m_reference.max.y); + e->SetAttribute("reference_max_z", m_reference.max.z); + + e->SetAttribute("use_world_units", m_use_world_units ? "true" : "false"); return e; } @@ -52,32 +60,45 @@ void KRLODGroup::loadXML(tinyxml2::XMLElement *e) float x=0.0f, y=0.0f, z=0.0f; - if(e->QueryFloatAttribute("reference_x", &x) != tinyxml2::XML_SUCCESS) { + if(e->QueryFloatAttribute("reference_min_x", &x) != tinyxml2::XML_SUCCESS) { x = 0.0f; } - if(e->QueryFloatAttribute("reference_y", &y) != tinyxml2::XML_SUCCESS) { + if(e->QueryFloatAttribute("reference_min_y", &y) != tinyxml2::XML_SUCCESS) { y = 0.0f; } - if(e->QueryFloatAttribute("reference_z", &z) != tinyxml2::XML_SUCCESS) { + if(e->QueryFloatAttribute("reference_min_z", &z) != tinyxml2::XML_SUCCESS) { z = 0.0f; } - m_referencePoint = KRVector3(x,y,z); + + m_reference.min = KRVector3(x,y,z); + + x=0.0f; y=0.0f; z=0.0f; + if(e->QueryFloatAttribute("reference_max_x", &x) != tinyxml2::XML_SUCCESS) { + x = 0.0f; + } + if(e->QueryFloatAttribute("reference_max_y", &y) != tinyxml2::XML_SUCCESS) { + y = 0.0f; + } + if(e->QueryFloatAttribute("reference_max_z", &z) != tinyxml2::XML_SUCCESS) { + z = 0.0f; + } + m_reference.max = KRVector3(x,y,z); + + m_use_world_units = true; + if(e->QueryBoolAttribute("use_world_units", &m_use_world_units) != tinyxml2::XML_SUCCESS) { + m_use_world_units = true; + } } -const KRVector3 KRLODGroup::getReferencePoint() +const KRAABB &KRLODGroup::getReference() const { - return m_referencePoint; + return m_reference; } -void KRLODGroup::setReferencePoint(const KRVector3 &referencePoint) +void KRLODGroup::setReference(const KRAABB &reference) { - m_referencePoint = referencePoint; -} - -const KRVector3 KRLODGroup::getWorldReferencePoint() -{ - return localToWorld(m_referencePoint); + m_reference = reference; } bool KRLODGroup::getLODVisibility(const KRViewport &viewport) @@ -88,8 +109,20 @@ bool KRLODGroup::getLODVisibility(const KRViewport &viewport) // return (m_max_distance == 0); // FINDME, HACK - Test code to enable only the lowest LOD group float lod_bias = viewport.getLODBias(); lod_bias = pow(2.0f, -lod_bias); - // Compare square distances as sqrt is expensive - float sqr_distance = (viewport.getCameraPosition() - getWorldReferencePoint()).sqrMagnitude() * (lod_bias * lod_bias); + + float sqr_distance; // Compare using squared distances as sqrt is expensive + + KRVector3 world_camera_position = viewport.getCameraPosition(); + KRVector3 local_camera_position = worldToLocal(world_camera_position); + KRVector3 local_reference_point = m_reference.nearestPoint(local_camera_position); + + if(m_use_world_units) { + KRVector3 world_reference_point = localToWorld(local_reference_point); + sqr_distance = (world_camera_position - world_reference_point).sqrMagnitude() * (lod_bias * lod_bias); + } else { + sqr_distance = (local_camera_position - local_reference_point).sqrMagnitude() * (lod_bias * lod_bias); + } + float sqr_min_distance = m_min_distance * m_min_distance; float sqr_max_distance = m_max_distance * m_max_distance; return ((sqr_distance >= sqr_min_distance || m_min_distance == 0) && (sqr_distance < sqr_max_distance || m_max_distance == 0)); @@ -132,3 +165,12 @@ void KRLODGroup::setMaxDistance(float max_distance) m_max_distance = max_distance; } +void KRLODGroup::setUseWorldUnits(bool use_world_units) +{ + m_use_world_units = use_world_units; +} + +bool KRLODGroup::getUseWorldUnits() const +{ + return m_use_world_units; +} diff --git a/KREngine/kraken/KRLODGroup.h b/KREngine/kraken/KRLODGroup.h index 815daa8..a35daea 100644 --- a/KREngine/kraken/KRLODGroup.h +++ b/KREngine/kraken/KRLODGroup.h @@ -28,16 +28,17 @@ public: void setMinDistance(float min_distance); void setMaxDistance(float max_distance); - const KRVector3 getReferencePoint(); - void setReferencePoint(const KRVector3 &referencePoint); - - const KRVector3 getWorldReferencePoint(); + const KRAABB &getReference() const; + void setReference(const KRAABB &reference); + void setUseWorldUnits(bool use_world_units); + bool getUseWorldUnits() const; private: bool getLODVisibility(const KRViewport &viewport); float m_min_distance; float m_max_distance; - KRVector3 m_referencePoint; // Point of reference, used for distance calculation. Usually set to the bounding box center + KRAABB m_reference; // Point of reference, used for distance calculation. Usually set to the bounding box center + bool m_use_world_units; }; diff --git a/KREngine/kraken/KRNode.cpp b/KREngine/kraken/KRNode.cpp index 7c83aee..845330b 100644 --- a/KREngine/kraken/KRNode.cpp +++ b/KREngine/kraken/KRNode.cpp @@ -278,16 +278,18 @@ KRScene &KRNode::getScene() { } KRAABB KRNode::getBounds() { - KRAABB bounds = KRAABB::Infinite(); + KRAABB bounds = KRAABB::Zero(); bool first_child = true; for(std::vector::iterator itr=m_childNodes.begin(); itr < m_childNodes.end(); ++itr) { KRNode *child = (*itr); - if(first_child) { - first_child = false; - bounds = child->getBounds(); - } else { - bounds.encapsulate(child->getBounds()); + if(child->getBounds() != KRAABB::Zero()) { + if(first_child) { + first_child = false; + bounds = child->getBounds(); + } else { + bounds.encapsulate(child->getBounds()); + } } } diff --git a/KREngine/kraken/KROctree.cpp b/KREngine/kraken/KROctree.cpp index 00e0849..bb866b6 100644 --- a/KREngine/kraken/KROctree.cpp +++ b/KREngine/kraken/KROctree.cpp @@ -26,7 +26,9 @@ KROctree::~KROctree() void KROctree::add(KRNode *pNode) { KRAABB nodeBounds = pNode->getBounds(); - if(nodeBounds == KRAABB::Infinite()) { + if(nodeBounds == KRAABB::Zero()) { + // This item is not visible, don't add it to the octree or outer scene nodes + } else if(nodeBounds == KRAABB::Infinite()) { // This item is infinitely large; we track it separately m_outerSceneNodes.insert(pNode); } else { diff --git a/KREngine/kraken/KRResource+fbx.cpp b/KREngine/kraken/KRResource+fbx.cpp index 4c3e2cb..45c9bb1 100644 --- a/KREngine/kraken/KRResource+fbx.cpp +++ b/KREngine/kraken/KRResource+fbx.cpp @@ -738,9 +738,7 @@ void LoadNode(KFbxScene* pFbxScene, KRNode *parent_node, std::vectorGetNodeAttribute(); // FbxCast(pNode); - if(!fbx_lod_group->WorldSpace.Get()) { - printf("WARNING - LOD Groups only supported with world space distance thresholds.\n"); - } + bool use_world_space_units = fbx_lod_group->WorldSpace.Get(); float group_min_distance = 0.0f; float group_max_distance = 0.0f; if(fbx_lod_group->MinMaxDistance.Get()) { @@ -748,7 +746,7 @@ void LoadNode(KFbxScene* pFbxScene, KRNode *parent_node, std::vectorMinDistance.Get(); } - KRVector3 reference_point; + KRAABB reference_bounds; // Create a lod_group node for each fbx child node int child_count = pNode->GetChildCount(); for(int i = 0; i < child_count; i++) @@ -797,16 +795,17 @@ void LoadNode(KFbxScene* pFbxScene, KRNode *parent_node, std::vectorsetLocalRotation(node_rotation); new_node->setLocalTranslation(node_translation); new_node->setLocalScale(node_scale); + new_node->setUseWorldUnits(use_world_space_units); parent_node->addChild(new_node); LoadNode(pFbxScene, new_node, resources, pGeometryConverter, pNode->GetChild(i)); if(i == 0) { // Calculate reference point using the bounding box center from the highest quality LOD level - reference_point = new_node->getBounds().center(); + reference_bounds = new_node->getBounds(); } - new_node->setReferencePoint(new_node->worldToLocal(reference_point)); + new_node->setReference(KRAABB(reference_bounds.min, reference_bounds.max, new_node->getInverseModelMatrix())); } } else { KRNode *new_node = NULL;