Merge pull request #655 from ZappoMan/occlusion_culling

Make Delta Sending Default, Added option for "Low Res" mode while moving
This commit is contained in:
Andrzej Kapolka 2013-07-11 14:08:22 -07:00
commit c3242598f5
10 changed files with 129 additions and 51 deletions

View file

@ -1236,12 +1236,16 @@ void Application::doTreeStats() {
_voxels.collectStatsForTreesAndVBOs();
}
void Application::setWantsLowResMoving(bool wantsLowResMoving) {
_myAvatar.setWantLowResMoving(wantsLowResMoving);
}
void Application::setWantsMonochrome(bool wantsMonochrome) {
_myAvatar.setWantColor(!wantsMonochrome);
}
void Application::setWantsDelta(bool wantsDelta) {
_myAvatar.setWantDelta(wantsDelta);
void Application::disableDeltaSending(bool disableDeltaSending) {
_myAvatar.setWantDelta(!disableDeltaSending);
}
void Application::disableOcclusionCulling(bool disableOcclusionCulling) {
@ -1635,9 +1639,11 @@ void Application::initMenu() {
renderDebugMenu->addAction("FALSE Color Occluded V2 Voxels", this, SLOT(doFalseColorizeOccludedV2()), Qt::CTRL | Qt::Key_P);
renderDebugMenu->addAction("Show TRUE Colors", this, SLOT(doTrueVoxelColors()), Qt::CTRL | Qt::Key_T);
debugMenu->addAction("Wants Monochrome", this, SLOT(setWantsMonochrome(bool)))->setCheckable(true);
debugMenu->addAction("Wants View Delta Sending", this, SLOT(setWantsDelta(bool)))->setCheckable(true);
(_shouldLowPassFilter = debugMenu->addAction("Test: LowPass filter"))->setCheckable(true);
debugMenu->addAction("Wants Monochrome", this, SLOT(setWantsMonochrome(bool)))->setCheckable(true);
debugMenu->addAction("Use Lower Resolution While Moving", this, SLOT(setWantsLowResMoving(bool)))->setCheckable(true);
debugMenu->addAction("Disable Delta Sending", this, SLOT(disableDeltaSending(bool)))->setCheckable(true);
debugMenu->addAction("Disable Occlusion Culling", this, SLOT(disableOcclusionCulling(bool)),
Qt::SHIFT | Qt::Key_C)->setCheckable(true);

View file

@ -136,7 +136,8 @@ private slots:
void doTrueVoxelColors();
void doTreeStats();
void setWantsMonochrome(bool wantsMonochrome);
void setWantsDelta(bool wantsDelta);
void setWantsLowResMoving(bool wantsLowResMoving);
void disableDeltaSending(bool disableDeltaSending);
void disableOcclusionCulling(bool disableOcclusionCulling);
void updateVoxelModeActions();
void decreaseVoxelSize();

View file

@ -891,13 +891,11 @@ bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) {
bool VoxelSystem::isViewChanging() {
bool result = false; // assume the best
/** TEMPORARY HACK ******
// If our viewFrustum has changed since our _lastKnowViewFrustum
if (_viewFrustum && !_lastKnowViewFrustum.matches(_viewFrustum)) {
if (!_lastKnowViewFrustum.matches(Application::getInstance()->getViewFrustum())) {
result = true;
_lastKnowViewFrustum = *_viewFrustum; // save last known
_lastKnowViewFrustum = *Application::getInstance()->getViewFrustum(); // save last known
}
**/
return result;
}

View file

@ -33,7 +33,8 @@ AvatarData::AvatarData(Node* owningNode) :
_cameraFarClip(0.0f),
_keyState(NO_KEY_DOWN),
_wantColor(true),
_wantDelta(false),
_wantDelta(true),
_wantLowResMoving(false),
_wantOcclusionCulling(true),
_headData(NULL),
_handData(NULL)
@ -112,8 +113,9 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
// bitMask of less than byte wide items
unsigned char bitItems = 0;
if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); }
if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); }
if (_wantLowResMoving) { setAtBit(bitItems, WANT_LOW_RES_MOVING_BIT); }
if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); }
if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); }
if (_wantOcclusionCulling) { setAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); }
// key state
@ -239,8 +241,9 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
// voxel sending features...
unsigned char bitItems = 0;
bitItems = (unsigned char)*sourceBuffer++;
_wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT);
_wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT);
_wantLowResMoving = oneAtBit(bitItems, WANT_LOW_RES_MOVING_BIT);
_wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT);
_wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT);
_wantOcclusionCulling = oneAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT);
// key state, stored as a semi-nibble in the bitItems

View file

@ -20,7 +20,7 @@
#include "HeadData.h"
#include "HandData.h"
const int UNUSED_BIT = 0; // this bit is available to use
const int WANT_LOW_RES_MOVING_BIT = 0;
const int WANT_COLOR_AT_BIT = 1;
const int WANT_DELTA_AT_BIT = 2;
const int KEY_STATE_START_BIT = 3; // 4th and 5th bits
@ -91,11 +91,14 @@ public:
const std::string& chatMessage () const { return _chatMessage; }
// related to Voxel Sending strategies
bool getWantColor() const { return _wantColor; }
bool getWantDelta() const { return _wantDelta; }
bool getWantColor() const { return _wantColor; }
bool getWantDelta() const { return _wantDelta; }
bool getWantLowResMoving() const { return _wantLowResMoving; }
bool getWantOcclusionCulling() const { return _wantOcclusionCulling; }
void setWantColor(bool wantColor) { _wantColor = wantColor; }
void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; }
void setWantColor(bool wantColor) { _wantColor = wantColor; }
void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; }
void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; }
void setWantOcclusionCulling(bool wantOcclusionCulling) { _wantOcclusionCulling = wantOcclusionCulling; }
void setHeadData(HeadData* headData) { _headData = headData; }
@ -130,6 +133,7 @@ protected:
// voxel server sending items
bool _wantColor;
bool _wantDelta;
bool _wantLowResMoving;
bool _wantOcclusionCulling;
std::vector<JointData> _joints;

View file

@ -1169,7 +1169,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
// caller can pass NULL as viewFrustum if they want everything
if (params.viewFrustum) {
float distance = node->distanceToCamera(*params.viewFrustum);
float boundaryDistance = boundaryDistanceForRenderLevel(*node->getOctalCode() + 1);
float boundaryDistance = boundaryDistanceForRenderLevel(node->getLevel() + params.boundaryLevelAdjust);
// If we're too far away for our render level, then just return
if (distance >= boundaryDistance) {
@ -1182,7 +1182,26 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
if (!node->isInView(*params.viewFrustum)) {
return bytesAtThisLevel;
}
// Ok, we are in view, but if we're in delta mode, then we also want to make sure we weren't already in view
// because we don't send nodes from the previously know in view frustum.
bool wasInView = false;
if (params.deltaViewFrustum && params.lastViewFrustum) {
ViewFrustum::location location = node->inFrustum(*params.lastViewFrustum);
// If we're a leaf, then either intersect or inside is considered "formerly in view"
if (node->isLeaf()) {
wasInView = location != ViewFrustum::OUTSIDE;
} else {
wasInView = location == ViewFrustum::INSIDE;
}
}
// If we were in view, then bail out early!
if (wasInView) {
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
@ -1200,16 +1219,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
CoverageMapStorageResult result = params.map->checkMap(voxelPolygon, false);
delete voxelPolygon; // cleanup
if (result == 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 voxelPolygon;
@ -1285,7 +1297,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
if (childIsInView) {
// Before we determine consider this further, let's see if it's in our LOD scope...
float distance = distancesToChildren[i]; // params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0;
float boundaryDistance = params.viewFrustum ? boundaryDistanceForRenderLevel(*childNode->getOctalCode() + 1) : 1;
float boundaryDistance = !params.viewFrustum ? 1 :
boundaryDistanceForRenderLevel(childNode->getLevel() + params.boundaryLevelAdjust);
if (distance < boundaryDistance) {
inViewCount++;
@ -1341,7 +1354,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp
if (params.viewFrustum && childNode->isColored() && !childNode->isLeaf()) {
int grandChildrenInView = 0;
int grandChildrenInLOD = 0;
float grandChildBoundaryDistance = boundaryDistanceForRenderLevel(childNode->getLevel() + 2);
float grandChildBoundaryDistance = boundaryDistanceForRenderLevel(childNode->getLevel() +
1 + params.boundaryLevelAdjust);
for (int grandChildIndex = 0; grandChildIndex < NUMBER_OF_CHILDREN; grandChildIndex++) {
VoxelNode* grandChild = childNode->getChildAtIndex(grandChildIndex);

View file

@ -33,6 +33,8 @@ typedef enum {GRADIENT, RANDOM, NATURAL} creationMode;
#define WANT_OCCLUSION_CULLING true
#define IGNORE_COVERAGE_MAP NULL
#define DONT_CHOP 0
#define NO_BOUNDARY_ADJUST 0
#define LOW_RES_MOVING_ADJUST 1
class EncodeBitstreamParams {
public:
@ -46,6 +48,7 @@ public:
const ViewFrustum* lastViewFrustum;
bool wantOcclusionCulling;
long childWasInViewDiscarded;
int boundaryLevelAdjust;
CoverageMap* map;
@ -58,18 +61,20 @@ public:
bool deltaViewFrustum = false,
const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM,
bool wantOcclusionCulling= NO_OCCLUSION_CULLING,
CoverageMap* map = IGNORE_COVERAGE_MAP) :
maxEncodeLevel (maxEncodeLevel),
maxLevelReached (0),
viewFrustum (viewFrustum),
includeColor (includeColor),
includeExistsBits (includeExistsBits),
chopLevels (chopLevels),
deltaViewFrustum (deltaViewFrustum),
lastViewFrustum (lastViewFrustum),
wantOcclusionCulling(wantOcclusionCulling),
childWasInViewDiscarded(0),
map (map)
CoverageMap* map = IGNORE_COVERAGE_MAP,
int boundaryLevelAdjust = NO_BOUNDARY_ADJUST) :
maxEncodeLevel (maxEncodeLevel),
maxLevelReached (0),
viewFrustum (viewFrustum),
includeColor (includeColor),
includeExistsBits (includeExistsBits),
chopLevels (chopLevels),
deltaViewFrustum (deltaViewFrustum),
lastViewFrustum (lastViewFrustum),
wantOcclusionCulling (wantOcclusionCulling),
childWasInViewDiscarded (0),
boundaryLevelAdjust (boundaryLevelAdjust),
map (map)
{}
};

View file

@ -17,7 +17,9 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) :
_voxelPacketAvailableBytes(MAX_VOXEL_PACKET_SIZE),
_maxSearchLevel(1),
_maxLevelReachedInLastSearch(1),
_lastTimeBagEmpty(0)
_lastTimeBagEmpty(0),
_viewFrustumChanging(false),
_currentPacketIsColor(true)
{
_voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE];
_voxelPacketAt = _voxelPacket;
@ -27,7 +29,10 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) :
void VoxelNodeData::resetVoxelPacket() {
PACKET_TYPE voxelPacketType = getWantColor() ? PACKET_TYPE_VOXEL_DATA : PACKET_TYPE_VOXEL_DATA_MONOCHROME;
// If we're moving, and the client asked for low res, then we force monochrome, otherwise, use
// the clients requested color state.
_currentPacketIsColor = (getWantLowResMoving() && _viewFrustumChanging) ? false : getWantColor();
PACKET_TYPE voxelPacketType = _currentPacketIsColor ? PACKET_TYPE_VOXEL_DATA : PACKET_TYPE_VOXEL_DATA_MONOCHROME;
int numBytesPacketHeader = populateTypeAndVersion(_voxelPacket, voxelPacketType);
_voxelPacketAt = _voxelPacket + numBytesPacketHeader;
_voxelPacketAvailableBytes = MAX_VOXEL_PACKET_SIZE - numBytesPacketHeader;
@ -64,6 +69,7 @@ bool VoxelNodeData::updateCurrentViewFrustum() {
_currentViewFrustum.calculate();
currentViewFrustumChanged = true;
}
_viewFrustumChanging = currentViewFrustumChanged;
return currentViewFrustumChanged;
}

View file

@ -53,6 +53,7 @@ public:
uint64_t getLastTimeBagEmpty() const { return _lastTimeBagEmpty; };
void setLastTimeBagEmpty(uint64_t lastTimeBagEmpty) { _lastTimeBagEmpty = lastTimeBagEmpty; };
bool getCurrentPacketIsColor() const { return _currentPacketIsColor; };
private:
VoxelNodeData(const VoxelNodeData &);
VoxelNodeData& operator= (const VoxelNodeData&);
@ -67,7 +68,8 @@ private:
ViewFrustum _currentViewFrustum;
ViewFrustum _lastKnownViewFrustum;
uint64_t _lastTimeBagEmpty;
bool _viewFrustumChanging;
bool _currentPacketIsColor;
};
#endif /* defined(__hifi__VoxelNodeData__) */

View file

@ -123,9 +123,47 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
int maxLevelReached = 0;
uint64_t start = usecTimestampNow();
int truePacketsSent = 0;
int trueBytesSent = 0;
// FOR NOW... node tells us if it wants to receive only view frustum deltas
bool wantDelta = viewFrustumChanged && nodeData->getWantDelta();
// If our packet already has content in it, then we must use the color choice of the waiting packet.
// If we're starting a fresh packet, then...
// If we're moving, and the client asked for low res, then we force monochrome, otherwise, use
// the clients requested color state.
bool wantColor = ((nodeData->getWantLowResMoving() && viewFrustumChanged) ? false : nodeData->getWantColor());
// If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color
// then let's just send that waiting packet.
if (wantColor != nodeData->getCurrentPacketIsColor()) {
if (nodeData->isPacketWaiting()) {
if (::debugVoxelSending) {
printf("wantColor=%s --- SENDING PARTIAL PACKET! nodeData->getCurrentPacketIsColor()=%s\n",
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()));
}
nodeList->getNodeSocket()->send(node->getActiveSocket(),
nodeData->getPacket(), nodeData->getPacketLength());
trueBytesSent += nodeData->getPacketLength();
truePacketsSent++;
nodeData->resetVoxelPacket();
} else {
if (::debugVoxelSending) {
printf("wantColor=%s --- FIXING HEADER! nodeData->getCurrentPacketIsColor()=%s\n",
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()));
}
nodeData->resetVoxelPacket();
}
}
if (::debugVoxelSending) {
printf("wantColor=%s getCurrentPacketIsColor()=%s, viewFrustumChanged=%s, getWantLowResMoving()=%s\n",
debug::valueOf(wantColor), debug::valueOf(nodeData->getCurrentPacketIsColor()),
debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->getWantLowResMoving()));
}
const ViewFrustum* lastViewFrustum = wantDelta ? &nodeData->getLastKnownViewFrustum() : NULL;
if (::debugVoxelSending) {
@ -149,9 +187,11 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
} else {
printf("elapsed time to send scene = %f seconds", elapsedSceneSend);
}
printf(" [occlusionCulling: %s]\n", debug::valueOf(nodeData->getWantOcclusionCulling()));
printf(" [occlusionCulling:%s, wantDelta:%s, wantColor:%s ]\n",
debug::valueOf(nodeData->getWantOcclusionCulling()), debug::valueOf(wantDelta),
debug::valueOf(wantColor));
}
nodeData->setLastTimeBagEmpty(now);
nodeData->setLastTimeBagEmpty(now); // huh? why is this inside debug? probably not what we want
}
// if our view has changed, we need to reset these things...
@ -199,8 +239,6 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
static unsigned char tempOutputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static
int bytesWritten = 0;
int packetsSentThisInterval = 0;
int truePacketsSent = 0;
int trueBytesSent = 0;
uint64_t start = usecTimestampNow();
bool shouldSendEnvironments = shouldDo(ENVIRONMENT_SEND_INTERVAL_USECS, VOXEL_SEND_INTERVAL_USECS);
@ -224,10 +262,12 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
VoxelNode* subTree = nodeData->nodeBag.extract();
bool wantOcclusionCulling = nodeData->getWantOcclusionCulling();
CoverageMap* coverageMap = wantOcclusionCulling ? &nodeData->map : IGNORE_COVERAGE_MAP;
int boundaryLevelAdjust = viewFrustumChanged && nodeData->getWantLowResMoving()
? LOW_RES_MOVING_ADJUST : NO_BOUNDARY_ADJUST;
EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), nodeData->getWantColor(),
EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor,
WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum,
wantOcclusionCulling, coverageMap);
wantOcclusionCulling, coverageMap, boundaryLevelAdjust);
bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1,
nodeData->nodeBag, params);
@ -254,7 +294,6 @@ void deepestLevelVoxelDistributor(NodeList* nodeList,
trueBytesSent += nodeData->getPacketLength();
truePacketsSent++;
nodeData->resetVoxelPacket();
}
packetsSentThisInterval = PACKETS_PER_CLIENT_PER_INTERVAL; // done for now, no nodes left
}