mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 19:59:28 +02:00
added CoverageMap and occlusion culling to server
This commit is contained in:
parent
c8d4b2ebed
commit
58c4010185
4 changed files with 211 additions and 39 deletions
|
@ -22,6 +22,7 @@
|
||||||
#include "ViewFrustum.h"
|
#include "ViewFrustum.h"
|
||||||
#include <fstream> // to load voxels from file
|
#include <fstream> // to load voxels from file
|
||||||
#include "VoxelConstants.h"
|
#include "VoxelConstants.h"
|
||||||
|
#include "CoverageMap.h"
|
||||||
|
|
||||||
#include <glm/gtc/noise.hpp>
|
#include <glm/gtc/noise.hpp>
|
||||||
|
|
||||||
|
@ -91,21 +92,19 @@ void VoxelTree::recurseNodeWithOperationDistanceSorted(VoxelNode* node, RecurseV
|
||||||
if (childNode) {
|
if (childNode) {
|
||||||
// chance to optimize, doesn't need to be actual distance!! Could be distance squared
|
// chance to optimize, doesn't need to be actual distance!! Could be distance squared
|
||||||
float distanceSquared = childNode->distanceSquareToPoint(point);
|
float distanceSquared = childNode->distanceSquareToPoint(point);
|
||||||
//printLog("recurseNodeWithOperationDistanceSorted() CHECKING child[%d] point=%f,%f center=%f,%f distance=%f...\n", i, point.x, point.y, center.x, center.y, distance);
|
//printLog("recurseNodeWithOperationDistanceSorted() CHECKING child[%d] point=%f,%f center=%f,%f distance=%f...\n", i, point.x, point.y, center.x, center.y, distance);
|
||||||
//childNode->printDebugDetails("");
|
//childNode->printDebugDetails("");
|
||||||
currentCount = insertIntoSortedArrays((void*)childNode, distanceSquared, i,
|
currentCount = insertIntoSortedArrays((void*)childNode, distanceSquared, i,
|
||||||
(void**)&sortedChildren, (float*)&distancesToChildren,
|
(void**)&sortedChildren, (float*)&distancesToChildren,
|
||||||
(int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN);
|
(int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < currentCount; i++) {
|
for (int i = 0; i < currentCount; i++) {
|
||||||
VoxelNode* childNode = sortedChildren[i];
|
VoxelNode* childNode = sortedChildren[i];
|
||||||
if (childNode) {
|
if (childNode) {
|
||||||
//printLog("recurseNodeWithOperationDistanceSorted() PROCESSING child[%d] distance=%f...\n", i, distancesToChildren[i]);
|
//printLog("recurseNodeWithOperationDistanceSorted() PROCESSING child[%d] distance=%f...\n", i, distancesToChildren[i]);
|
||||||
//childNode->printDebugDetails("");
|
//childNode->printDebugDetails("");
|
||||||
recurseNodeWithOperationDistanceSorted(childNode, operation, point, extraData);
|
recurseNodeWithOperationDistanceSorted(childNode, operation, point, extraData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1118,6 +1117,39 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
|
||||||
if (!node->isInView(*params.viewFrustum)) {
|
if (!node->isInView(*params.viewFrustum)) {
|
||||||
return bytesAtThisLevel;
|
return bytesAtThisLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If the user also asked for occlusion culling, check if this node is occluded, but only if it's not a leaf.
|
||||||
|
// leaf occlusion is handled down below when we check child nodes
|
||||||
|
if (params.wantOcclusionCulling && !node->isLeaf()) {
|
||||||
|
//node->printDebugDetails("upper section, params.wantOcclusionCulling... node=");
|
||||||
|
AABox voxelBox = node->getAABox();
|
||||||
|
voxelBox.scale(TREE_SCALE);
|
||||||
|
VoxelProjectedShadow* voxelShadow = new VoxelProjectedShadow(params.viewFrustum->getProjectedShadow(voxelBox));
|
||||||
|
|
||||||
|
// In order to check occlusion culling, the shadow has to be "all in view" otherwise, we will ignore occlusion
|
||||||
|
// culling and proceed as normal
|
||||||
|
if (voxelShadow->getAllInView()) {
|
||||||
|
//node->printDebugDetails("upper section, voxelShadow->getAllInView() node=");
|
||||||
|
|
||||||
|
CoverageMap::StorageResult result = params.map->checkMap(voxelShadow, false);
|
||||||
|
delete voxelShadow; // cleanup
|
||||||
|
if (result == CoverageMap::OCCLUDED) {
|
||||||
|
//node->printDebugDetails("upper section, non-Leaf is occluded!! node=");
|
||||||
|
//args->nonLeavesOccluded++;
|
||||||
|
|
||||||
|
//args->subtreeVoxelsSkipped += (subArgs.voxelsTouched - 1);
|
||||||
|
//args->totalVoxels += (subArgs.voxelsTouched - 1);
|
||||||
|
|
||||||
|
return bytesAtThisLevel;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//node->printDebugDetails("upper section, shadow Not in view node=");
|
||||||
|
// If this shadow wasn't "all in view" then we ignored it for occlusion culling, but
|
||||||
|
// we do need to clean up memory and proceed as normal...
|
||||||
|
delete voxelShadow;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more!
|
bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more!
|
||||||
|
@ -1126,37 +1158,68 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
|
||||||
// is 1 byte for child colors + 3*NUMBER_OF_CHILDREN bytes for the actual colors + 1 byte for child trees. There could be sub trees
|
// is 1 byte for child colors + 3*NUMBER_OF_CHILDREN bytes for the actual colors + 1 byte for child trees. There could be sub trees
|
||||||
// below this point, which might take many more bytes, but that's ok, because we can always mark our subtrees as
|
// below this point, which might take many more bytes, but that's ok, because we can always mark our subtrees as
|
||||||
// not existing and stop the packet at this point, then start up with a new packet for the remaining sub trees.
|
// not existing and stop the packet at this point, then start up with a new packet for the remaining sub trees.
|
||||||
const int CHILD_COLOR_MASK_BYTES = 1;
|
unsigned char childrenExistInTreeBits = 0;
|
||||||
|
unsigned char childrenExistInPacketBits = 0;
|
||||||
|
unsigned char childrenColoredBits = 0;
|
||||||
|
|
||||||
|
const int CHILD_COLOR_MASK_BYTES = sizeof(childrenColoredBits);
|
||||||
const int BYTES_PER_COLOR = 3;
|
const int BYTES_PER_COLOR = 3;
|
||||||
const int CHILD_TREE_EXISTS_BYTES = 1;
|
const int CHILD_TREE_EXISTS_BYTES = sizeof(childrenExistInTreeBits) + sizeof(childrenExistInPacketBits);
|
||||||
const int MAX_LEVEL_BYTES = CHILD_COLOR_MASK_BYTES + NUMBER_OF_CHILDREN * BYTES_PER_COLOR + CHILD_TREE_EXISTS_BYTES;
|
const int MAX_LEVEL_BYTES = CHILD_COLOR_MASK_BYTES + NUMBER_OF_CHILDREN * BYTES_PER_COLOR + CHILD_TREE_EXISTS_BYTES;
|
||||||
|
|
||||||
// Make our local buffer large enough to handle writing at this level in case we need to.
|
// Make our local buffer large enough to handle writing at this level in case we need to.
|
||||||
unsigned char thisLevelBuffer[MAX_LEVEL_BYTES];
|
unsigned char thisLevelBuffer[MAX_LEVEL_BYTES];
|
||||||
unsigned char* writeToThisLevelBuffer = &thisLevelBuffer[0];
|
unsigned char* writeToThisLevelBuffer = &thisLevelBuffer[0];
|
||||||
|
|
||||||
unsigned char childrenExistInTreeBits = 0;
|
|
||||||
unsigned char childrenExistInPacketBits = 0;
|
|
||||||
unsigned char childrenColoredBits = 0;
|
|
||||||
int inViewCount = 0;
|
int inViewCount = 0;
|
||||||
int inViewNotLeafCount = 0;
|
int inViewNotLeafCount = 0;
|
||||||
int inViewWithColorCount = 0;
|
int inViewWithColorCount = 0;
|
||||||
|
|
||||||
// for each child node, check to see if they exist, are colored, and in view, and if so
|
VoxelNode* sortedChildren[NUMBER_OF_CHILDREN];
|
||||||
// add them to our distance ordered array of children
|
float distancesToChildren[NUMBER_OF_CHILDREN];
|
||||||
|
int indexOfChildren[NUMBER_OF_CHILDREN]; // not really needed
|
||||||
|
int currentCount = 0;
|
||||||
|
|
||||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||||
VoxelNode* childNode = node->getChildAtIndex(i);
|
VoxelNode* childNode = node->getChildAtIndex(i);
|
||||||
|
|
||||||
// if the caller wants to include childExistsBits, then include them even if not in view
|
// if the caller wants to include childExistsBits, then include them even if not in view
|
||||||
if (params.includeExistsBits && childNode) {
|
if (params.includeExistsBits && childNode) {
|
||||||
childrenExistInTreeBits += (1 << (7 - i));
|
childrenExistInTreeBits += (1 << (7 - i));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (params.wantOcclusionCulling) {
|
||||||
|
if (childNode) {
|
||||||
|
// chance to optimize, doesn't need to be actual distance!! Could be distance squared
|
||||||
|
//float distanceSquared = childNode->distanceSquareToPoint(point);
|
||||||
|
//printLog("recurseNodeWithOperationDistanceSorted() CHECKING child[%d] point=%f,%f center=%f,%f distance=%f...\n", i, point.x, point.y, center.x, center.y, distance);
|
||||||
|
//childNode->printDebugDetails("");
|
||||||
|
|
||||||
|
float distance = params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0;
|
||||||
|
|
||||||
|
currentCount = insertIntoSortedArrays((void*)childNode, distance, i,
|
||||||
|
(void**)&sortedChildren, (float*)&distancesToChildren,
|
||||||
|
(int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sortedChildren[i] = childNode;
|
||||||
|
indexOfChildren[i] = i;
|
||||||
|
distancesToChildren[i] = 0.0f;
|
||||||
|
currentCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// for each child node in Distance sorted order..., check to see if they exist, are colored, and in view, and if so
|
||||||
|
// add them to our distance ordered array of children
|
||||||
|
for (int i = 0; i < currentCount; i++) {
|
||||||
|
VoxelNode* childNode = sortedChildren[i];
|
||||||
|
int originalIndex = indexOfChildren[i];
|
||||||
|
|
||||||
bool childIsInView = (childNode && (!params.viewFrustum || childNode->isInView(*params.viewFrustum)));
|
bool childIsInView = (childNode && (!params.viewFrustum || childNode->isInView(*params.viewFrustum)));
|
||||||
|
|
||||||
if (childIsInView) {
|
if (childIsInView) {
|
||||||
// Before we determine consider this further, let's see if it's in our LOD scope...
|
// Before we determine consider this further, let's see if it's in our LOD scope...
|
||||||
float distance = params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0;
|
float distance = distancesToChildren[i]; // params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0;
|
||||||
float boundaryDistance = params.viewFrustum ? boundaryDistanceForRenderLevel(*childNode->getOctalCode() + 1) : 1;
|
float boundaryDistance = params.viewFrustum ? boundaryDistanceForRenderLevel(*childNode->getOctalCode() + 1) : 1;
|
||||||
|
|
||||||
if (distance < boundaryDistance) {
|
if (distance < boundaryDistance) {
|
||||||
|
@ -1166,16 +1229,62 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
|
||||||
// we don't care about recursing deeper on them, and we don't consider their
|
// we don't care about recursing deeper on them, and we don't consider their
|
||||||
// subtree to exist
|
// subtree to exist
|
||||||
if (!(childNode && childNode->isLeaf())) {
|
if (!(childNode && childNode->isLeaf())) {
|
||||||
childrenExistInPacketBits += (1 << (7 - i));
|
childrenExistInPacketBits += (1 << (7 - originalIndex));
|
||||||
inViewNotLeafCount++;
|
inViewNotLeafCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool childIsOccluded = false; // assume it's not occluded
|
||||||
|
|
||||||
|
// If the user also asked for occlusion culling, check if this node is occluded
|
||||||
|
if (params.wantOcclusionCulling && childNode->isLeaf()) {
|
||||||
|
//printLog("params.wantOcclusionCulling... in childNode section...\n");
|
||||||
|
// Don't check occlusion here, just add them to our distance ordered array...
|
||||||
|
|
||||||
|
AABox voxelBox = childNode->getAABox();
|
||||||
|
voxelBox.scale(TREE_SCALE);
|
||||||
|
VoxelProjectedShadow* voxelShadow = new VoxelProjectedShadow(params.viewFrustum->getProjectedShadow(voxelBox));
|
||||||
|
|
||||||
|
// In order to check occlusion culling, the shadow has to be "all in view" otherwise, we will ignore occlusion
|
||||||
|
// culling and proceed as normal
|
||||||
|
if (voxelShadow->getAllInView()) {
|
||||||
|
//childNode->printDebugDetails("voxelShadow->getAllInView() childNode=");
|
||||||
|
|
||||||
|
CoverageMap::StorageResult result = params.map->checkMap(voxelShadow, true);
|
||||||
|
|
||||||
|
// In all cases where the shadow wasn't stored, we need to free our own memory.
|
||||||
|
// In the case where it is stored, the CoverageMap will free memory for us later.
|
||||||
|
if (result != CoverageMap::STORED) {
|
||||||
|
delete voxelShadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == CoverageMap::STORED) {
|
||||||
|
//childNode->printDebugDetails("Leaf is stored!! childNode=");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == CoverageMap::DOESNT_FIT) {
|
||||||
|
//printLog(">>>> Leaf DOESNT_FIT!! That's not expected!!! \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If while attempting to add this voxel's shadow, we determined it was occluded, then
|
||||||
|
// we don't need to process it further and we can exit early.
|
||||||
|
if (result == CoverageMap::OCCLUDED) {
|
||||||
|
//childNode->printDebugDetails("Leaf is occluded!! childNode=");
|
||||||
|
childIsOccluded = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//childNode->printDebugDetails("Not all in view, cleanup... childNode=");
|
||||||
|
delete voxelShadow;
|
||||||
|
}
|
||||||
|
} // wants occlusion culling & isLeaf()
|
||||||
|
|
||||||
|
|
||||||
bool childWasInView = (childNode && params.deltaViewFrustum &&
|
bool childWasInView = (childNode && params.deltaViewFrustum &&
|
||||||
(params.lastViewFrustum && ViewFrustum::INSIDE == childNode->inFrustum(*params.lastViewFrustum)));
|
(params.lastViewFrustum && ViewFrustum::INSIDE == childNode->inFrustum(*params.lastViewFrustum)));
|
||||||
|
|
||||||
// track children with actual color, only if the child wasn't previously in view!
|
// track children with actual color, only if the child wasn't previously in view!
|
||||||
if (childNode && childNode->isColored() && !childWasInView) {
|
if (childNode && childNode->isColored() && !childWasInView && !childIsOccluded) {
|
||||||
childrenColoredBits += (1 << (7 - i));
|
childrenColoredBits += (1 << (7 - originalIndex));
|
||||||
inViewWithColorCount++;
|
inViewWithColorCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1235,15 +1344,35 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
|
||||||
//
|
//
|
||||||
// we know the last thing we wrote to the outputBuffer was our childrenExistInPacketBits. Let's remember where that was!
|
// we know the last thing we wrote to the outputBuffer was our childrenExistInPacketBits. Let's remember where that was!
|
||||||
unsigned char* childExistsPlaceHolder = outputBuffer-sizeof(childrenExistInPacketBits);
|
unsigned char* childExistsPlaceHolder = outputBuffer-sizeof(childrenExistInPacketBits);
|
||||||
|
|
||||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
|
||||||
|
|
||||||
if (oneAtBit(childrenExistInPacketBits, i)) {
|
// we are also going to recurse these child trees in "distance" sorted order, but we need to pack them in the
|
||||||
VoxelNode* childNode = node->getChildAtIndex(i);
|
// final packet in standard order. So what we're going to do is keep track of how big each subtree was in bytes,
|
||||||
|
// and then later reshuffle these sections of our output buffer back into normal order. This allows us to make
|
||||||
|
// a single recursive pass in distance sorted order, but retain standard order in our encoded packet
|
||||||
|
int recursiveSliceSizes[NUMBER_OF_CHILDREN];
|
||||||
|
unsigned char* recursiveSliceStarts[NUMBER_OF_CHILDREN];
|
||||||
|
unsigned char* firstRecursiveSlice = outputBuffer;
|
||||||
|
int allSlicesSize = 0;
|
||||||
|
|
||||||
|
// for each child node in Distance sorted order..., check to see if they exist, are colored, and in view, and if so
|
||||||
|
// add them to our distance ordered array of children
|
||||||
|
for (int indexByDistance = 0; indexByDistance < currentCount; indexByDistance++) {
|
||||||
|
VoxelNode* childNode = sortedChildren[indexByDistance];
|
||||||
|
int originalIndex = indexOfChildren[indexByDistance];
|
||||||
|
|
||||||
|
if (oneAtBit(childrenExistInPacketBits, originalIndex)) {
|
||||||
|
|
||||||
int thisLevel = currentEncodeLevel;
|
int thisLevel = currentEncodeLevel;
|
||||||
|
|
||||||
|
// remember this for reshuffling
|
||||||
|
recursiveSliceStarts[originalIndex] = outputBuffer;
|
||||||
|
|
||||||
int childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, outputBuffer, availableBytes, bag,
|
int childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, outputBuffer, availableBytes, bag,
|
||||||
params, thisLevel);
|
params, thisLevel);
|
||||||
|
|
||||||
|
// remember this for reshuffling
|
||||||
|
recursiveSliceSizes[originalIndex] = childTreeBytesOut;
|
||||||
|
allSlicesSize += childTreeBytesOut;
|
||||||
|
|
||||||
// if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space,
|
// if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space,
|
||||||
// basically, the children below don't contain any info.
|
// basically, the children below don't contain any info.
|
||||||
|
@ -1273,15 +1402,40 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
|
||||||
// then we want to remove their bit from the childExistsPlaceHolder bitmask
|
// then we want to remove their bit from the childExistsPlaceHolder bitmask
|
||||||
if (childTreeBytesOut == 0) {
|
if (childTreeBytesOut == 0) {
|
||||||
// remove this child's bit...
|
// remove this child's bit...
|
||||||
childrenExistInPacketBits -= (1 << (7 - i));
|
childrenExistInPacketBits -= (1 << (7 - originalIndex));
|
||||||
// repair the child exists mask
|
// repair the child exists mask
|
||||||
*childExistsPlaceHolder = childrenExistInPacketBits;
|
*childExistsPlaceHolder = childrenExistInPacketBits;
|
||||||
// Note: no need to move the pointer, cause we already stored this
|
// Note: no need to move the pointer, cause we already stored this
|
||||||
} // end if (childTreeBytesOut == 0)
|
} // end if (childTreeBytesOut == 0)
|
||||||
} // end if (oneAtBit(childrenExistInPacketBits, i))
|
} // end if (oneAtBit(childrenExistInPacketBits, originalIndex))
|
||||||
} // end for
|
} // end for
|
||||||
} // end keepDiggingDeeper
|
|
||||||
|
|
||||||
|
// reshuffle here...
|
||||||
|
if (params.wantOcclusionCulling) {
|
||||||
|
unsigned char tempReshuffleBuffer[MAX_VOXEL_PACKET_SIZE];
|
||||||
|
|
||||||
|
unsigned char* tempBufferTo = &tempReshuffleBuffer[0]; // this is our temporary destination
|
||||||
|
|
||||||
|
// iterate through our childrenExistInPacketBits, these will be the sections of the packet that we copied subTree
|
||||||
|
// details into. Unfortunately, they're in distance sorted order, not original index order. we need to put them
|
||||||
|
// back into original distance order
|
||||||
|
for (int originalIndex = 0; originalIndex < NUMBER_OF_CHILDREN; originalIndex++) {
|
||||||
|
if (oneAtBit(childrenExistInPacketBits, originalIndex)) {
|
||||||
|
int thisSliceSize = recursiveSliceSizes[originalIndex];
|
||||||
|
unsigned char* thisSliceStarts = recursiveSliceStarts[originalIndex];
|
||||||
|
|
||||||
|
memcpy(tempBufferTo, thisSliceStarts, thisSliceSize);
|
||||||
|
tempBufferTo += thisSliceSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now that all slices are back in the correct order, copy them to the correct output buffer
|
||||||
|
memcpy(firstRecursiveSlice, &tempReshuffleBuffer[0], allSlicesSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
} // end keepDiggingDeeper
|
||||||
|
|
||||||
return bytesAtThisLevel;
|
return bytesAtThisLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,20 +13,25 @@
|
||||||
#include "ViewFrustum.h"
|
#include "ViewFrustum.h"
|
||||||
#include "VoxelNode.h"
|
#include "VoxelNode.h"
|
||||||
#include "VoxelNodeBag.h"
|
#include "VoxelNodeBag.h"
|
||||||
|
#include "CoverageMap.h"
|
||||||
|
|
||||||
// Callback function, for recuseTreeWithOperation
|
// Callback function, for recuseTreeWithOperation
|
||||||
typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, void* extraData);
|
typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, void* extraData);
|
||||||
typedef enum {GRADIENT, RANDOM, NATURAL} creationMode;
|
typedef enum {GRADIENT, RANDOM, NATURAL} creationMode;
|
||||||
|
|
||||||
#define NO_EXISTS_BITS false
|
#define NO_EXISTS_BITS false
|
||||||
#define WANT_EXISTS_BITS true
|
#define WANT_EXISTS_BITS true
|
||||||
#define NO_COLOR false
|
#define NO_COLOR false
|
||||||
#define WANT_COLOR true
|
#define WANT_COLOR true
|
||||||
#define IGNORE_VIEW_FRUSTUM NULL
|
#define IGNORE_VIEW_FRUSTUM NULL
|
||||||
#define JUST_STAGE_DELETION true
|
#define JUST_STAGE_DELETION true
|
||||||
#define ACTUALLY_DELETE false
|
#define ACTUALLY_DELETE false
|
||||||
#define COLLAPSE_EMPTY_TREE true
|
#define COLLAPSE_EMPTY_TREE true
|
||||||
#define DONT_COLLAPSE false
|
#define DONT_COLLAPSE false
|
||||||
|
#define NO_OCCLUSION_CULLING false
|
||||||
|
#define WANT_OCCLUSION_CULLING true
|
||||||
|
#define IGNORE_COVERAGE_MAP NULL
|
||||||
|
#define DONT_CHOP 0
|
||||||
|
|
||||||
class EncodeBitstreamParams {
|
class EncodeBitstreamParams {
|
||||||
public:
|
public:
|
||||||
|
@ -37,6 +42,8 @@ public:
|
||||||
int chopLevels;
|
int chopLevels;
|
||||||
bool deltaViewFrustum;
|
bool deltaViewFrustum;
|
||||||
const ViewFrustum* lastViewFrustum;
|
const ViewFrustum* lastViewFrustum;
|
||||||
|
bool wantOcclusionCulling;
|
||||||
|
CoverageMap* map;
|
||||||
|
|
||||||
EncodeBitstreamParams(
|
EncodeBitstreamParams(
|
||||||
int maxEncodeLevel = INT_MAX,
|
int maxEncodeLevel = INT_MAX,
|
||||||
|
@ -45,7 +52,9 @@ public:
|
||||||
bool includeExistsBits = WANT_EXISTS_BITS,
|
bool includeExistsBits = WANT_EXISTS_BITS,
|
||||||
int chopLevels = 0,
|
int chopLevels = 0,
|
||||||
bool deltaViewFrustum = false,
|
bool deltaViewFrustum = false,
|
||||||
const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM) :
|
const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM,
|
||||||
|
bool wantOcclusionCulling= NO_OCCLUSION_CULLING,
|
||||||
|
CoverageMap* map = IGNORE_COVERAGE_MAP) :
|
||||||
|
|
||||||
maxEncodeLevel (maxEncodeLevel),
|
maxEncodeLevel (maxEncodeLevel),
|
||||||
viewFrustum (viewFrustum),
|
viewFrustum (viewFrustum),
|
||||||
|
@ -53,7 +62,9 @@ public:
|
||||||
includeExistsBits (includeExistsBits),
|
includeExistsBits (includeExistsBits),
|
||||||
chopLevels (chopLevels),
|
chopLevels (chopLevels),
|
||||||
deltaViewFrustum (deltaViewFrustum),
|
deltaViewFrustum (deltaViewFrustum),
|
||||||
lastViewFrustum (lastViewFrustum)
|
lastViewFrustum (lastViewFrustum),
|
||||||
|
wantOcclusionCulling(wantOcclusionCulling),
|
||||||
|
map (map)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <AvatarData.h>
|
#include <AvatarData.h>
|
||||||
#include "VoxelNodeBag.h"
|
#include "VoxelNodeBag.h"
|
||||||
#include "VoxelConstants.h"
|
#include "VoxelConstants.h"
|
||||||
|
#include "CoverageMap.h"
|
||||||
|
|
||||||
class VoxelAgentData : public AvatarData {
|
class VoxelAgentData : public AvatarData {
|
||||||
public:
|
public:
|
||||||
|
@ -36,6 +37,7 @@ public:
|
||||||
void setMaxLevelReached(int maxLevelReached) { _maxLevelReachedInLastSearch = maxLevelReached; }
|
void setMaxLevelReached(int maxLevelReached) { _maxLevelReachedInLastSearch = maxLevelReached; }
|
||||||
|
|
||||||
VoxelNodeBag nodeBag;
|
VoxelNodeBag nodeBag;
|
||||||
|
CoverageMap map;
|
||||||
|
|
||||||
ViewFrustum& getCurrentViewFrustum() { return _currentViewFrustum; };
|
ViewFrustum& getCurrentViewFrustum() { return _currentViewFrustum; };
|
||||||
ViewFrustum& getLastKnownViewFrustum() { return _lastKnownViewFrustum; };
|
ViewFrustum& getLastKnownViewFrustum() { return _lastKnownViewFrustum; };
|
||||||
|
|
|
@ -312,9 +312,13 @@ void deepestLevelVoxelDistributor(AgentList* agentList,
|
||||||
while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) {
|
while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) {
|
||||||
if (!agentData->nodeBag.isEmpty()) {
|
if (!agentData->nodeBag.isEmpty()) {
|
||||||
VoxelNode* subTree = agentData->nodeBag.extract();
|
VoxelNode* subTree = agentData->nodeBag.extract();
|
||||||
|
|
||||||
|
bool wantOcclusionCulling = agentData->getWantOcclusionCulling();
|
||||||
|
CoverageMap* coverageMap = wantOcclusionCulling ? &agentData->map : IGNORE_COVERAGE_MAP;
|
||||||
|
|
||||||
EncodeBitstreamParams params(INT_MAX, &agentData->getCurrentViewFrustum(), agentData->getWantColor(),
|
EncodeBitstreamParams params(INT_MAX, &agentData->getCurrentViewFrustum(), agentData->getWantColor(),
|
||||||
WANT_EXISTS_BITS, wantDelta, lastViewFrustum);
|
WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum,
|
||||||
|
wantOcclusionCulling, coverageMap);
|
||||||
|
|
||||||
bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1,
|
bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1,
|
||||||
agentData->nodeBag, params);
|
agentData->nodeBag, params);
|
||||||
|
@ -375,6 +379,7 @@ void deepestLevelVoxelDistributor(AgentList* agentList,
|
||||||
if (agentData->nodeBag.isEmpty()) {
|
if (agentData->nodeBag.isEmpty()) {
|
||||||
agentData->updateLastKnownViewFrustum();
|
agentData->updateLastKnownViewFrustum();
|
||||||
agentData->setViewSent(true);
|
agentData->setViewSent(true);
|
||||||
|
agentData->map.erase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue