mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 21:36:47 +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
|
// 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
|
// 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.
|
// endcoding. It returns the maximum level that we reached during our search. That might be the maximum level we were asked
|
||||||
void VoxelTree::searchForColoredNodes(VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag) {
|
// 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
|
// 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 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)) {
|
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;
|
const int MAX_CHILDREN = 8;
|
||||||
VoxelNode* inViewChildren[MAX_CHILDREN];
|
VoxelNode* inViewChildren[MAX_CHILDREN];
|
||||||
float distancesToChildren[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
|
// 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
|
// 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.
|
// these based on which tree is closer.
|
||||||
//
|
|
||||||
for (int i = 0; i < inViewCount; i++) {
|
for (int i = 0; i < inViewCount; i++) {
|
||||||
VoxelNode* childNode = inViewChildren[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.
|
// 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
|
// 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
|
// 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
|
// 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,
|
unsigned char* outputBuffer, int availableBytes,
|
||||||
VoxelNodeBag& bag) {
|
VoxelNodeBag& bag) {
|
||||||
|
|
||||||
|
@ -850,7 +875,9 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, const ViewFrustum& viewFrust
|
||||||
bytesWritten += codeLength; // keep track of byte count
|
bytesWritten += codeLength; // keep track of byte count
|
||||||
availableBytes -= codeLength; // keep track or remaining space
|
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);
|
outputBuffer, availableBytes, bag);
|
||||||
|
|
||||||
// if childBytesWritten == 1 then something went wrong... that's not possible
|
// 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
|
// NOTE: This recursive function DOES NOT add the octcode to the buffer. It's assumed that the caller has
|
||||||
// already done that.
|
// 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,
|
unsigned char* outputBuffer, int availableBytes,
|
||||||
VoxelNodeBag& bag) const {
|
VoxelNodeBag& bag) const {
|
||||||
// How many bytes have we written so far at this level;
|
// How many bytes have we written so far at this level;
|
||||||
int bytesAtThisLevel = 0;
|
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!
|
// 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
|
// although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if
|
||||||
// we're out of view
|
// we're out of view
|
||||||
|
@ -1002,7 +1038,10 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum&
|
||||||
|
|
||||||
if (oneAtBit(childrenExistBits, i)) {
|
if (oneAtBit(childrenExistBits, i)) {
|
||||||
VoxelNode* childNode = node->children[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,
|
// 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.
|
||||||
|
|
|
@ -59,18 +59,20 @@ public:
|
||||||
|
|
||||||
void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL);
|
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,
|
unsigned char* outputBuffer, int availableBytes,
|
||||||
VoxelNodeBag& bag);
|
VoxelNodeBag& bag);
|
||||||
|
|
||||||
void searchForColoredNodes(VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag);
|
int searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int encodeTreeBitstreamRecursion(VoxelNode* node, const ViewFrustum& viewFrustum,
|
int encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel,
|
||||||
|
VoxelNode* node, const ViewFrustum& viewFrustum,
|
||||||
unsigned char* outputBuffer, int availableBytes,
|
unsigned char* outputBuffer, int availableBytes,
|
||||||
VoxelNodeBag& bag) const;
|
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);
|
void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData);
|
||||||
VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode);
|
VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode);
|
||||||
|
|
|
@ -20,6 +20,8 @@ void VoxelAgentData::init() {
|
||||||
_voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE];
|
_voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE];
|
||||||
_voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE;
|
_voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE;
|
||||||
_voxelPacketAt = _voxelPacket;
|
_voxelPacketAt = _voxelPacket;
|
||||||
|
_maxSearchLevel = 1;
|
||||||
|
_maxLevelReachedInLastSearch = 1;
|
||||||
resetVoxelPacket();
|
resetVoxelPacket();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,12 @@ public:
|
||||||
int getPacketLength() const { return (MAX_VOXEL_PACKET_SIZE-_voxelPacketAvailableBytes); }
|
int getPacketLength() const { return (MAX_VOXEL_PACKET_SIZE-_voxelPacketAvailableBytes); }
|
||||||
bool isPacketWaiting() const { return _voxelPacketWaiting; }
|
bool isPacketWaiting() const { return _voxelPacketWaiting; }
|
||||||
int getAvailable() const { return _voxelPacketAvailableBytes; }
|
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;
|
VoxelNodeBag nodeBag;
|
||||||
private:
|
private:
|
||||||
|
@ -42,8 +48,8 @@ private:
|
||||||
unsigned char* _voxelPacketAt;
|
unsigned char* _voxelPacketAt;
|
||||||
int _voxelPacketAvailableBytes;
|
int _voxelPacketAvailableBytes;
|
||||||
bool _voxelPacketWaiting;
|
bool _voxelPacketWaiting;
|
||||||
|
int _maxSearchLevel;
|
||||||
|
int _maxLevelReachedInLastSearch;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__hifi__VoxelAgentData__) */
|
#endif /* defined(__hifi__VoxelAgentData__) */
|
||||||
|
|
|
@ -152,7 +152,6 @@ void eraseVoxelTreeAndCleanupAgentVisitData() {
|
||||||
|
|
||||||
|
|
||||||
void newDistributeHelper(AgentList* agentList, AgentList::iterator& agent, VoxelAgentData* agentData, ViewFrustum& viewFrustum) {
|
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
|
// 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
|
// 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
|
// 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
|
// 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
|
// 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.
|
// 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 we have something in our nodeBag, then turn them into packets and send them out...
|
||||||
if (!agentData->nodeBag.isEmpty()) {
|
if (!agentData->nodeBag.isEmpty()) {
|
||||||
|
|
||||||
static unsigned char tempOutputBuffer[MAX_VOXEL_PACKET_SIZE-1]; // save on allocs by making this static
|
static unsigned char tempOutputBuffer[MAX_VOXEL_PACKET_SIZE-1]; // save on allocs by making this static
|
||||||
int bytesWritten = 0;
|
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???
|
// 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")
|
// 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);
|
&tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE-1, agentData->nodeBag);
|
||||||
|
|
||||||
// if we have room in our final packet, add this buffer to the final packet
|
// 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')
|
// reset our finalOutputBuffer (keep the 'V')
|
||||||
agentData->resetVoxelPacket();
|
agentData->resetVoxelPacket();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// and we're done now for this interval, because we know we have not nodes in our
|
// 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;
|
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