bool OctreeQueryNode::updateCurrentViewFrustum() { // if shutting down, return immediately if (_isShuttingDown) { return false; } bool currentViewFrustumChanged = false; ViewFrustum newestViewFrustum; // get position and orientation details from the camera newestViewFrustum.setPosition(getCameraPosition()); newestViewFrustum.setOrientation(getCameraOrientation()); // Also make sure it's got the correct lens details from the camera float originalFOV = getCameraFov(); float wideFOV = originalFOV + VIEW_FRUSTUM_FOV_OVERSEND; newestViewFrustum.setFieldOfView(wideFOV); // hack newestViewFrustum.setAspectRatio(getCameraAspectRatio()); newestViewFrustum.setNearClip(getCameraNearClip()); newestViewFrustum.setFarClip(getCameraFarClip()); newestViewFrustum.setEyeOffsetPosition(getCameraEyeOffsetPosition()); // if there has been a change, then recalculate if (!newestViewFrustum.isVerySimilar(_currentViewFrustum)) { _currentViewFrustum = newestViewFrustum; _currentViewFrustum.calculate(); currentViewFrustumChanged = true; } // Also check for LOD changes from the client if (_lodInitialized) { if (_lastClientBoundaryLevelAdjust != getBoundaryLevelAdjust()) { _lastClientBoundaryLevelAdjust = getBoundaryLevelAdjust(); _lodChanged = true; } if (_lastClientOctreeSizeScale != getOctreeSizeScale()) { _lastClientOctreeSizeScale = getOctreeSizeScale(); _lodChanged = true; } } else { _lodInitialized = true; _lastClientOctreeSizeScale = getOctreeSizeScale(); _lastClientBoundaryLevelAdjust = getBoundaryLevelAdjust(); _lodChanged = false; } // When we first detect that the view stopped changing, we record this. // but we don't change it back to false until we've completely sent this // scene. if (_viewFrustumChanging && !currentViewFrustumChanged) { _viewFrustumJustStoppedChanging = true; } _viewFrustumChanging = currentViewFrustumChanged; return currentViewFrustumChanged; }
QString LODManager::getLODFeedbackText() { // determine granularity feedback int boundaryLevelAdjust = getBoundaryLevelAdjust(); QString granularityFeedback; switch (boundaryLevelAdjust) { case 0: { granularityFeedback = QString("."); } break; case 1: { granularityFeedback = QString(" at half of standard granularity."); } break; case 2: { granularityFeedback = QString(" at a third of standard granularity."); } break; default: { granularityFeedback = QString(" at 1/%1th of standard granularity.").arg(boundaryLevelAdjust + 1); } break; } // distance feedback float octreeSizeScale = getOctreeSizeScale(); float relativeToDefault = octreeSizeScale / DEFAULT_OCTREE_SIZE_SCALE; int relativeToTwentyTwenty = 20 / relativeToDefault; QString result; if (relativeToDefault > 1.01f) { result = QString("20:%1 or %2 times further than average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault,0,'f',2).arg(granularityFeedback); } else if (relativeToDefault > 0.99f) { result = QString("20:20 or the default distance for average vision%1").arg(granularityFeedback); } else if (relativeToDefault > 0.01f) { result = QString("20:%1 or %2 of default distance for average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault,0,'f',3).arg(granularityFeedback); } else { result = QString("%2 of default distance for average vision%3").arg(relativeToDefault,0,'f',3).arg(granularityFeedback); } return result; }
// TODO: This is essentially the same logic used to render octree cells, but since models are more detailed then octree cells // I've added a voxelToModelRatio that adjusts how much closer to a model you have to be to see it. bool LODManager::shouldRenderMesh(float largestDimension, float distanceToCamera) { const float octreeToMeshRatio = 4.0f; // must be this many times closer to a mesh than a voxel to see it. float octreeSizeScale = getOctreeSizeScale(); int boundaryLevelAdjust = getBoundaryLevelAdjust(); float maxScale = (float)TREE_SCALE; float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / octreeToMeshRatio; if (_shouldRenderTableNeedsRebuilding) { _shouldRenderTable.clear(); float SMALLEST_SCALE_IN_TABLE = 0.001f; // 1mm is plenty small float scale = maxScale; float visibleDistanceAtScale = visibleDistanceAtMaxScale; while (scale > SMALLEST_SCALE_IN_TABLE) { scale /= 2.0f; visibleDistanceAtScale /= 2.0f; _shouldRenderTable[scale] = visibleDistanceAtScale; } _shouldRenderTableNeedsRebuilding = false; } float closestScale = maxScale; float visibleDistanceAtClosestScale = visibleDistanceAtMaxScale; QMap<float, float>::const_iterator lowerBound = _shouldRenderTable.lowerBound(largestDimension); if (lowerBound != _shouldRenderTable.constEnd()) { closestScale = lowerBound.key(); visibleDistanceAtClosestScale = lowerBound.value(); } if (closestScale < largestDimension) { visibleDistanceAtClosestScale *= 2.0f; } return (distanceToCamera <= visibleDistanceAtClosestScale); }
bool OctreeQueryNode::updateCurrentViewFrustum() { // if shutting down, return immediately if (_isShuttingDown) { return false; } if (!_usesFrustum) { // this client does not use a view frustum so the view frustum for this query has not changed return false; } else { bool currentViewFrustumChanged = false; ViewFrustum newestViewFrustum; // get position and orientation details from the camera newestViewFrustum.setPosition(getCameraPosition()); newestViewFrustum.setOrientation(getCameraOrientation()); newestViewFrustum.setCenterRadius(getCameraCenterRadius()); // Also make sure it's got the correct lens details from the camera float originalFOV = getCameraFov(); float wideFOV = originalFOV + VIEW_FRUSTUM_FOV_OVERSEND; if (0.0f != getCameraAspectRatio() && 0.0f != getCameraNearClip() && 0.0f != getCameraFarClip() && getCameraNearClip() != getCameraFarClip()) { newestViewFrustum.setProjection(glm::perspective( glm::radians(wideFOV), // hack getCameraAspectRatio(), getCameraNearClip(), getCameraFarClip())); newestViewFrustum.calculate(); } { // if there has been a change, then recalculate QMutexLocker viewLocker(&_viewMutex); if (!newestViewFrustum.isVerySimilar(_currentViewFrustum)) { _currentViewFrustum = newestViewFrustum; currentViewFrustumChanged = true; } } // Also check for LOD changes from the client if (_lodInitialized) { if (_lastClientBoundaryLevelAdjust != getBoundaryLevelAdjust()) { _lastClientBoundaryLevelAdjust = getBoundaryLevelAdjust(); _lodChanged = true; } if (_lastClientOctreeSizeScale != getOctreeSizeScale()) { _lastClientOctreeSizeScale = getOctreeSizeScale(); _lodChanged = true; } } else { _lodInitialized = true; _lastClientOctreeSizeScale = getOctreeSizeScale(); _lastClientBoundaryLevelAdjust = getBoundaryLevelAdjust(); _lodChanged = false; } // When we first detect that the view stopped changing, we record this. // but we don't change it back to false until we've completely sent this // scene. if (_viewFrustumChanging && !currentViewFrustumChanged) { _viewFrustumJustStoppedChanging = true; } _viewFrustumChanging = currentViewFrustumChanged; return currentViewFrustumChanged; } }