mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 15:13:09 +02:00
added support for LOD scanned sendding order of voxel scene
This commit is contained in:
parent
e7296e1851
commit
a638542aa0
5 changed files with 96 additions and 21 deletions
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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__) */
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue