mirror of
https://github.com/overte-org/overte.git
synced 2025-04-25 18:35:32 +02:00
better working version of hideOutOfView voxel support
This commit is contained in:
parent
303f4a8ce4
commit
2979a8e738
4 changed files with 359 additions and 76 deletions
|
@ -376,6 +376,13 @@ Menu::Menu() :
|
|||
QMenu* renderDebugMenu = developerMenu->addMenu("Render Debugging Tools");
|
||||
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::PipelineWarnings, Qt::CTRL | Qt::SHIFT | Qt::Key_P);
|
||||
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::SuppressShortTimings, Qt::CTRL | Qt::SHIFT | Qt::Key_S);
|
||||
|
||||
|
||||
addActionToQMenuAndActionHash(renderDebugMenu,
|
||||
MenuOption::ShowAllLocalVoxels,
|
||||
Qt::CTRL | Qt::Key_A,
|
||||
appInstance->getVoxels(),
|
||||
SLOT(showAllLocalVoxels()));
|
||||
|
||||
addActionToQMenuAndActionHash(renderDebugMenu,
|
||||
MenuOption::KillLocalVoxels,
|
||||
|
|
|
@ -198,6 +198,7 @@ namespace MenuOption {
|
|||
const QString SendVoxelColors = "Colored Voxels";
|
||||
const QString SettingsImport = "Import Settings";
|
||||
const QString SettingsExport = "Export Settings";
|
||||
const QString ShowAllLocalVoxels = "Show All Local Voxels";
|
||||
const QString ShowTrueColors = "Show TRUE Colors";
|
||||
const QString SimulateLeapHand = "Simulate Leap Hand";
|
||||
const QString SkeletonTracking = "Skeleton Tracking";
|
||||
|
|
|
@ -107,6 +107,8 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
|
|||
|
||||
_inSetupNewVoxelsForDrawing = false;
|
||||
_useFastVoxelPipeline = false;
|
||||
|
||||
_culledOnce = false;
|
||||
}
|
||||
|
||||
void VoxelSystem::voxelDeleted(VoxelNode* node) {
|
||||
|
@ -229,16 +231,21 @@ void VoxelSystem::freeBufferIndex(glBufferIndex index) {
|
|||
|
||||
// This will run through the list of _freeIndexes and reset their VBO array values to be "invisible".
|
||||
void VoxelSystem::clearFreeBufferIndexes() {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "###### clearFreeBufferIndexes()");
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "clearFreeBufferIndexes()");
|
||||
_voxelsInWriteArrays = 0; // reset our VBO
|
||||
_abandonedVBOSlots = 0;
|
||||
|
||||
// clear out freeIndexes
|
||||
pthread_mutex_lock(&_freeIndexLock);
|
||||
_freeIndexes.clear();
|
||||
{
|
||||
PerformanceWarning warn(showWarnings,"clearFreeBufferIndexes() : pthread_mutex_lock(&_freeIndexLock)");
|
||||
pthread_mutex_lock(&_freeIndexLock);
|
||||
}
|
||||
{
|
||||
PerformanceWarning warn(showWarnings,"clearFreeBufferIndexes() : _freeIndexes.clear()");
|
||||
_freeIndexes.clear();
|
||||
}
|
||||
pthread_mutex_unlock(&_freeIndexLock);
|
||||
|
||||
clearAllNodesBufferIndex();
|
||||
}
|
||||
|
||||
VoxelSystem::~VoxelSystem() {
|
||||
|
@ -745,7 +752,6 @@ void VoxelSystem::checkForCulling() {
|
|||
&& !isViewChanging()
|
||||
)
|
||||
) {
|
||||
|
||||
_lastViewCulling = start;
|
||||
|
||||
// When we call removeOutOfView() voxels, we don't actually remove the voxels from the VBOs, but we do remove
|
||||
|
@ -950,6 +956,12 @@ int VoxelSystem::forceRemoveNodeFromArrays(VoxelNode* node) {
|
|||
int VoxelSystem::updateNodeInArrays(VoxelNode* node, bool reuseIndex, bool forceDraw) {
|
||||
// If we've run out of room, then just bail...
|
||||
if (_voxelsInWriteArrays >= _maxVoxels) {
|
||||
// We need to think about what else we can do in this case. This basically means that all of our available
|
||||
// VBO slots are used up, but we're trying to render more voxels. At this point, if this happens we'll just
|
||||
// not render these Voxels. We need to think about ways to keep the entire scene intact but maybe lower quality
|
||||
// possibly shifting down to lower LOD or something. This debug message is to help identify, if/when/how this
|
||||
// state actually occurs.
|
||||
qDebug("OHHHH NOOOOOO!!!! updateNodeInArrays() BAILING (_voxelsInWriteArrays >= _maxVoxels)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1062,10 +1074,24 @@ void VoxelSystem::changeTree(VoxelTree* newTree) {
|
|||
}
|
||||
|
||||
void VoxelSystem::updateFullVBOs() {
|
||||
updateVBOSegment(0, _voxelsInReadArrays);
|
||||
bool outputWarning = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(outputWarning, "updateFullVBOs()");
|
||||
|
||||
{
|
||||
static char buffer[128] = { 0 };
|
||||
if (outputWarning) {
|
||||
sprintf(buffer, "updateFullVBOs() : updateVBOSegment(0, _voxelsInReadArrays=%lu);", _voxelsInReadArrays);
|
||||
};
|
||||
|
||||
PerformanceWarning warn(outputWarning,buffer);
|
||||
updateVBOSegment(0, _voxelsInReadArrays);
|
||||
}
|
||||
|
||||
// consider the _readVoxelDirtyArray[] clean!
|
||||
memset(_readVoxelDirtyArray, false, _voxelsInReadArrays * sizeof(bool));
|
||||
{
|
||||
PerformanceWarning warn(outputWarning,"updateFullVBOs() : memset(_readVoxelDirtyArray...)");
|
||||
// consider the _readVoxelDirtyArray[] clean!
|
||||
memset(_readVoxelDirtyArray, false, _voxelsInReadArrays * sizeof(bool));
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelSystem::updatePartialVBOs() {
|
||||
|
@ -1117,6 +1143,9 @@ void VoxelSystem::updateVBOs() {
|
|||
}
|
||||
|
||||
void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) {
|
||||
bool showWarning = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarning, "updateVBOSegment()");
|
||||
|
||||
if (_useVoxelShader) {
|
||||
int segmentLength = (segmentEnd - segmentStart) + 1;
|
||||
GLintptr segmentStartAt = segmentStart * sizeof(VoxelShaderVBOData);
|
||||
|
@ -1131,18 +1160,36 @@ void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex seg
|
|||
GLintptr segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLfloat);
|
||||
GLsizeiptr segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLfloat);
|
||||
GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * vertexPointsPerVoxel);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
|
||||
|
||||
{
|
||||
PerformanceWarning warn(showWarning, "updateVBOSegment() : glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);");
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceWarning warn(showWarning, "updateVBOSegment() : glBufferSubData() _vboVerticesID);");
|
||||
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
|
||||
}
|
||||
|
||||
segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLubyte);
|
||||
segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLubyte);
|
||||
GLubyte* readColorsFrom = _readColorsArray + (segmentStart * vertexPointsPerVoxel);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);
|
||||
|
||||
{
|
||||
PerformanceWarning warn(showWarning, "updateVBOSegment() : glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);");
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
}
|
||||
|
||||
{
|
||||
PerformanceWarning warn(showWarning, "updateVBOSegment() : glBufferSubData() _vboColorsID);");
|
||||
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelSystem::render(bool texture) {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "render()");
|
||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showWarnings, "render()");
|
||||
|
||||
// If we got here and we're not initialized then bail!
|
||||
if (!_initialized) {
|
||||
|
@ -1154,8 +1201,7 @@ void VoxelSystem::render(bool texture) {
|
|||
bool dontCallOpenGLDraw = Menu::getInstance()->isOptionChecked(MenuOption::DontCallOpenGLForVoxels);
|
||||
// if not don't... then do...
|
||||
if (_useVoxelShader) {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"render().. _useVoxelShader openGL..");
|
||||
PerformanceWarning warn(showWarnings,"render().. _useVoxelShader openGL..");
|
||||
|
||||
|
||||
//Define this somewhere in your header file
|
||||
|
@ -1201,68 +1247,78 @@ void VoxelSystem::render(bool texture) {
|
|||
glDisableVertexAttribArray(attributeLocation);
|
||||
}
|
||||
} else {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "render().. openGL...");
|
||||
PerformanceWarning warn(showWarnings, "render().. TRIANGLES...");
|
||||
|
||||
// tell OpenGL where to find vertex and color information
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
{
|
||||
PerformanceWarning warn(showWarnings,"render().. setup before glDrawRangeElementsEXT()...");
|
||||
|
||||
// tell OpenGL where to find vertex and color information
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
glVertexPointer(3, GL_FLOAT, 0, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
|
||||
glVertexPointer(3, GL_FLOAT, 0, 0);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
|
||||
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
|
||||
|
||||
applyScaleAndBindProgram(texture);
|
||||
applyScaleAndBindProgram(texture);
|
||||
|
||||
// for performance, enable backface culling
|
||||
glEnable(GL_CULL_FACE);
|
||||
// for performance, enable backface culling
|
||||
glEnable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
// draw voxels in 6 passes
|
||||
|
||||
if (!dontCallOpenGLDraw) {
|
||||
PerformanceWarning warn(showWarnings, "render().. glDrawRangeElementsEXT()...");
|
||||
|
||||
glNormal3f(0,1.0f,0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesTop);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
|
||||
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glNormal3f(0,-1.0f,0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBottom);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
|
||||
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glNormal3f(-1.0f,0,0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesLeft);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
|
||||
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glNormal3f(1.0f,0,0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesRight);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
|
||||
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glNormal3f(0,0,-1.0f);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesFront);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
|
||||
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||
|
||||
glNormal3f(0,0,1.0f);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBack);
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
|
||||
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
|
||||
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
|
||||
}
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
{
|
||||
PerformanceWarning warn(showWarnings, "render().. cleanup after glDrawRangeElementsEXT()...");
|
||||
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
removeScaleAndReleaseProgram(texture);
|
||||
removeScaleAndReleaseProgram(texture);
|
||||
|
||||
// deactivate vertex and color arrays after drawing
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
// deactivate vertex and color arrays after drawing
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
// bind with 0 to switch back to normal operation
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
// bind with 0 to switch back to normal operation
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1527,11 +1583,11 @@ public:
|
|||
VoxelSystem* thisVoxelSystem;
|
||||
ViewFrustum thisViewFrustum;
|
||||
VoxelNodeBag dontRecurseBag;
|
||||
unsigned long nodesScanned;
|
||||
unsigned long nodesRemoved;
|
||||
unsigned long nodesInside;
|
||||
unsigned long nodesIntersect;
|
||||
unsigned long nodesOutside;
|
||||
unsigned long nodesScanned;
|
||||
unsigned long nodesRemoved;
|
||||
unsigned long nodesInside;
|
||||
unsigned long nodesIntersect;
|
||||
unsigned long nodesOutside;
|
||||
VoxelNode* insideRoot;
|
||||
VoxelNode* outsideRoot;
|
||||
|
||||
|
@ -1612,10 +1668,10 @@ bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) {
|
|||
bool VoxelSystem::isViewChanging() {
|
||||
bool result = false; // assume the best
|
||||
|
||||
// If our viewFrustum has changed since our _lastKnowViewFrustum
|
||||
if (!_lastKnowViewFrustum.matches(_viewFrustum)) {
|
||||
// If our viewFrustum has changed since our _lastKnownViewFrustum
|
||||
if (!_lastKnownViewFrustum.matches(_viewFrustum)) {
|
||||
result = true;
|
||||
_lastKnowViewFrustum = *_viewFrustum; // save last known
|
||||
_lastKnownViewFrustum = *_viewFrustum; // save last known
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -1628,7 +1684,7 @@ bool VoxelSystem::hasViewChanged() {
|
|||
return false;
|
||||
}
|
||||
|
||||
// If our viewFrustum has changed since our _lastKnowViewFrustum
|
||||
// If our viewFrustum has changed since our _lastKnownViewFrustum
|
||||
if (!_lastStableViewFrustum.matches(_viewFrustum)) {
|
||||
result = true;
|
||||
_lastStableViewFrustum = *_viewFrustum; // save last stable
|
||||
|
@ -1653,27 +1709,92 @@ void VoxelSystem::removeOutOfView() {
|
|||
}
|
||||
}
|
||||
|
||||
// combines the removeOutOfView args into a single class
|
||||
class showAllLocalVoxelsArgs {
|
||||
public:
|
||||
VoxelSystem* thisVoxelSystem;
|
||||
ViewFrustum thisViewFrustum;
|
||||
unsigned long nodesScanned;
|
||||
|
||||
showAllLocalVoxelsArgs(VoxelSystem* voxelSystem) :
|
||||
thisVoxelSystem(voxelSystem),
|
||||
thisViewFrustum(*voxelSystem->getViewFrustum()),
|
||||
nodesScanned(0)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void VoxelSystem::showAllLocalVoxels() {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "showAllLocalVoxels()");
|
||||
showAllLocalVoxelsArgs args(this);
|
||||
_tree->recurseTreeWithOperation(showAllLocalVoxelsOperation,(void*)&args);
|
||||
|
||||
bool showRemoveDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
if (showRemoveDebugDetails) {
|
||||
qDebug("showAllLocalVoxels() scanned=%ld \n",args.nodesScanned );
|
||||
}
|
||||
}
|
||||
|
||||
bool VoxelSystem::showAllLocalVoxelsOperation(VoxelNode* node, void* extraData) {
|
||||
showAllLocalVoxelsArgs* args = (showAllLocalVoxelsArgs*)extraData;
|
||||
|
||||
args->nodesScanned++;
|
||||
|
||||
bool shouldRender = true; // node->calculateShouldRender(&args->thisViewFrustum);
|
||||
node->setShouldRender(shouldRender);
|
||||
|
||||
if (shouldRender) {
|
||||
bool falseColorize = false;
|
||||
if (falseColorize) {
|
||||
node->setFalseColor(0,0,255); // fake
|
||||
}
|
||||
// how does randomize color work?
|
||||
node->setDirtyBit(); // will this make it draw!
|
||||
node->markWithChangedTime(); // fake
|
||||
}
|
||||
|
||||
return true; // keep recursing!
|
||||
}
|
||||
|
||||
|
||||
// combines the removeOutOfView args into a single class
|
||||
class hideOutOfViewArgs {
|
||||
public:
|
||||
VoxelSystem* thisVoxelSystem;
|
||||
VoxelTree* tree;
|
||||
ViewFrustum thisViewFrustum;
|
||||
unsigned long nodesScanned;
|
||||
unsigned long nodesRemoved;
|
||||
unsigned long nodesInside;
|
||||
unsigned long nodesIntersect;
|
||||
unsigned long nodesOutside;
|
||||
VoxelSystem* thisVoxelSystem;
|
||||
VoxelTree* tree;
|
||||
ViewFrustum thisViewFrustum;
|
||||
ViewFrustum lastViewFrustum;
|
||||
bool culledOnce;
|
||||
bool wantDeltaFrustums;
|
||||
unsigned long nodesScanned;
|
||||
unsigned long nodesRemoved;
|
||||
unsigned long nodesInside;
|
||||
unsigned long nodesIntersect;
|
||||
unsigned long nodesOutside;
|
||||
unsigned long nodesInsideInside;
|
||||
unsigned long nodesIntersectInside;
|
||||
unsigned long nodesOutsideInside;
|
||||
unsigned long nodesInsideOutside;
|
||||
unsigned long nodesOutsideOutside;
|
||||
|
||||
hideOutOfViewArgs(VoxelSystem* voxelSystem, VoxelTree* tree, bool widenViewFrustum = true) :
|
||||
hideOutOfViewArgs(VoxelSystem* voxelSystem, VoxelTree* tree,
|
||||
bool culledOnce, bool widenViewFrustum, bool wantDeltaFrustums) :
|
||||
thisVoxelSystem(voxelSystem),
|
||||
tree(tree),
|
||||
thisViewFrustum(*voxelSystem->getViewFrustum()),
|
||||
lastViewFrustum(*voxelSystem->getLastCulledViewFrustum()),
|
||||
culledOnce(culledOnce),
|
||||
wantDeltaFrustums(wantDeltaFrustums),
|
||||
nodesScanned(0),
|
||||
nodesRemoved(0),
|
||||
nodesInside(0),
|
||||
nodesIntersect(0),
|
||||
nodesOutside(0)
|
||||
nodesOutside(0),
|
||||
nodesInsideInside(0),
|
||||
nodesIntersectInside(0),
|
||||
nodesOutsideInside(0),
|
||||
nodesInsideOutside(0),
|
||||
nodesOutsideOutside(0)
|
||||
{
|
||||
// Widen the FOV for trimming
|
||||
if (widenViewFrustum) {
|
||||
|
@ -1686,9 +1807,67 @@ public:
|
|||
};
|
||||
|
||||
void VoxelSystem::hideOutOfView() {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "hideOutOfView()");
|
||||
hideOutOfViewArgs args(this, this->_tree, true); // widen to match server!
|
||||
bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
PerformanceWarning warn(showDebugDetails, "hideOutOfView()", showDebugDetails);
|
||||
bool widenFrustum = true;
|
||||
bool wantDeltaFrustums = false; // Menu::getInstance()->isOptionChecked(MenuOption::UseDeltaFrustumInHide);
|
||||
hideOutOfViewArgs args(this, this->_tree, _culledOnce, widenFrustum, wantDeltaFrustums);
|
||||
|
||||
const bool wantViewFrustumDebugging = false; // change to true for additional debugging
|
||||
if (wantViewFrustumDebugging) {
|
||||
printf("\n\n----------thisViewFrustum----------\n");
|
||||
args.thisViewFrustum.printDebugDetails();
|
||||
|
||||
if (!_culledOnce) {
|
||||
printf("\n\n----------NOT YET CULLED !!!!----------\n");
|
||||
} else {
|
||||
printf("\n\n----------lastViewFrustum----------\n");
|
||||
args.lastViewFrustum.printDebugDetails();
|
||||
}
|
||||
}
|
||||
|
||||
if (_culledOnce && args.lastViewFrustum.matches(args.thisViewFrustum)) {
|
||||
//printf("view frustum hasn't changed BAIL!!!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Changed hideOutOfView() to support "delta" view frustums and only hide/show items that are in the difference
|
||||
// between the two view frustums. There are some potential problems with this idea...
|
||||
//
|
||||
// 1) This might work well for rotating, but what about moving forward?
|
||||
// in the move forward case, you'll get new voxel details, but those
|
||||
// new voxels will be in the last view... does that work?
|
||||
//
|
||||
// 2) what about voxels coming in from the network that are OUTSIDE of the view
|
||||
// frustum... they don't get hidden... and so we can't assume they are correctly
|
||||
// hidden... we could solve this with checking in view on voxelUpdated...
|
||||
//
|
||||
// 3) this seems to mostly work for a few minutes, then it starts to break after some period of time??
|
||||
// and is it related to what appears to be the view changing even when stationary...???
|
||||
//
|
||||
// 4) if something goes wrong it stays wrong? unless new packets come from network... why aren't those redrawing...
|
||||
//
|
||||
// consider doing false colorization...
|
||||
//
|
||||
// What if we kept track of which voxels were visible, and iterated them in an array instead of in the tree?
|
||||
// would that be faster? seems like it wouldn't be.
|
||||
|
||||
//
|
||||
// What's working well now....
|
||||
// Fast Voxel Pipeline + normal Remove Out Of View...
|
||||
// this fails when you spin around, it will just have a big blank spot...
|
||||
// you also see flashes of white/no voxels in areas you've already been
|
||||
//
|
||||
// When you add Don't Remove Out of View voxels...
|
||||
// works OK... but... it loads up too many voxels...
|
||||
// and frame rate drops...
|
||||
//
|
||||
// We'd like to add in hide/show... but things break... See above.
|
||||
// this is the problem... SOLVE this problem...
|
||||
|
||||
_tree->recurseTreeWithOperation(hideOutOfViewOperation,(void*)&args);
|
||||
_lastCulledViewFrustum = args.thisViewFrustum; // save last stable
|
||||
_culledOnce = true;
|
||||
|
||||
if (args.nodesRemoved) {
|
||||
_tree->setDirtyBit();
|
||||
|
@ -1696,24 +1875,47 @@ void VoxelSystem::hideOutOfView() {
|
|||
}
|
||||
|
||||
|
||||
bool showRemoveDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||
if (showRemoveDebugDetails) {
|
||||
if (showDebugDetails) {
|
||||
qDebug("hideOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld\n",
|
||||
args.nodesScanned, args.nodesRemoved, args.nodesInside,
|
||||
args.nodesIntersect, args.nodesOutside
|
||||
);
|
||||
qDebug(" inside/inside=%ld intersect/inside=%ld outside/outside=%ld\n",
|
||||
args.nodesInsideInside, args.nodesIntersectInside, args.nodesOutsideOutside
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
bool VoxelSystem::hideAllSubTreeOperation(VoxelNode* node, void* extraData) {
|
||||
hideOutOfViewArgs* args = (hideOutOfViewArgs*)extraData;
|
||||
|
||||
// If we've culled at least once, then we will use the status of this voxel in the last culled frustum to determine
|
||||
// how to proceed. If we've never culled, then we just consider all these voxels to be UNKNOWN so that we will not
|
||||
// consider that case.
|
||||
ViewFrustum::location inLastCulledFrustum;
|
||||
|
||||
if (args->culledOnce && args->wantDeltaFrustums) {
|
||||
inLastCulledFrustum = node->inFrustum(args->lastViewFrustum);
|
||||
|
||||
// if this node is fully OUTSIDE our last culled view frustum, then we don't need to recurse further
|
||||
if (inLastCulledFrustum == ViewFrustum::OUTSIDE) {
|
||||
args->nodesOutsideOutside++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
args->nodesOutside++;
|
||||
if (node->isKnownBufferIndex()) {
|
||||
args->nodesRemoved++;
|
||||
VoxelSystem* thisVoxelSystem = args->thisVoxelSystem;
|
||||
thisVoxelSystem->_voxelsUpdated += thisVoxelSystem->forceRemoveNodeFromArrays(node);
|
||||
thisVoxelSystem->setupNewVoxelsForDrawingSingleNode();
|
||||
bool falseColorize = false;
|
||||
if (falseColorize) {
|
||||
node->setFalseColor(255,0,0); // fake
|
||||
} else {
|
||||
VoxelSystem* thisVoxelSystem = args->thisVoxelSystem;
|
||||
thisVoxelSystem->_voxelsUpdated += thisVoxelSystem->forceRemoveNodeFromArrays(node);
|
||||
thisVoxelSystem->setupNewVoxelsForDrawingSingleNode();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1722,17 +1924,40 @@ bool VoxelSystem::hideAllSubTreeOperation(VoxelNode* node, void* extraData) {
|
|||
bool VoxelSystem::showAllSubTreeOperation(VoxelNode* node, void* extraData) {
|
||||
hideOutOfViewArgs* args = (hideOutOfViewArgs*)extraData;
|
||||
|
||||
// If we've culled at least once, then we will use the status of this voxel in the last culled frustum to determine
|
||||
// how to proceed. If we've never culled, then we just consider all these voxels to be UNKNOWN so that we will not
|
||||
// consider that case.
|
||||
ViewFrustum::location inLastCulledFrustum;
|
||||
|
||||
if (args->culledOnce && args->wantDeltaFrustums) {
|
||||
inLastCulledFrustum = node->inFrustum(args->lastViewFrustum);
|
||||
|
||||
// if this node is fully inside our last culled view frustum, then we don't need to recurse further
|
||||
if (inLastCulledFrustum == ViewFrustum::INSIDE) {
|
||||
args->nodesInsideInside++;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
args->nodesInside++;
|
||||
|
||||
if (node->getShouldRender() && !node->isKnownBufferIndex()) {
|
||||
//printf("<<<<<<<<<<< showAllSubTreeOperation() >>>>>>>>>>>>>>>\n");
|
||||
|
||||
bool shouldRender = node->calculateShouldRender(&args->thisViewFrustum);
|
||||
node->setShouldRender(shouldRender);
|
||||
|
||||
if (shouldRender /*&& !node->isKnownBufferIndex()*/) {
|
||||
bool falseColorize = false;
|
||||
if (falseColorize) {
|
||||
node->setFalseColor(0,0,255); // fake
|
||||
}
|
||||
node->setDirtyBit(); // will this make it draw!
|
||||
node->markWithChangedTime(); // fake
|
||||
}
|
||||
|
||||
return true; // keep recursing!
|
||||
}
|
||||
|
||||
|
||||
|
||||
// "hide" voxels in the VBOs that are still in the tree that but not in view.
|
||||
// We don't remove them from the tree, we don't delete them, we do remove them
|
||||
// from the VBOs and mark them as such in the tree.
|
||||
|
@ -1742,26 +1967,67 @@ bool VoxelSystem::hideOutOfViewOperation(VoxelNode* node, void* extraData) {
|
|||
// If we're still recursing the tree using this operator, then we don't know if we're inside or outside...
|
||||
// so before we move forward we need to determine our frustum location
|
||||
ViewFrustum::location inFrustum = node->inFrustum(args->thisViewFrustum);
|
||||
|
||||
// If we've culled at least once, then we will use the status of this voxel in the last culled frustum to determine
|
||||
// how to proceed. If we've never culled, then we just consider all these voxels to be UNKNOWN so that we will not
|
||||
// consider that case.
|
||||
ViewFrustum::location inLastCulledFrustum;
|
||||
|
||||
if (args->culledOnce && args->wantDeltaFrustums) {
|
||||
inLastCulledFrustum = node->inFrustum(args->lastViewFrustum);
|
||||
}
|
||||
|
||||
// ok, now do some processing for this node...
|
||||
switch (inFrustum) {
|
||||
case ViewFrustum::OUTSIDE: {
|
||||
// if this node is fully OUTSIDE the view, then we know that ALL of it's children are also fully OUTSIDE
|
||||
// so we can recurse the children and simply mark them as hidden
|
||||
|
||||
// If this node is outside the current view, then we might want to hide it... unless it was previously OUTSIDE,
|
||||
// if it was previously outside, then we can safely assume it's already hidden, and we can also safely assume
|
||||
// that all of it's children are outside both of our views, in which case we can just stop recursing...
|
||||
if (args->culledOnce && args->wantDeltaFrustums && inLastCulledFrustum == ViewFrustum::OUTSIDE) {
|
||||
args->nodesScanned++;
|
||||
args->nodesOutsideOutside++;
|
||||
return false; // stop recursing this branch!
|
||||
}
|
||||
|
||||
// if this node is fully OUTSIDE the view, but previously intersected and/or was inside the last view, then
|
||||
// we need to hide it. Additionally we know that ALL of it's children are also fully OUTSIDE so we can recurse
|
||||
// the children and simply mark them as hidden
|
||||
args->tree->recurseNodeWithOperation(node, hideAllSubTreeOperation, args );
|
||||
|
||||
return false;
|
||||
|
||||
} break;
|
||||
case ViewFrustum::INSIDE: {
|
||||
// if this node is fully INSIDE the view, then we know that ALL of it's children are also fully INSIDE
|
||||
// so we can recurse the children and simply mark them as visible (as appropriate based on LOD)
|
||||
args->tree->recurseNodeWithOperation(node, showAllSubTreeOperation, args );
|
||||
|
||||
// If this node is INSIDE the current view, then we might want to show it... unless it was previously INSIDE,
|
||||
// if it was previously INSIDE, then we can safely assume it's already shown, and we can also safely assume
|
||||
// that all of it's children are INSIDE both of our views, in which case we can just stop recursing...
|
||||
if (args->culledOnce && args->wantDeltaFrustums && inLastCulledFrustum == ViewFrustum::INSIDE) {
|
||||
args->nodesScanned++;
|
||||
args->nodesInsideInside++;
|
||||
return false; // stop recursing this branch!
|
||||
}
|
||||
|
||||
// if this node is fully INSIDE the view, but previously INTERSECTED and/or was OUTSIDE the last view, then
|
||||
// we need to show it. Additionally we know that ALL of it's children are also fully INSIDE so we can recurse
|
||||
// the children and simply mark them as visible (as appropriate based on LOD)
|
||||
//printf("<<<<<<<<<<< HERE!!!!! >>>>>>>>>>>>>>>\n");
|
||||
args->tree->recurseNodeWithOperation(node, showAllSubTreeOperation, args);
|
||||
|
||||
return false;
|
||||
} break;
|
||||
case ViewFrustum::INTERSECT: {
|
||||
args->nodesScanned++;
|
||||
|
||||
// If this node INTERSECTS the current view, then we might want to show it... unless it was previously INSIDE
|
||||
// the last known view, in which case it will already be visible, and we know that all it's children are also
|
||||
// previously INSIDE and visible. So in this case stop recursing
|
||||
if (args->culledOnce && args->wantDeltaFrustums && inLastCulledFrustum == ViewFrustum::INSIDE) {
|
||||
args->nodesIntersectInside++;
|
||||
return false; // stop recursing this branch!
|
||||
}
|
||||
|
||||
args->nodesIntersect++;
|
||||
|
||||
// if the child node INTERSECTs the view, then we want to check to see if it thinks it should render
|
||||
|
@ -1887,6 +2153,7 @@ public:
|
|||
};
|
||||
|
||||
bool VoxelSystem::collectStatsForTreesAndVBOsOperation(VoxelNode* node, void* extraData) {
|
||||
|
||||
collectStatsForTreesAndVBOsArgs* args = (collectStatsForTreesAndVBOsArgs*)extraData;
|
||||
args->totalNodes++;
|
||||
|
||||
|
|
|
@ -59,6 +59,9 @@ public:
|
|||
void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; }
|
||||
unsigned long getVoxelsUpdated() const { return _voxelsUpdated; }
|
||||
unsigned long getVoxelsRendered() const { return _voxelsInReadArrays; }
|
||||
unsigned long getVoxelsWritten() const { return _voxelsInWriteArrays; }
|
||||
|
||||
ViewFrustum* getLastCulledViewFrustum() { return &_lastCulledViewFrustum; }
|
||||
|
||||
void loadVoxelsFile(const char* fileName,bool wantColorRandomizer);
|
||||
void writeToSVOFile(const char* filename, VoxelNode* node) const;
|
||||
|
@ -123,6 +126,7 @@ public slots:
|
|||
void collectStatsForTreesAndVBOs();
|
||||
|
||||
// Methods that recurse tree
|
||||
void showAllLocalVoxels();
|
||||
void randomizeVoxelColors();
|
||||
void falseColorizeRandom();
|
||||
void trueColorize();
|
||||
|
@ -192,6 +196,7 @@ private:
|
|||
static bool hideOutOfViewUnrollOperation(VoxelNode* node, void* extraData);
|
||||
static bool hideAllSubTreeOperation(VoxelNode* node, void* extraData);
|
||||
static bool showAllSubTreeOperation(VoxelNode* node, void* extraData);
|
||||
static bool showAllLocalVoxelsOperation(VoxelNode* node, void* extraData);
|
||||
|
||||
int updateNodeInArrays(VoxelNode* node, bool reuseIndex, bool forceDraw);
|
||||
int forceRemoveNodeFromArrays(VoxelNode* node);
|
||||
|
@ -252,10 +257,13 @@ private:
|
|||
pthread_mutex_t _bufferWriteLock;
|
||||
pthread_mutex_t _treeLock;
|
||||
|
||||
ViewFrustum _lastKnowViewFrustum;
|
||||
ViewFrustum _lastKnownViewFrustum;
|
||||
ViewFrustum _lastStableViewFrustum;
|
||||
ViewFrustum* _viewFrustum;
|
||||
|
||||
ViewFrustum _lastCulledViewFrustum; // used for hide/show visible passes
|
||||
bool _culledOnce;
|
||||
|
||||
void setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndices[]);
|
||||
|
||||
int newTreeToArrays(VoxelNode *currentNode);
|
||||
|
|
Loading…
Reference in a new issue