added support for LOD scanned sendding order of voxel scene

This commit is contained in:
ZappoMan 2013-04-29 14:34:17 -07:00
parent e7296e1851
commit a638542aa0
5 changed files with 96 additions and 21 deletions

View file

@ -748,22 +748,45 @@ void VoxelTree::createSphere(float r,float xc, float yc, float zc, float s, bool
// This will encode a larger tree into multiple subtree bitstreams. Given a node it will search for deeper subtrees that
// have color. It will search for sub trees, and upon finding a subTree, it will stick the node in the bag to for later
// endcoding.
void VoxelTree::searchForColoredNodes(VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) {
// endcoding. It returns the maximum level that we reached during our search. That might be the maximum level we were asked
// to search (if the tree is deeper than that max level), or it will be the maximum level of the tree (if we asked to search
// deeper than the tree exists).
int VoxelTree::searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) {
// call the recursive version, this will add all found colored node roots to the bag
searchForColoredNodesRecursion(rootNode, viewFrustum, bag);
int currentSearchLevel = 0;
// levelReached will be the maximum level reached. If we made it to the maxSearchLevel, then it will be that.
// but if the tree is shallower than the maxSearchLevel, then we will return the deepest level of the tree that
// exists.
int levelReached = searchForColoredNodesRecursion(maxSearchLevel, currentSearchLevel, rootNode, viewFrustum, bag);
return levelReached;
}
void VoxelTree::searchForColoredNodesRecursion(VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) {
int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel,
VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) {
// Keep track of how deep we've searched.
currentSearchLevel++;
// If we've reached our max Search Level, then stop searching.
if (currentSearchLevel >= maxSearchLevel) {
return currentSearchLevel;
}
// If we're at a node that is out of view, then we can return, because no nodes below us will be in view!
if (!node->isInView(viewFrustum)) {
return;
return currentSearchLevel;
}
// Ok, this is a little tricky, each child may have been deeper than the others, so we need to track
// how deep each child went. And we actually return the maximum of each child. We use these variables below
// when we recurse the children.
int thisLevel = currentSearchLevel;
int maxChildLevel = thisLevel;
const int MAX_CHILDREN = 8;
VoxelNode* inViewChildren[MAX_CHILDREN];
float distancesToChildren[MAX_CHILDREN];
@ -812,12 +835,14 @@ void VoxelTree::searchForColoredNodesRecursion(VoxelNode* node, const ViewFrustu
// at this point, we need to iterate the children who are in view, even if not colored
// and we need to determine if there's a deeper tree below them that we care about. We will iterate
// these based on which tree is closer.
//
for (int i = 0; i < inViewCount; i++) {
VoxelNode* childNode = inViewChildren[i];
searchForColoredNodesRecursion(childNode, viewFrustum, bag);
thisLevel = currentSearchLevel; // reset this, since the children will munge it up
int childLevelReached = searchForColoredNodesRecursion(maxSearchLevel, thisLevel, childNode, viewFrustum, bag);
maxChildLevel = std::max(maxChildLevel, childLevelReached);
}
}
return maxChildLevel;
}
// This will encode a tree bitstream, given a node it will encode the full tree from that point onward.
@ -830,7 +855,7 @@ void VoxelTree::searchForColoredNodesRecursion(VoxelNode* node, const ViewFrustu
// extraTrees is assumed to me an allocated array of VoxelNode*, if we're unable to fully encode the tree
// because we run out of room on the outputBuffer, then we will add VoxelNode*'s of the trees that need
// to be encoded to that array. If the array
int VoxelTree::encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrustum,
int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, const ViewFrustum& viewFrustum,
unsigned char* outputBuffer, int availableBytes,
VoxelNodeBag& bag) {
@ -850,7 +875,9 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrust
bytesWritten += codeLength; // keep track of byte count
availableBytes -= codeLength; // keep track or remaining space
int childBytesWritten = encodeTreeBitstreamRecursion(node, viewFrustum,
int currentEncodeLevel = 0;
int childBytesWritten = encodeTreeBitstreamRecursion(maxEncodeLevel, currentEncodeLevel,
node, viewFrustum,
outputBuffer, availableBytes, bag);
// if childBytesWritten == 1 then something went wrong... that's not possible
@ -878,12 +905,21 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrust
//
// NOTE: This recursive function DOES NOT add the octcode to the buffer. It's assumed that the caller has
// already done that.
int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& viewFrustum,
int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel,
VoxelNode* node, const ViewFrustum& viewFrustum,
unsigned char* outputBuffer, int availableBytes,
VoxelNodeBag& bag) const {
// How many bytes have we written so far at this level;
int bytesAtThisLevel = 0;
// Keep track of how deep we've encoded.
currentEncodeLevel++;
// If we've reached our max Search Level, then stop searching.
if (currentEncodeLevel >= maxEncodeLevel) {
return bytesAtThisLevel;
}
// If we're at a node that is out of view, then we can return, because no nodes below us will be in view!
// although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if
// we're out of view
@ -1002,7 +1038,10 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum&
if (oneAtBit(childrenExistBits, i)) {
VoxelNode* childNode = node->children[i];
int childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, viewFrustum, outputBuffer, availableBytes, bag);
int thisLevel = currentEncodeLevel;
int childTreeBytesOut = encodeTreeBitstreamRecursion(maxEncodeLevel, thisLevel,
childNode, viewFrustum, outputBuffer, availableBytes, bag);
// 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.

View file

@ -59,18 +59,20 @@ public:
void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL);
int encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrustum,
int encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, const ViewFrustum& viewFrustum,
unsigned char* outputBuffer, int availableBytes,
VoxelNodeBag& bag);
void searchForColoredNodes(VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag);
int searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag);
private:
int encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& viewFrustum,
int encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel,
VoxelNode* node, const ViewFrustum& viewFrustum,
unsigned char* outputBuffer, int availableBytes,
VoxelNodeBag& bag) const;
void searchForColoredNodesRecursion(VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag);
int searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel,
VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag);
void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData);
VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode);

View file

@ -20,6 +20,8 @@ void VoxelAgentData::init() {
_voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE];
_voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE;
_voxelPacketAt = _voxelPacket;
_maxSearchLevel = 1;
_maxLevelReachedInLastSearch = 1;
resetVoxelPacket();
}

View file

@ -35,6 +35,12 @@ public:
int getPacketLength() const { return (MAX_VOXEL_PACKET_SIZE-_voxelPacketAvailableBytes); }
bool isPacketWaiting() const { return _voxelPacketWaiting; }
int getAvailable() const { return _voxelPacketAvailableBytes; }
int getMaxSearchLevel() const { return _maxSearchLevel; };
void resetMaxSearchLevel() { _maxSearchLevel = 1; };
void incrementMaxSearchLevel() { _maxSearchLevel++; };
int getMaxLevelReached() const { return _maxLevelReachedInLastSearch; };
void setMaxLevelReached(int maxLevelReached) { _maxLevelReachedInLastSearch = maxLevelReached; }
VoxelNodeBag nodeBag;
private:
@ -42,8 +48,8 @@ private:
unsigned char* _voxelPacketAt;
int _voxelPacketAvailableBytes;
bool _voxelPacketWaiting;
int _maxSearchLevel;
int _maxLevelReachedInLastSearch;
};
#endif /* defined(__hifi__VoxelAgentData__) */

View file

@ -152,7 +152,6 @@ void eraseVoxelTreeAndCleanupAgentVisitData() {
void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, VoxelAgentData* agentData, ViewFrustum& viewFrustum) {
// A quick explanation of the strategy here. First, each time through, we ask ourselves, do we have voxels
// that need to be sent? If not, we search for them, if we do, then we send them. We store our to be sent voxel sub trees
// in a VoxelNodeBag on a per agent basis. The bag stores just pointers to the root node of the sub tree to be sent, so
@ -185,12 +184,28 @@ void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Voxel
// can include the siblings. Since dense trees take more space per ranch, we often end up only being able to encode a
// single branch. This means on a per packet basis, the trees actually _are not_ dense. And sparse trees are shorter to
// encode when we only include the child tree.
randomTree.searchForColoredNodes(randomTree.rootNode, viewFrustum, agentData->nodeBag);
//
// Now, a quick explanation of maxSearchLevel: We will actually send the entire scene, multiple times for each search
// level. We start at level 1, and we scan the scene for this level, then we increment to the next level until we've
// sent the entire scene at it's deepest possible level. This means that clients will get an initial view of the scene
// with chunky granularity and then finer and finer granularity until they've gotten the whole scene. Then we start
// over to handle packet loss and changes in the scene.
int maxLevelReached = randomTree.searchForColoredNodes(agentData->getMaxSearchLevel(), randomTree.rootNode,
viewFrustum, agentData->nodeBag);
agentData->setMaxLevelReached(maxLevelReached);
// If nothing got added, then we bump our levels.
if (agentData->nodeBag.isEmpty()) {
if (agentData->getMaxLevelReached() < agentData->getMaxSearchLevel()) {
agentData->resetMaxSearchLevel();
} else {
agentData->incrementMaxSearchLevel();
}
}
}
// If we have something in our nodeBag, then turn them into packets and send them out...
if (!agentData->nodeBag.isEmpty()) {
static unsigned char tempOutputBuffer[MAX_VOXEL_PACKET_SIZE-1]; // save on allocs by making this static
int bytesWritten = 0;
@ -203,7 +218,7 @@ void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Voxel
// Only let this guy create at largest packets equal to the amount of space we have left in our final???
// Or let it create the largest possible size (minus 1 for the "V")
bytesWritten = randomTree.encodeTreeBitstream(subTree, viewFrustum,
bytesWritten = randomTree.encodeTreeBitstream(agentData->getMaxSearchLevel(), subTree, viewFrustum,
&tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE-1, agentData->nodeBag);
// if we have room in our final packet, add this buffer to the final packet
@ -232,6 +247,7 @@ void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Voxel
// reset our finalOutputBuffer (keep the 'V')
agentData->resetVoxelPacket();
}
// and we're done now for this interval, because we know we have not nodes in our
@ -240,6 +256,16 @@ void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, Voxel
packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL;
}
}
// Ok, so we're in the "send from our bag mode"... if during this last pass, we emptied our bag, then
// we want to move to the next level.
if (agentData->nodeBag.isEmpty()) {
if (agentData->getMaxLevelReached() < agentData->getMaxSearchLevel()) {
agentData->resetMaxSearchLevel();
} else {
agentData->incrementMaxSearchLevel();
}
}
}
}