Completed implementation of Model LOD system
--HG-- extra : convert_revision : svn%3A7752d6cf-9f14-4ad2-affc-04f1e67b81a5/trunk%40117
This commit is contained in:
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "KRAABB.h"
|
#include "KRAABB.h"
|
||||||
#include "KRMat4.h"
|
#include "KRMat4.h"
|
||||||
|
#include "KRVector2.h"
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
|
|
||||||
KRAABB::KRAABB(const KRVector3 &minPoint, const KRVector3 &maxPoint)
|
KRAABB::KRAABB(const KRVector3 &minPoint, const KRVector3 &maxPoint)
|
||||||
@@ -182,3 +183,31 @@ bool KRAABB::visible(const KRMat4 &matViewProjection) const
|
|||||||
//is_visible = true;
|
//is_visible = true;
|
||||||
return is_visible;
|
return is_visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
float KRAABB::coverage(const KRMat4 &matMVP, const KRVector2 viewportSize) const
|
||||||
|
{
|
||||||
|
if(!visible(matMVP)) {
|
||||||
|
return 0.0f; // Culled out by view frustrum
|
||||||
|
} else {
|
||||||
|
KRVector2 screen_min;
|
||||||
|
KRVector2 screen_max;
|
||||||
|
// Loop through all corners and transform them to screen space
|
||||||
|
for(int i=0; i<8; i++) {
|
||||||
|
KRVector3 screen_pos = KRMat4::Dot(matMVP, KRVector3(i & 1 ? min.x : max.x, i & 2 ? min.y : max.y, i & 4 ? min.z :max.z));
|
||||||
|
if(i==0) {
|
||||||
|
screen_min.x = screen_pos.x;
|
||||||
|
screen_min.y = screen_pos.y;
|
||||||
|
screen_max.x = screen_pos.x;
|
||||||
|
screen_max.y = screen_pos.y;
|
||||||
|
} else {
|
||||||
|
if(screen_pos.x < screen_min.x) screen_min.x = screen_pos.x;
|
||||||
|
if(screen_pos.y < screen_min.y) screen_min.y = screen_pos.y;
|
||||||
|
if(screen_pos.x > screen_max.x) screen_max.x = screen_pos.x;
|
||||||
|
if(screen_pos.y > screen_max.y) screen_max.y = screen_pos.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (screen_max.x - screen_min.x) / viewportSize.x * (screen_max.y - screen_min.y) / viewportSize.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
#include "KRVector3.h"
|
#include "KRVector3.h"
|
||||||
|
|
||||||
class KRMat4;
|
class KRMat4;
|
||||||
|
class KRVector2;
|
||||||
|
|
||||||
class KRAABB {
|
class KRAABB {
|
||||||
public:
|
public:
|
||||||
@@ -39,6 +40,7 @@ public:
|
|||||||
KRVector3 max;
|
KRVector3 max;
|
||||||
|
|
||||||
static KRAABB Infinite();
|
static KRAABB Infinite();
|
||||||
|
float coverage(const KRMat4 &matMVP, const KRVector2 viewportSize) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -35,11 +35,11 @@
|
|||||||
#import "KRModel.h"
|
#import "KRModel.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
KRInstance::KRInstance(KRScene &scene, std::string instance_name, std::string model_name, std::string light_map) : KRNode(scene, instance_name) {
|
KRInstance::KRInstance(KRScene &scene, std::string instance_name, std::string model_name, std::string light_map, float lod_min_coverage) : KRNode(scene, instance_name) {
|
||||||
m_lightMap = light_map;
|
m_lightMap = light_map;
|
||||||
m_pLightMap = NULL;
|
m_pLightMap = NULL;
|
||||||
m_pModel = NULL;
|
|
||||||
m_model_name = model_name;
|
m_model_name = model_name;
|
||||||
|
m_min_lod_coverage = lod_min_coverage;
|
||||||
}
|
}
|
||||||
|
|
||||||
KRInstance::~KRInstance() {
|
KRInstance::~KRInstance() {
|
||||||
@@ -55,6 +55,7 @@ tinyxml2::XMLElement *KRInstance::saveXML( tinyxml2::XMLNode *parent)
|
|||||||
tinyxml2::XMLElement *e = KRNode::saveXML(parent);
|
tinyxml2::XMLElement *e = KRNode::saveXML(parent);
|
||||||
e->SetAttribute("mesh_name", m_model_name.c_str());
|
e->SetAttribute("mesh_name", m_model_name.c_str());
|
||||||
e->SetAttribute("light_map", m_lightMap.c_str());
|
e->SetAttribute("light_map", m_lightMap.c_str());
|
||||||
|
e->SetAttribute("lod_min_coverage", m_min_lod_coverage);
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,9 +66,9 @@ KRMat4 &KRInstance::getModelMatrix() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void KRInstance::loadModel() {
|
void KRInstance::loadModel() {
|
||||||
if(m_pModel == NULL) {
|
if(m_models.size() == 0) {
|
||||||
m_pModel = m_pContext->getModelManager()->getModel(m_model_name.c_str());
|
m_models = m_pContext->getModelManager()->getModel(m_model_name.c_str()); // The model manager returns the LOD levels in sorted order, with the highest detail first
|
||||||
if(m_pModel != NULL) {
|
if(m_models.size() > 0) {
|
||||||
getScene().notify_sceneGraphModify(this);
|
getScene().notify_sceneGraphModify(this);
|
||||||
}
|
}
|
||||||
// if(m_pModel == NULL) {
|
// if(m_pModel == NULL) {
|
||||||
@@ -89,13 +90,27 @@ void KRInstance::render(KRCamera *pCamera, KRContext *pContext, KRMat4 &viewMatr
|
|||||||
|
|
||||||
loadModel();
|
loadModel();
|
||||||
|
|
||||||
|
if(m_models.size() > 0) {
|
||||||
KRMat4 projectionMatrix;
|
KRMat4 projectionMatrix;
|
||||||
if(renderPass != KRNode::RENDER_PASS_SHADOWMAP) {
|
if(renderPass != KRNode::RENDER_PASS_SHADOWMAP) {
|
||||||
projectionMatrix = pCamera->getProjectionMatrix();
|
projectionMatrix = pCamera->getProjectionMatrix();
|
||||||
}
|
}
|
||||||
|
KRMat4 matVP = viewMatrix * projectionMatrix;
|
||||||
|
float lod_coverage = getBounds().coverage(matVP, pCamera->getViewportSize()); // This also checks the view frustrum culling
|
||||||
|
if(lod_coverage > m_min_lod_coverage) {
|
||||||
|
|
||||||
if(m_pModel != NULL) {
|
// ---===--- Select the best LOD model based on screen coverage ---===---
|
||||||
if(getBounds().visible(viewMatrix * projectionMatrix)) {
|
std::vector<KRModel *>::iterator itr=m_models.begin();
|
||||||
|
KRModel *pModel = *itr++;
|
||||||
|
|
||||||
|
while(itr != m_models.end()) {
|
||||||
|
KRModel *pLODModel = *itr++;
|
||||||
|
if((float)pLODModel->getLODCoverage() / 100.0f > lod_coverage) {
|
||||||
|
pModel = pLODModel;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(m_pLightMap == NULL && m_lightMap.size()) {
|
if(m_pLightMap == NULL && m_lightMap.size()) {
|
||||||
m_pLightMap = pContext->getTextureManager()->getTexture(m_lightMap.c_str());
|
m_pLightMap = pContext->getTextureManager()->getTexture(m_lightMap.c_str());
|
||||||
@@ -121,7 +136,7 @@ void KRInstance::render(KRCamera *pCamera, KRContext *pContext, KRMat4 &viewMatr
|
|||||||
KRVector3 cameraPosObject = KRMat4::Dot(inverseModelMatrix, cameraPosition);
|
KRVector3 cameraPosObject = KRMat4::Dot(inverseModelMatrix, cameraPosition);
|
||||||
KRVector3 lightDirObject = KRMat4::Dot(inverseModelMatrix, lightDirection);
|
KRVector3 lightDirObject = KRMat4::Dot(inverseModelMatrix, lightDirection);
|
||||||
|
|
||||||
m_pModel->render(pCamera, pContext, viewMatrix, matModelToView, mvpmatrix, lightDirection, pShadowMatrices, shadowDepthTextures, cShadowBuffers, m_pLightMap, renderPass);
|
pModel->render(pCamera, pContext, viewMatrix, matModelToView, mvpmatrix, lightDirection, pShadowMatrices, shadowDepthTextures, cShadowBuffers, m_pLightMap, renderPass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,8 +145,8 @@ void KRInstance::render(KRCamera *pCamera, KRContext *pContext, KRMat4 &viewMatr
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool KRInstance::hasTransparency() {
|
bool KRInstance::hasTransparency() {
|
||||||
if(m_pModel) {
|
if(m_models.size() > 0) {
|
||||||
return m_pModel->hasTransparency();
|
return m_models[0]->hasTransparency();
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -142,9 +157,9 @@ KRAABB KRInstance::getBounds() {
|
|||||||
loadModel();
|
loadModel();
|
||||||
|
|
||||||
KRVector3 meshMin, meshMax;
|
KRVector3 meshMin, meshMax;
|
||||||
if(m_pModel) {
|
if(m_models.size() > 0) {
|
||||||
meshMin = m_pModel->getMinPoint();
|
meshMin = m_models[0]->getMinPoint();
|
||||||
meshMax = m_pModel->getMaxPoint();
|
meshMax = m_models[0]->getMaxPoint();
|
||||||
} else {
|
} else {
|
||||||
meshMin = -KRVector3::Max();
|
meshMin = -KRVector3::Max();
|
||||||
meshMax = KRVector3::Max();
|
meshMax = KRVector3::Max();
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
class KRInstance : public KRNode {
|
class KRInstance : public KRNode {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
KRInstance(KRScene &scene, std::string instance_name, std::string model_name, std::string light_map);
|
KRInstance(KRScene &scene, std::string instance_name, std::string model_name, std::string light_map, float lod_min_coverage);
|
||||||
virtual ~KRInstance();
|
virtual ~KRInstance();
|
||||||
|
|
||||||
virtual std::string getElementName();
|
virtual std::string getElementName();
|
||||||
@@ -70,12 +70,14 @@ public:
|
|||||||
void calcModelMatrix();
|
void calcModelMatrix();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KRModel *m_pModel;
|
std::vector<KRModel *> m_models;
|
||||||
KRMat4 m_modelMatrix;
|
KRMat4 m_modelMatrix;
|
||||||
KRTexture *m_pLightMap;
|
KRTexture *m_pLightMap;
|
||||||
std::string m_lightMap;
|
std::string m_lightMap;
|
||||||
std::string m_model_name;
|
std::string m_model_name;
|
||||||
|
|
||||||
|
|
||||||
|
float m_min_lod_coverage;
|
||||||
void loadModel();
|
void loadModel();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,23 @@ KRModel::KRModel(KRContext &context, std::string name) : KRResource(context, nam
|
|||||||
m_materials.clear();
|
m_materials.clear();
|
||||||
m_uniqueMaterials.clear();
|
m_uniqueMaterials.clear();
|
||||||
m_pData = new KRDataBlock();
|
m_pData = new KRDataBlock();
|
||||||
|
m_lodCoverage = 100; // Default to being the full detail mesh; not an LOD level
|
||||||
|
m_lodBaseName = name;
|
||||||
|
|
||||||
|
size_t last_underscore_pos = name.find_last_of('_');
|
||||||
|
if(last_underscore_pos != std::string::npos) {
|
||||||
|
// Found an underscore
|
||||||
|
std::string suffix = name.substr(last_underscore_pos + 1);
|
||||||
|
if(suffix.find_first_of("lod") == 0) {
|
||||||
|
std::string lod_level_string = suffix.substr(3);
|
||||||
|
char *end = NULL;
|
||||||
|
int c = (int)strtol(suffix.c_str(), &end, 10);
|
||||||
|
if(m_lodCoverage < 0 || m_lodCoverage > 100 || *end != '\0') {
|
||||||
|
m_lodCoverage = c;
|
||||||
|
m_lodBaseName = name.substr(0, last_underscore_pos - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KRModel::KRModel(KRContext &context, std::string name, KRDataBlock *data) : KRResource(context, name) {
|
KRModel::KRModel(KRContext &context, std::string name, KRDataBlock *data) : KRResource(context, name) {
|
||||||
@@ -59,6 +76,7 @@ KRModel::KRModel(KRContext &context, std::string name, KRDataBlock *data) : KRRe
|
|||||||
m_materials.clear();
|
m_materials.clear();
|
||||||
m_uniqueMaterials.clear();
|
m_uniqueMaterials.clear();
|
||||||
m_pData = new KRDataBlock();
|
m_pData = new KRDataBlock();
|
||||||
|
m_lodCoverage = 100;
|
||||||
loadPack(data);
|
loadPack(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,3 +452,17 @@ void KRModel::clearBuffers() {
|
|||||||
m_submeshes.clear();
|
m_submeshes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int KRModel::getLODCoverage() const {
|
||||||
|
return m_lodCoverage;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string KRModel::getLODBaseName() const {
|
||||||
|
return m_lodBaseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Predicate used with std::sort to sort by highest detail model first, decending to lowest detail LOD model
|
||||||
|
bool KRModel::lod_sort_predicate(const KRModel *m1, const KRModel *m2)
|
||||||
|
{
|
||||||
|
return m1->m_lodCoverage > m2->m_lodCoverage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,8 @@ public:
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
std::string m_lodBaseName;
|
||||||
|
|
||||||
virtual std::string getExtension();
|
virtual std::string getExtension();
|
||||||
virtual bool save(const std::string& path);
|
virtual bool save(const std::string& path);
|
||||||
|
|
||||||
@@ -119,8 +121,14 @@ public:
|
|||||||
char szName[256];
|
char szName[256];
|
||||||
} pack_material;
|
} pack_material;
|
||||||
|
|
||||||
|
int getLODCoverage() const;
|
||||||
|
std::string getLODBaseName() const;
|
||||||
|
|
||||||
|
|
||||||
|
static bool lod_sort_predicate(const KRModel *m1, const KRModel *m2);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
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;
|
vector<KRMaterial *> m_materials;
|
||||||
set<KRMaterial *> m_uniqueMaterials;
|
set<KRMaterial *> m_uniqueMaterials;
|
||||||
|
|
||||||
|
|||||||
@@ -46,26 +46,45 @@ KRModelManager::KRModelManager(KRContext &context) : KRContextObject(context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
KRModelManager::~KRModelManager() {
|
KRModelManager::~KRModelManager() {
|
||||||
for(map<std::string, KRModel *>::iterator itr = m_models.begin(); itr != m_models.end(); ++itr){
|
for(std::multimap<std::string, KRModel *>::iterator itr = m_models.begin(); itr != m_models.end(); ++itr){
|
||||||
delete (*itr).second;
|
delete (*itr).second;
|
||||||
}
|
}
|
||||||
m_models.empty();
|
m_models.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
KRModel *KRModelManager::loadModel(const char *szName, KRDataBlock *pData) {
|
KRModel *KRModelManager::loadModel(const char *szName, KRDataBlock *pData) {
|
||||||
KRModel *pModel = new KRModel(*m_pContext, szName, pData);
|
|
||||||
m_models[szName] = pModel;
|
std::string lowerName = szName;
|
||||||
|
std::transform(lowerName.begin(), lowerName.end(),
|
||||||
|
lowerName.begin(), ::tolower);
|
||||||
|
|
||||||
|
|
||||||
|
KRModel *pModel = new KRModel(*m_pContext, lowerName, pData);
|
||||||
|
m_models.insert(std::pair<std::string, KRModel *>(pModel->getName(), pModel));
|
||||||
|
|
||||||
return pModel;
|
return pModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
KRModel *KRModelManager::getModel(const char *szName) {
|
std::vector<KRModel *> KRModelManager::getModel(const char *szName) {
|
||||||
std::map<std::string, KRModel *>::iterator itr_match = m_models.find(szName);
|
std::string lowerName = szName;
|
||||||
if(itr_match == m_models.end()) {
|
std::transform(lowerName.begin(), lowerName.end(),
|
||||||
fprintf(stderr, "ERROR: Model not found: %s\n", szName);
|
lowerName.begin(), ::tolower);
|
||||||
return NULL;
|
|
||||||
} else {
|
|
||||||
return itr_match->second;
|
std::vector<KRModel *> matching_models;
|
||||||
|
|
||||||
|
std::pair<std::multimap<std::string, KRModel *>::iterator, std::multimap<std::string, KRModel *>::iterator> range = m_models.equal_range(lowerName);
|
||||||
|
for(std::multimap<std::string, KRModel *>::iterator itr_match = range.first; itr_match != range.second; itr_match++) {
|
||||||
|
matching_models.push_back(itr_match->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::sort(matching_models.begin(), matching_models.end(), KRModel::lod_sort_predicate);
|
||||||
|
|
||||||
|
if(matching_models.size() == 0) {
|
||||||
|
fprintf(stderr, "ERROR: Model not found: %s\n", lowerName.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return matching_models;
|
||||||
}
|
}
|
||||||
|
|
||||||
KRModel *KRModelManager::getFirstModel() {
|
KRModel *KRModelManager::getFirstModel() {
|
||||||
@@ -73,7 +92,7 @@ KRModel *KRModelManager::getFirstModel() {
|
|||||||
return (*model_itr).second;
|
return (*model_itr).second;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::map<std::string, KRModel *> KRModelManager::getModels() {
|
std::multimap<std::string, KRModel *> KRModelManager::getModels() {
|
||||||
return m_models;
|
return m_models;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,11 +54,11 @@ public:
|
|||||||
void rotateBuffers(bool new_frame);
|
void rotateBuffers(bool new_frame);
|
||||||
|
|
||||||
KRModel *loadModel(const char *szName, KRDataBlock *pData);
|
KRModel *loadModel(const char *szName, KRDataBlock *pData);
|
||||||
KRModel *getModel(const char *szName);
|
std::vector<KRModel *> getModel(const char *szName);
|
||||||
KRModel *getFirstModel();
|
KRModel *getFirstModel();
|
||||||
|
|
||||||
std::vector<std::string> getModelNames();
|
std::vector<std::string> getModelNames();
|
||||||
std::map<std::string, KRModel *> getModels();
|
std::multimap<std::string, KRModel *> getModels();
|
||||||
|
|
||||||
|
|
||||||
void bindVBO(GLvoid *data, GLsizeiptr size, bool enable_vertex, bool enable_normal, bool enable_tangent, bool enable_uva, bool enable_uvb);
|
void bindVBO(GLvoid *data, GLsizeiptr size, bool enable_vertex, bool enable_normal, bool enable_tangent, bool enable_uva, bool enable_uvb);
|
||||||
@@ -68,7 +68,7 @@ public:
|
|||||||
void configureAttribs(bool enable_vertex, bool enable_normal, bool enable_tangent, bool enable_uva, bool enable_uvb);
|
void configureAttribs(bool enable_vertex, bool enable_normal, bool enable_tangent, bool enable_uva, bool enable_uvb);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<std::string, KRModel *> m_models;
|
std::multimap<std::string, KRModel *> m_models; // Multiple models with the same name/key may be inserted, representing multiple LOD levels of the model
|
||||||
|
|
||||||
typedef struct vbo_info {
|
typedef struct vbo_info {
|
||||||
GLuint handle;
|
GLuint handle;
|
||||||
|
|||||||
@@ -138,7 +138,11 @@ KRNode *KRNode::LoadXML(KRScene &scene, tinyxml2::XMLElement *e) {
|
|||||||
} else if(strcmp(szElementName, "spot_light") == 0) {
|
} else if(strcmp(szElementName, "spot_light") == 0) {
|
||||||
new_node = new KRSpotLight(scene, szName);
|
new_node = new KRSpotLight(scene, szName);
|
||||||
} else if(strcmp(szElementName, "mesh") == 0) {
|
} else if(strcmp(szElementName, "mesh") == 0) {
|
||||||
new_node = new KRInstance(scene, szName, szName, e->Attribute("light_map"));
|
float lod_min_coverage = 0.0f;
|
||||||
|
if(e->QueryFloatAttribute("lod_min_coverage", &lod_min_coverage) != tinyxml2::XML_SUCCESS) {
|
||||||
|
lod_min_coverage = 0.0f; //1.0f / 1024.0f / 768.0f; // FINDME - HACK - Need to dynamically select the absolute minimum based on the render buffer size
|
||||||
|
}
|
||||||
|
new_node = new KRInstance(scene, szName, szName, e->Attribute("light_map"), lod_min_coverage);
|
||||||
} else if(strcmp(szElementName, "sky_box") == 0) {
|
} else if(strcmp(szElementName, "sky_box") == 0) {
|
||||||
new_node = new KRSkyBox(scene, szName);
|
new_node = new KRSkyBox(scene, szName);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,7 +168,14 @@ void KRScene::render(int childOrder[], KROctreeNode *pOctreeNode, std::set<KRAAB
|
|||||||
if(renderPass != KRNode::RENDER_PASS_SHADOWMAP) {
|
if(renderPass != KRNode::RENDER_PASS_SHADOWMAP) {
|
||||||
projectionMatrix = pCamera->getProjectionMatrix();
|
projectionMatrix = pCamera->getProjectionMatrix();
|
||||||
}
|
}
|
||||||
if(pOctreeNode->getBounds().visible(viewMatrix * projectionMatrix)) { // Only recurse deeper if within the view frustrum
|
KRMat4 matVP = viewMatrix * projectionMatrix;
|
||||||
|
|
||||||
|
float min_coverage = 0.0f; // 1.0f / 1024.0f / 768.0f; // FINDME - HACK - Need to dynamically select the absolute minimum based on the render buffer size
|
||||||
|
|
||||||
|
float lod_coverage = pOctreeNode->getBounds().coverage(matVP, pCamera->getViewportSize()); // This also checks the view frustrum culling
|
||||||
|
if(lod_coverage > min_coverage) {
|
||||||
|
|
||||||
|
// if(pOctreeNode->getBounds().visible(viewMatrix * projectionMatrix)) { // Only recurse deeper if within the view frustrum
|
||||||
|
|
||||||
// ----====---- Rendering and occlusion test pass ----====----
|
// ----====---- Rendering and occlusion test pass ----====----
|
||||||
bool bVisible = false;
|
bool bVisible = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user