From 538fc897392e9e16e3ab2e1500bc017970f6d56d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 26 May 2013 13:11:54 -0700 Subject: [PATCH 01/41] first cut at dirty bit sending support --- libraries/voxels/src/VoxelNode.cpp | 10 ++++++++++ libraries/voxels/src/VoxelNode.h | 4 ++++ libraries/voxels/src/VoxelTree.cpp | 13 ++++++++----- libraries/voxels/src/VoxelTree.h | 6 ++++-- voxel-server/src/VoxelAgentData.cpp | 7 +++++++ voxel-server/src/VoxelAgentData.h | 4 ++++ voxel-server/src/main.cpp | 3 ++- 7 files changed, 39 insertions(+), 8 deletions(-) diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index f542fe0dd4..a9a1f4eb12 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -47,6 +47,8 @@ void VoxelNode::init(unsigned char * octalCode) { _shouldRender = false; _isStagedForDeletion = false; + _lastChanged = usecTimestampNow(); + calculateAABox(); } @@ -66,6 +68,7 @@ void VoxelNode::setShouldRender(bool shouldRender) { if (shouldRender != _shouldRender) { _shouldRender = shouldRender; _isDirty = true; + _lastChanged = usecTimestampNow(); } } @@ -89,6 +92,7 @@ void VoxelNode::deleteChildAtIndex(int childIndex) { delete _children[childIndex]; _children[childIndex] = NULL; _isDirty = true; + _lastChanged = usecTimestampNow(); _childCount--; } } @@ -99,6 +103,7 @@ VoxelNode* VoxelNode::removeChildAtIndex(int childIndex) { if (_children[childIndex]) { _children[childIndex] = NULL; _isDirty = true; + _lastChanged = usecTimestampNow(); _childCount--; } return returnedChild; @@ -108,6 +113,7 @@ void VoxelNode::addChildAtIndex(int childIndex) { if (!_children[childIndex]) { _children[childIndex] = new VoxelNode(childOctalCode(_octalCode, childIndex)); _isDirty = true; + _lastChanged = usecTimestampNow(); _childCount++; } } @@ -135,6 +141,7 @@ void VoxelNode::safeDeepDeleteChildAtIndex(int childIndex, bool& stagedForDeleti deleteChildAtIndex(childIndex); _isDirty = true; } + _lastChanged = usecTimestampNow(); } } @@ -178,6 +185,7 @@ void VoxelNode::setFalseColor(colorPart red, colorPart green, colorPart blue) { _currentColor[2] = blue; _currentColor[3] = 1; // XXXBHG - False colors are always considered set _isDirty = true; + _lastChanged = usecTimestampNow(); } } @@ -189,6 +197,7 @@ void VoxelNode::setFalseColored(bool isFalseColored) { } _falseColored = isFalseColored; _isDirty = true; + _lastChanged = usecTimestampNow(); } }; @@ -202,6 +211,7 @@ void VoxelNode::setColor(const nodeColor& color) { memcpy(&_currentColor,&color,sizeof(nodeColor)); } _isDirty = true; + _lastChanged = usecTimestampNow(); } } #endif diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 1b21962261..ca00260ace 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -36,6 +36,8 @@ private: void calculateAABox(); void init(unsigned char * octalCode); + + double _lastChanged; public: VoxelNode(); // root node constructor @@ -75,6 +77,8 @@ public: void printDebugDetails(const char* label) const; bool isDirty() const { return _isDirty; }; void clearDirtyBit() { _isDirty = false; }; + bool hasChangedSince(double time) const { return (_lastChanged > time); }; + glBufferIndex getBufferIndex() const { return _glBufferIndex; }; bool isKnownBufferIndex() const { return (_glBufferIndex != GLBUFFER_INDEX_UNKNOWN); }; void setBufferIndex(glBufferIndex index) { _glBufferIndex = index; }; diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 798b447d6c..41782a3d2b 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -862,7 +862,8 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor, bool includeExistsBits, - bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const { + bool deltaViewFrustum, const ViewFrustum* lastViewFrustum, + double lastViewFrustumSent) const { // How many bytes have we written so far at this level; int bytesWritten = 0; @@ -883,7 +884,7 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned int currentEncodeLevel = 0; int childBytesWritten = encodeTreeBitstreamRecursion(maxEncodeLevel, currentEncodeLevel, node, outputBuffer, availableBytes, bag, viewFrustum, includeColor, includeExistsBits, - deltaViewFrustum, lastViewFrustum); + deltaViewFrustum, lastViewFrustum, lastViewFrustumSent); // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); @@ -907,7 +908,8 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor, bool includeExistsBits, - bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const { + bool deltaViewFrustum, const ViewFrustum* lastViewFrustum, + double lastViewFrustumSent) const { // How many bytes have we written so far at this level; int bytesAtThisLevel = 0; @@ -992,7 +994,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco (lastViewFrustum && ViewFrustum::INSIDE == childNode->inFrustum(*lastViewFrustum))); // track children with actual color, only if the child wasn't previously in view! - if (childNode && childNode->isColored() && !childWasInView) { + if (childNode && childNode->isColored() && + (!childWasInView || childNode->hasChangedSince(lastViewFrustumSent) )) { childrenColoredBits += (1 << (7 - i)); inViewWithColorCount++; } @@ -1063,7 +1066,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco int childTreeBytesOut = encodeTreeBitstreamRecursion(maxEncodeLevel, thisLevel, childNode, outputBuffer, availableBytes, bag, viewFrustum, includeColor, includeExistsBits, - deltaViewFrustum, lastViewFrustum); + deltaViewFrustum, lastViewFrustum, lastViewFrustumSent); // 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. diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 0643b1038e..0d774ebbad 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -71,7 +71,8 @@ public: int encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, - bool deltaViewFrustum = false, const ViewFrustum* lastViewFrustum = NULL) const; + bool deltaViewFrustum = false, const ViewFrustum* lastViewFrustum = NULL, + double lastViewFrustumSent = 0) const; int searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag, bool deltaViewFrustum = false, const ViewFrustum* lastViewFrustum = NULL); @@ -100,7 +101,8 @@ private: int encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor, bool includeExistsBits, - bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const; + bool deltaViewFrustum, const ViewFrustum* lastViewFrustum, + double lastViewFrustumSent) const; int searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag, diff --git a/voxel-server/src/VoxelAgentData.cpp b/voxel-server/src/VoxelAgentData.cpp index 082fc5e7fc..0ca7778a94 100644 --- a/voxel-server/src/VoxelAgentData.cpp +++ b/voxel-server/src/VoxelAgentData.cpp @@ -8,6 +8,7 @@ #include "PacketHeaders.h" #include "VoxelAgentData.h" +#include "SharedUtil.h" #include #include @@ -20,6 +21,7 @@ VoxelAgentData::VoxelAgentData(Agent* owningAgent) : { _voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; _voxelPacketAt = _voxelPacket; + _lastViewFrustumSent = 0; resetVoxelPacket(); } @@ -72,5 +74,10 @@ void VoxelAgentData::updateLastKnownViewFrustum() { // save our currentViewFrustum into our lastKnownViewFrustum _lastKnownViewFrustum = _currentViewFrustum; } + + // save that we know the view has been sent. + double now = usecTimestampNow(); + printf("updateLastKnownViewFrustum() setLastViewSent() to %lf\n", now); + setLastViewSent(now); } diff --git a/voxel-server/src/VoxelAgentData.h b/voxel-server/src/VoxelAgentData.h index 2afc64a6c8..04da24ea6b 100644 --- a/voxel-server/src/VoxelAgentData.h +++ b/voxel-server/src/VoxelAgentData.h @@ -48,6 +48,9 @@ public: bool getViewSent() const { return _viewSent; }; void setViewSent(bool viewSent) { _viewSent = viewSent; } + double getLastViewSent() const { return _lastViewFrustumSent; }; + void setLastViewSent(double viewSent) { _lastViewFrustumSent = viewSent; } + private: VoxelAgentData(const VoxelAgentData &); VoxelAgentData& operator= (const VoxelAgentData&); @@ -61,6 +64,7 @@ private: int _maxLevelReachedInLastSearch; ViewFrustum _currentViewFrustum; ViewFrustum _lastKnownViewFrustum; + double _lastViewFrustumSent; }; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 1a93021f09..098596f02e 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -314,7 +314,7 @@ void deepestLevelVoxelDistributor(AgentList* agentList, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, agentData->nodeBag, &agentData->getCurrentViewFrustum(), agentData->getWantColor(), WANT_EXISTS_BITS, - wantDelta, lastViewFrustum); + wantDelta, lastViewFrustum, agentData->getLastViewSent()); if (agentData->getAvailable() >= bytesWritten) { agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten); @@ -370,6 +370,7 @@ void deepestLevelVoxelDistributor(AgentList* agentList, // if after sending packets we've emptied our bag, then we want to remember that we've sent all // the voxels from the current view frustum if (agentData->nodeBag.isEmpty()) { +printf("agentData->nodeBag.isEmpty()...\n"); agentData->updateLastKnownViewFrustum(); agentData->setViewSent(true); } From 12dc11fbfae108f170b05ef5aa9b00e610c2dd0c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 27 May 2013 09:56:35 -0700 Subject: [PATCH 02/41] Optimize View Frustum wire format. - Changed View frstum orientaton to be a quaternion - Implemented packing formats for Orientation Quats, Ratios, and Clipping values - Changed wire format for View Frustum details to be more efficient 28 bytes vs 64 bytes --- interface/src/Application.cpp | 8 +- interface/src/Avatar.cpp | 2 +- interface/src/Head.cpp | 4 +- libraries/avatars/src/AvatarData.cpp | 167 +++++++++++++++++++-------- libraries/avatars/src/AvatarData.h | 50 +++++--- libraries/shared/src/SharedUtil.cpp | 1 + libraries/shared/src/SharedUtil.h | 1 + libraries/voxels/src/ViewFrustum.cpp | 42 +++++-- libraries/voxels/src/ViewFrustum.h | 29 ++--- voxel-server/src/VoxelAgentData.cpp | 2 +- 10 files changed, 210 insertions(+), 96 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a0979eb4b9..790a7f9495 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1092,7 +1092,7 @@ static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) { void Application::addVoxelInFrontOfAvatar() { VoxelDetail detail; - glm::vec3 position = (_myAvatar.getPosition() + _myAvatar.getCameraDirection()) * (1.0f / TREE_SCALE); + glm::vec3 position = (_myAvatar.getPosition() + _myAvatar.calculateCameraDirection()) * (1.0f / TREE_SCALE); detail.s = _mouseVoxelScale; detail.x = detail.s * floor(position.x / detail.s); @@ -1347,9 +1347,7 @@ void Application::updateAvatar(float deltaTime) { // to the server. loadViewFrustum(_myCamera, _viewFrustum); _myAvatar.setCameraPosition(_viewFrustum.getPosition()); - _myAvatar.setCameraDirection(_viewFrustum.getDirection()); - _myAvatar.setCameraUp(_viewFrustum.getUp()); - _myAvatar.setCameraRight(_viewFrustum.getRight()); + _myAvatar.setCameraOrientation(_viewFrustum.getOrientation()); _myAvatar.setCameraFov(_viewFrustum.getFieldOfView()); _myAvatar.setCameraAspectRatio(_viewFrustum.getAspectRatio()); _myAvatar.setCameraNearClip(_viewFrustum.getNearClip()); @@ -1435,7 +1433,7 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { // Set the viewFrustum up with the correct position and orientation of the camera viewFrustum.setPosition(position); - viewFrustum.setOrientation(direction,up,right); + viewFrustum.setOrientation(o.getQuat()); // Also make sure it's got the correct lens details from the camera viewFrustum.setFieldOfView(fov); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 8ce1abb05b..fce56ff670 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -80,8 +80,8 @@ Avatar::Avatar(Agent* owningAgent) : _bodyRollDelta(0.0f), _movedHandOffset(0.0f, 0.0f, 0.0f), _rotation(0.0f, 0.0f, 0.0f, 0.0f), - _cameraPosition(0.0f, 0.0f, 0.0f), _mode(AVATAR_MODE_STANDING), + _cameraPosition(0.0f, 0.0f, 0.0f), _handHoldingPosition(0.0f, 0.0f, 0.0f), _velocity(0.0f, 0.0f, 0.0f), _thrust(0.0f, 0.0f, 0.0f), diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 1486013c9c..736534f087 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -62,9 +62,9 @@ Head::Head(Avatar* owningAvatar) : _audioAttack(0.0f), _returnSpringScale(1.0f), _bodyRotation(0.0f, 0.0f, 0.0f), + _renderLookatVectors(false), _mohawkTriangleFan(NULL), - _mohawkColors(NULL), - _renderLookatVectors(false) { + _mohawkColors(NULL) { for (int t = 0; t < NUM_HAIR_TUFTS; t ++) { _hairTuft[t].length = HAIR_LENGTH; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 4b97a2a047..fa0a8d1e20 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -17,20 +17,6 @@ using namespace std; -int packFloatAngleToTwoByte(unsigned char* buffer, float angle) { - const float ANGLE_CONVERSION_RATIO = (std::numeric_limits::max() / 360.0); - - uint16_t angleHolder = floorf((angle + 180) * ANGLE_CONVERSION_RATIO); - memcpy(buffer, &angleHolder, sizeof(uint16_t)); - - return sizeof(uint16_t); -} - -int unpackFloatAngleFromTwoByte(uint16_t* byteAnglePointer, float* destinationPointer) { - *destinationPointer = (*byteAnglePointer / (float) std::numeric_limits::max()) * 360.0 - 180; - return sizeof(uint16_t); -} - AvatarData::AvatarData(Agent* owningAgent) : AgentData(owningAgent), _handPosition(0,0,0), @@ -40,9 +26,7 @@ AvatarData::AvatarData(Agent* owningAgent) : _audioLoudness(0), _handState(0), _cameraPosition(0,0,0), - _cameraDirection(0,0,0), - _cameraUp(0,0,0), - _cameraRight(0,0,0), + _cameraOrientation(), _cameraFov(0.0f), _cameraAspectRatio(0.0f), _cameraNearClip(0.0f), @@ -110,20 +94,11 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { // camera details memcpy(destinationBuffer, &_cameraPosition, sizeof(_cameraPosition)); destinationBuffer += sizeof(_cameraPosition); - memcpy(destinationBuffer, &_cameraDirection, sizeof(_cameraDirection)); - destinationBuffer += sizeof(_cameraDirection); - memcpy(destinationBuffer, &_cameraRight, sizeof(_cameraRight)); - destinationBuffer += sizeof(_cameraRight); - memcpy(destinationBuffer, &_cameraUp, sizeof(_cameraUp)); - destinationBuffer += sizeof(_cameraUp); - memcpy(destinationBuffer, &_cameraFov, sizeof(_cameraFov)); - destinationBuffer += sizeof(_cameraFov); - memcpy(destinationBuffer, &_cameraAspectRatio, sizeof(_cameraAspectRatio)); - destinationBuffer += sizeof(_cameraAspectRatio); - memcpy(destinationBuffer, &_cameraNearClip, sizeof(_cameraNearClip)); - destinationBuffer += sizeof(_cameraNearClip); - memcpy(destinationBuffer, &_cameraFarClip, sizeof(_cameraFarClip)); - destinationBuffer += sizeof(_cameraFarClip); + destinationBuffer += packOrientationQuatToBytes(destinationBuffer, _cameraOrientation); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _cameraFov); + destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _cameraAspectRatio); + destinationBuffer += packClipValueToTwoByte(destinationBuffer, _cameraNearClip); + destinationBuffer += packClipValueToTwoByte(destinationBuffer, _cameraFarClip); // key state *destinationBuffer++ = _keyState; @@ -204,21 +179,12 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { // camera details memcpy(&_cameraPosition, sourceBuffer, sizeof(_cameraPosition)); sourceBuffer += sizeof(_cameraPosition); - memcpy(&_cameraDirection, sourceBuffer, sizeof(_cameraDirection)); - sourceBuffer += sizeof(_cameraDirection); - memcpy(&_cameraRight, sourceBuffer, sizeof(_cameraRight)); - sourceBuffer += sizeof(_cameraRight); - memcpy(&_cameraUp, sourceBuffer, sizeof(_cameraUp)); - sourceBuffer += sizeof(_cameraUp); - memcpy(&_cameraFov, sourceBuffer, sizeof(_cameraFov)); - sourceBuffer += sizeof(_cameraFov); - memcpy(&_cameraAspectRatio, sourceBuffer, sizeof(_cameraAspectRatio)); - sourceBuffer += sizeof(_cameraAspectRatio); - memcpy(&_cameraNearClip, sourceBuffer, sizeof(_cameraNearClip)); - sourceBuffer += sizeof(_cameraNearClip); - memcpy(&_cameraFarClip, sourceBuffer, sizeof(_cameraFarClip)); - sourceBuffer += sizeof(_cameraFarClip); - + sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, _cameraOrientation); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_cameraFov); + sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer,_cameraAspectRatio); + sourceBuffer += unpackClipValueFromTwoByte(sourceBuffer,_cameraNearClip); + sourceBuffer += unpackClipValueFromTwoByte(sourceBuffer,_cameraFarClip); + // key state _keyState = (KeyState)*sourceBuffer++; @@ -236,3 +202,112 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { return sourceBuffer - startPosition; } + +glm::vec3 AvatarData::calculateCameraDirection() const { + const glm::vec3 IDENTITY_FRONT = glm::vec3( 0.0f, 0.0f, 1.0f); + glm::mat4 rotationMatrix = glm::mat4_cast(_cameraOrientation); + glm::vec3 direction = glm::vec3(glm::vec4(IDENTITY_FRONT, 0.0f) * rotationMatrix); + return direction; +} + + +int packFloatAngleToTwoByte(unsigned char* buffer, float angle) { + const float ANGLE_CONVERSION_RATIO = (std::numeric_limits::max() / 360.0); + + uint16_t angleHolder = floorf((angle + 180) * ANGLE_CONVERSION_RATIO); + memcpy(buffer, &angleHolder, sizeof(uint16_t)); + + return sizeof(uint16_t); +} + +int unpackFloatAngleFromTwoByte(uint16_t* byteAnglePointer, float* destinationPointer) { + *destinationPointer = (*byteAnglePointer / (float) std::numeric_limits::max()) * 360.0 - 180; + return sizeof(uint16_t); +} + +int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput) { + const float QUAT_PART_CONVERSION_RATIO = (std::numeric_limits::max() / 2.0); + uint16_t quatParts[4]; + quatParts[0] = floorf((quatInput.x + 1.0) * QUAT_PART_CONVERSION_RATIO); + quatParts[1] = floorf((quatInput.y + 1.0) * QUAT_PART_CONVERSION_RATIO); + quatParts[2] = floorf((quatInput.z + 1.0) * QUAT_PART_CONVERSION_RATIO); + quatParts[3] = floorf((quatInput.w + 1.0) * QUAT_PART_CONVERSION_RATIO); + + memcpy(buffer, &quatParts, sizeof(quatParts)); + return sizeof(quatParts); +} + +int unpackOrientationQuatFromBytes(unsigned char* buffer, glm::quat& quatOutput) { + uint16_t quatParts[4]; + memcpy(&quatParts, buffer, sizeof(quatParts)); + + quatOutput.x = ((quatParts[0] / (float) std::numeric_limits::max()) * 2.0) - 1.0; + quatOutput.y = ((quatParts[1] / (float) std::numeric_limits::max()) * 2.0) - 1.0; + quatOutput.z = ((quatParts[2] / (float) std::numeric_limits::max()) * 2.0) - 1.0; + quatOutput.w = ((quatParts[3] / (float) std::numeric_limits::max()) * 2.0) - 1.0; + + return sizeof(quatParts); +} + +float SMALL_LIMIT = 10.0; +float LARGE_LIMIT = 1000.0; + +int packFloatRatioToTwoByte(unsigned char* buffer, float ratio) { + // if the ratio is less than 10, then encode it as a positive number scaled from 0 to int16::max() + int16_t ratioHolder; + + if (ratio < SMALL_LIMIT) { + const float SMALL_RATIO_CONVERSION_RATIO = (std::numeric_limits::max() / SMALL_LIMIT); + ratioHolder = floorf(ratio * SMALL_RATIO_CONVERSION_RATIO); + } else { + const float LARGE_RATIO_CONVERSION_RATIO = std::numeric_limits::min() / LARGE_LIMIT; + ratioHolder = floorf((std::min(ratio,LARGE_LIMIT) - SMALL_LIMIT) * LARGE_RATIO_CONVERSION_RATIO); + } + memcpy(buffer, &ratioHolder, sizeof(ratioHolder)); + return sizeof(ratioHolder); +} + +int unpackFloatRatioFromTwoByte(unsigned char* buffer, float& ratio) { + int16_t ratioHolder; + memcpy(&ratioHolder, buffer, sizeof(ratioHolder)); + + // If it's positive, than the original ratio was less than SMALL_LIMIT + if (ratioHolder > 0) { + ratio = (ratioHolder / (float) std::numeric_limits::max()) * SMALL_LIMIT; + } else { + // If it's negative, than the original ratio was between SMALL_LIMIT and LARGE_LIMIT + ratio = ((ratioHolder / (float) std::numeric_limits::min()) * LARGE_LIMIT) + SMALL_LIMIT; + } + return sizeof(ratioHolder); +} + +int packClipValueToTwoByte(unsigned char* buffer, float clipValue) { + // Clip values must be less than max signed 16bit integers + assert(clipValue < std::numeric_limits::max()); + int16_t holder; + + // if the clip is less than 10, then encode it as a positive number scaled from 0 to int16::max() + if (clipValue < SMALL_LIMIT) { + const float SMALL_RATIO_CONVERSION_RATIO = (std::numeric_limits::max() / SMALL_LIMIT); + holder = floorf(clipValue * SMALL_RATIO_CONVERSION_RATIO); + } else { + // otherwise we store it as a negative integer + holder = -1 * floorf(clipValue); + } + memcpy(buffer, &holder, sizeof(holder)); + return sizeof(holder); +} + +int unpackClipValueFromTwoByte(unsigned char* buffer, float& clipValue) { + int16_t holder; + memcpy(&holder, buffer, sizeof(holder)); + + // If it's positive, than the original clipValue was less than SMALL_LIMIT + if (holder > 0) { + clipValue = (holder / (float) std::numeric_limits::max()) * SMALL_LIMIT; + } else { + // If it's negative, than the original holder can be found as the opposite sign of holder + clipValue = -1.0f * holder; + } + return sizeof(holder); +} diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 5773dedffd..d86cc6078b 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -12,6 +12,7 @@ #include #include +#include #include #include "HeadData.h" @@ -58,23 +59,21 @@ public: // getters for camera details const glm::vec3& getCameraPosition() const { return _cameraPosition; }; - const glm::vec3& getCameraDirection() const { return _cameraDirection; } - const glm::vec3& getCameraUp() const { return _cameraUp; } - const glm::vec3& getCameraRight() const { return _cameraRight; } + const glm::quat& getCameraOrientation() const { return _cameraOrientation; } float getCameraFov() const { return _cameraFov; } float getCameraAspectRatio() const { return _cameraAspectRatio; } float getCameraNearClip() const { return _cameraNearClip; } float getCameraFarClip() const { return _cameraFarClip; } + glm::vec3 calculateCameraDirection() const; + // setters for camera details - void setCameraPosition(const glm::vec3& position) { _cameraPosition = position; }; - void setCameraDirection(const glm::vec3& direction) { _cameraDirection = direction; } - void setCameraUp(const glm::vec3& up) { _cameraUp = up; } - void setCameraRight(const glm::vec3& right) { _cameraRight = right; } - void setCameraFov(float fov) { _cameraFov = fov; } - void setCameraAspectRatio(float aspectRatio) { _cameraAspectRatio = aspectRatio; } - void setCameraNearClip(float nearClip) { _cameraNearClip = nearClip; } - void setCameraFarClip(float farClip) { _cameraFarClip = farClip; } + void setCameraPosition(const glm::vec3& position) { _cameraPosition = position; } + void setCameraOrientation(const glm::quat& orientation) { _cameraOrientation = orientation; } + void setCameraFov(float fov) { _cameraFov = fov; } + void setCameraAspectRatio(float aspectRatio) { _cameraAspectRatio = aspectRatio; } + void setCameraNearClip(float nearClip) { _cameraNearClip = nearClip; } + void setCameraFarClip(float farClip) { _cameraFarClip = farClip; } // key state void setKeyState(KeyState s) { _keyState = s; } @@ -111,11 +110,7 @@ protected: // camera details for the avatar glm::vec3 _cameraPosition; - - // can we describe this in less space? For example, a Quaternion? or Euler angles? - glm::vec3 _cameraDirection; - glm::vec3 _cameraUp; - glm::vec3 _cameraRight; + glm::quat _cameraOrientation; float _cameraFov; float _cameraAspectRatio; float _cameraNearClip; @@ -139,4 +134,27 @@ private: AvatarData& operator= (const AvatarData&); }; + +// These pack/unpack functions are designed to start specific known types in as efficient a manner +// as possible. Taking advantage of the known characteristics of the semantic types. + +// Angles are known to be between 0 and 360deg, this allows us to encode in 16bits with great accuracy +int packFloatAngleToTwoByte(unsigned char* buffer, float angle); +int unpackFloatAngleFromTwoByte(uint16_t* byteAnglePointer, float* destinationPointer); + +// Orientation Quats are known to have 4 normalized components be between -1.0 and 1.0 +// this allows us to encode each component in 16bits with great accuracy +int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput); +int unpackOrientationQuatFromBytes(unsigned char* buffer, glm::quat& quatOutput); + +// Ratios need the be highly accurate when less than 10, but not very accurate above 10, and they +// are never greater than 1000 to 1, this allows us to encode each component in 16bits +int packFloatRatioToTwoByte(unsigned char* buffer, float ratio); +int unpackFloatRatioFromTwoByte(unsigned char* buffer, float& ratio); + +// Near/Far Clip values need the be highly accurate when less than 10, but only integer accuracy above 10 and +// they are never greater than 16,000, this allows us to encode each component in 16bits +int packClipValueToTwoByte(unsigned char* buffer, float clipValue); +int unpackClipValueFromTwoByte(unsigned char* buffer, float& clipValue); + #endif /* defined(__hifi__AvatarData__) */ diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 5829bbe34a..ca31cdd994 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -421,3 +421,4 @@ int insertIntoSortedArrays(void* value, float key, int originalIndex, } return -1; // error case } + diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 8da9d7beca..9d858f11e0 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -87,4 +87,5 @@ class debug { public: static const char* valueOf(bool checkValue) { return checkValue ? "yes" : "no"; }; }; + #endif /* defined(__hifi__SharedUtil__) */ diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index 061727b003..0f10428b23 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -19,22 +19,40 @@ using namespace std; ViewFrustum::ViewFrustum() : - _position(glm::vec3(0,0,0)), - _direction(glm::vec3(0,0,0)), - _up(glm::vec3(0,0,0)), - _right(glm::vec3(0,0,0)), + _position(0,0,0), + _orientation(), + _direction(0,0,0), + _up(0,0,0), + _right(0,0,0), _fieldOfView(0.0), _aspectRatio(1.0), _nearClip(0.1), _farClip(500.0), - _farTopLeft(glm::vec3(0,0,0)), - _farTopRight(glm::vec3(0,0,0)), - _farBottomLeft(glm::vec3(0,0,0)), - _farBottomRight(glm::vec3(0,0,0)), - _nearTopLeft(glm::vec3(0,0,0)), - _nearTopRight(glm::vec3(0,0,0)), - _nearBottomLeft(glm::vec3(0,0,0)), - _nearBottomRight(glm::vec3(0,0,0)) { } + _farTopLeft(0,0,0), + _farTopRight(0,0,0), + _farBottomLeft(0,0,0), + _farBottomRight(0,0,0), + _nearTopLeft(0,0,0), + _nearTopRight(0,0,0), + _nearBottomLeft(0,0,0), + _nearBottomRight(0,0,0) { } + +void ViewFrustum::setOrientation(const glm::quat& orientationAsQuaternion) { + glm::quat quat; + quat = quat * orientationAsQuaternion; + + // this is where the coordinate system is represented + const glm::vec3 IDENTITY_RIGHT = glm::vec3(-1.0f, 0.0f, 0.0f); + const glm::vec3 IDENTITY_UP = glm::vec3( 0.0f, 1.0f, 0.0f); + const glm::vec3 IDENTITY_FRONT = glm::vec3( 0.0f, 0.0f, 1.0f); + + glm::mat4 rotationMatrix = glm::mat4_cast(quat); + + _orientation = orientationAsQuaternion; + _right = glm::vec3(glm::vec4(IDENTITY_RIGHT, 0.0f) * rotationMatrix); + _up = glm::vec3(glm::vec4(IDENTITY_UP, 0.0f) * rotationMatrix); + _direction = glm::vec3(glm::vec4(IDENTITY_FRONT, 0.0f) * rotationMatrix); +} ///////////////////////////////////////////////////////////////////////////////////// // ViewFrustum::calculateViewFrustum() diff --git a/libraries/voxels/src/ViewFrustum.h b/libraries/voxels/src/ViewFrustum.h index 1ae33d55ad..1c61160566 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -21,6 +21,9 @@ private: // camera location/orientation attributes glm::vec3 _position; + glm::quat _orientation; + + // calculated for orientation glm::vec3 _direction; glm::vec3 _up; glm::vec3 _right; @@ -53,23 +56,23 @@ private: public: // setters for camera attributes - void setPosition (const glm::vec3& p) { _position = p; } - void setOrientation (const glm::vec3& d, const glm::vec3& u, const glm::vec3& r ) - { _direction = d; _up = u; _right = r; } + void setPosition (const glm::vec3& p) { _position = p; }; + void setOrientation (const glm::quat& orientationAsQuaternion); // getters for camera attributes - const glm::vec3& getPosition() const { return _position; }; - const glm::vec3& getDirection() const { return _direction; }; - const glm::vec3& getUp() const { return _up; }; - const glm::vec3& getRight() const { return _right; }; + const glm::vec3& getPosition() const { return _position; }; + const glm::quat& getOrientation() const { return _orientation; }; + const glm::vec3& getDirection() const { return _direction; }; + const glm::vec3& getUp() const { return _up; }; + const glm::vec3& getRight() const { return _right; }; // setters for lens attributes - void setFieldOfView ( float f ) { _fieldOfView = f; } - void setAspectRatio ( float a ) { _aspectRatio = a; } - void setNearClip ( float n ) { _nearClip = n; } - void setFarClip ( float f ) { _farClip = f; } - void setEyeOffsetPosition (const glm::vec3& p) { _eyeOffsetPosition = p; } - void setEyeOffsetOrientation (const glm::quat& o) { _eyeOffsetOrientation = o; } + void setFieldOfView ( float f ) { _fieldOfView = f; }; + void setAspectRatio ( float a ) { _aspectRatio = a; }; + void setNearClip ( float n ) { _nearClip = n; }; + void setFarClip ( float f ) { _farClip = f; }; + void setEyeOffsetPosition (const glm::vec3& p) { _eyeOffsetPosition = p; }; + void setEyeOffsetOrientation (const glm::quat& o) { _eyeOffsetOrientation = o; }; // getters for lens attributes diff --git a/voxel-server/src/VoxelAgentData.cpp b/voxel-server/src/VoxelAgentData.cpp index 0ca7778a94..acb185fb5f 100644 --- a/voxel-server/src/VoxelAgentData.cpp +++ b/voxel-server/src/VoxelAgentData.cpp @@ -50,7 +50,7 @@ bool VoxelAgentData::updateCurrentViewFrustum() { ViewFrustum newestViewFrustum; // get position and orientation details from the camera newestViewFrustum.setPosition(getCameraPosition()); - newestViewFrustum.setOrientation(getCameraDirection(), getCameraUp(), getCameraRight()); + newestViewFrustum.setOrientation(getCameraOrientation()); // Also make sure it's got the correct lens details from the camera newestViewFrustum.setFieldOfView(getCameraFov()); From 20917c37b86915d5f04338309f0aeb84ca635e24 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 27 May 2013 09:59:53 -0700 Subject: [PATCH 03/41] removed extra comment --- libraries/avatars/src/AvatarData.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index fa0a8d1e20..b5ef015c7b 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -108,7 +108,6 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { memcpy(destinationBuffer, _chatMessage.data(), _chatMessage.size() * sizeof(char)); destinationBuffer += _chatMessage.size() * sizeof(char); - // voxel sending features... // voxel sending features... unsigned char wantItems = 0; if (_wantResIn) { setAtBit(wantItems,WANT_RESIN_AT_BIT); } From 06e98d2c43f2d78b67f54e279fbd2a1a8563728d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 27 May 2013 14:10:51 -0700 Subject: [PATCH 04/41] Optimize wire-format for AvatarData - moved HandState into semi-nibble in bitItems - moved KeyState into semi-nibble in bitItems - moved AudioLoudness into scaled float stored as byte - overall savings - 5 bytes --- interface/src/AvatarTouch.h | 2 +- libraries/avatars/src/AvatarData.cpp | 72 ++++++++++++++++------------ libraries/avatars/src/AvatarData.h | 12 ++++- libraries/shared/src/SharedUtil.cpp | 9 ++++ libraries/shared/src/SharedUtil.h | 4 ++ 5 files changed, 66 insertions(+), 33 deletions(-) diff --git a/interface/src/AvatarTouch.h b/interface/src/AvatarTouch.h index 2111c0ecf1..cc4d21ae82 100644 --- a/interface/src/AvatarTouch.h +++ b/interface/src/AvatarTouch.h @@ -12,7 +12,7 @@ enum AvatarHandState { - HAND_STATE_NULL = -1, + HAND_STATE_NULL = 0, HAND_STATE_OPEN, HAND_STATE_GRASPING, HAND_STATE_POINTING, diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index b5ef015c7b..1c126b7587 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -83,13 +83,8 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { memcpy(destinationBuffer, &_headData->_lookAtPosition, sizeof(_headData->_lookAtPosition)); destinationBuffer += sizeof(_headData->_lookAtPosition); - // Hand State (0 = not grabbing, 1 = grabbing) - memcpy(destinationBuffer, &_handState, sizeof(char)); - destinationBuffer += sizeof(char); - // Instantaneous audio loudness (used to drive facial animation) - memcpy(destinationBuffer, &_audioLoudness, sizeof(float)); - destinationBuffer += sizeof(float); + destinationBuffer += packFloatToByte(destinationBuffer, std::min(MAX_AUDIO_LOUDNESS, _audioLoudness), MAX_AUDIO_LOUDNESS); // camera details memcpy(destinationBuffer, &_cameraPosition, sizeof(_cameraPosition)); @@ -100,20 +95,22 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { destinationBuffer += packClipValueToTwoByte(destinationBuffer, _cameraNearClip); destinationBuffer += packClipValueToTwoByte(destinationBuffer, _cameraFarClip); - // key state - *destinationBuffer++ = _keyState; - // chat message *destinationBuffer++ = _chatMessage.size(); memcpy(destinationBuffer, _chatMessage.data(), _chatMessage.size() * sizeof(char)); destinationBuffer += _chatMessage.size() * sizeof(char); - // voxel sending features... - unsigned char wantItems = 0; - if (_wantResIn) { setAtBit(wantItems,WANT_RESIN_AT_BIT); } - if (_wantColor) { setAtBit(wantItems,WANT_COLOR_AT_BIT); } - if (_wantDelta) { setAtBit(wantItems,WANT_DELTA_AT_BIT); } - *destinationBuffer++ = wantItems; + // bitMask of less than byte wide items + unsigned char bitItems = 0; + if (_wantResIn) { setAtBit(bitItems,WANT_RESIN_AT_BIT); } + if (_wantColor) { setAtBit(bitItems,WANT_COLOR_AT_BIT); } + if (_wantDelta) { setAtBit(bitItems,WANT_DELTA_AT_BIT); } + + // key state + setSemiNibbleAt(bitItems,KEY_STATE_START_BIT,_keyState); + // hand state + setSemiNibbleAt(bitItems,HAND_STATE_START_BIT,_handState); + *destinationBuffer++ = bitItems; return destinationBuffer - bufferStart; } @@ -162,18 +159,13 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { // Hand Position memcpy(&_handPosition, sourceBuffer, sizeof(float) * 3); sourceBuffer += sizeof(float) * 3; - + // Lookat Position memcpy(&_headData->_lookAtPosition, sourceBuffer, sizeof(_headData->_lookAtPosition)); sourceBuffer += sizeof(_headData->_lookAtPosition); - - // Hand State - memcpy(&_handState, sourceBuffer, sizeof(char)); - sourceBuffer += sizeof(char); - + // Instantaneous audio loudness (used to drive facial animation) - memcpy(&_audioLoudness, sourceBuffer, sizeof(float)); - sourceBuffer += sizeof(float); + sourceBuffer += unpackFloatFromByte(sourceBuffer, _audioLoudness, MAX_AUDIO_LOUDNESS); // camera details memcpy(&_cameraPosition, sourceBuffer, sizeof(_cameraPosition)); @@ -184,20 +176,23 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { sourceBuffer += unpackClipValueFromTwoByte(sourceBuffer,_cameraNearClip); sourceBuffer += unpackClipValueFromTwoByte(sourceBuffer,_cameraFarClip); - // key state - _keyState = (KeyState)*sourceBuffer++; - // the rest is a chat message int chatMessageSize = *sourceBuffer++; _chatMessage = string((char*)sourceBuffer, chatMessageSize); sourceBuffer += chatMessageSize * sizeof(char); // voxel sending features... - unsigned char wantItems = 0; - wantItems = (unsigned char)*sourceBuffer++; - _wantResIn = oneAtBit(wantItems,WANT_RESIN_AT_BIT); - _wantColor = oneAtBit(wantItems,WANT_COLOR_AT_BIT); - _wantDelta = oneAtBit(wantItems,WANT_DELTA_AT_BIT); + unsigned char bitItems = 0; + bitItems = (unsigned char)*sourceBuffer++; + _wantResIn = oneAtBit(bitItems,WANT_RESIN_AT_BIT); + _wantColor = oneAtBit(bitItems,WANT_COLOR_AT_BIT); + _wantDelta = oneAtBit(bitItems,WANT_DELTA_AT_BIT); + + // key state, stored as a semi-nibble in the bitItems + _keyState = (KeyState)getSemiNibbleAt(bitItems,KEY_STATE_START_BIT); + + // hand state, stored as a semi-nibble in the bitItems + _handState = getSemiNibbleAt(bitItems,HAND_STATE_START_BIT); return sourceBuffer - startPosition; } @@ -310,3 +305,18 @@ int unpackClipValueFromTwoByte(unsigned char* buffer, float& clipValue) { } return sizeof(holder); } + +int packFloatToByte(unsigned char* buffer, float value, float scaleBy) { + unsigned char holder; + const float CONVERSION_RATIO = (255 / scaleBy); + holder = floorf(value * CONVERSION_RATIO); + memcpy(buffer, &holder, sizeof(holder)); + return sizeof(holder); +} + +int unpackFloatFromByte(unsigned char* buffer, float& value, float scaleBy) { + unsigned char holder; + memcpy(&holder, buffer, sizeof(holder)); + value = ((float)holder / (float) 255) * scaleBy; + return sizeof(holder); +} diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index d86cc6078b..04bc7e6ad5 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -20,10 +20,15 @@ const int WANT_RESIN_AT_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 +const int HAND_STATE_START_BIT = 5; // 6th and 7th bits + +const float MAX_AUDIO_LOUDNESS = 1000.0; // close enough for mouth animation + enum KeyState { - NO_KEY_DOWN, + NO_KEY_DOWN = 0, INSERT_KEY_DOWN, DELETE_KEY_DOWN }; @@ -157,4 +162,9 @@ int unpackFloatRatioFromTwoByte(unsigned char* buffer, float& ratio); int packClipValueToTwoByte(unsigned char* buffer, float clipValue); int unpackClipValueFromTwoByte(unsigned char* buffer, float& clipValue); +// Positive floats that don't need to be very precise +int packFloatToByte(unsigned char* buffer, float value, float scaleBy); +int unpackFloatFromByte(unsigned char* buffer, float& value, float scaleBy); + + #endif /* defined(__hifi__AvatarData__) */ diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index ca31cdd994..10967ea3e7 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -101,6 +101,15 @@ void setAtBit(unsigned char& byte, int bitIndex) { byte += (1 << (7 - bitIndex)); } +int getSemiNibbleAt(unsigned char& byte, int bitIndex) { + return (byte >> (7 - bitIndex) & 3); // semi-nibbles store 00, 01, 10, or 11 +} + +void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) { + assert(value <= 3 && value >= 0); + byte += ((value & 3) << (7 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11 +} + void switchToResourcesParentIfRequired() { #ifdef __APPLE__ diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 9d858f11e0..75c00c71f7 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -53,6 +53,10 @@ int numberOfOnes(unsigned char byte); bool oneAtBit(unsigned char byte, int bitIndex); void setAtBit(unsigned char& byte, int bitIndex); +int getSemiNibbleAt(unsigned char& byte, int bitIndex); +void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value); + + void switchToResourcesParentIfRequired(); void loadRandomIdentifier(unsigned char* identifierBuffer, int numBytes); From b250289749bd8b0115e447d2193d2486c6e5b543 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 3 Jun 2013 21:41:23 -0700 Subject: [PATCH 05/41] removed debug --- voxel-server/src/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 098596f02e..f0c87f8ada 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -370,7 +370,6 @@ void deepestLevelVoxelDistributor(AgentList* agentList, // if after sending packets we've emptied our bag, then we want to remember that we've sent all // the voxels from the current view frustum if (agentData->nodeBag.isEmpty()) { -printf("agentData->nodeBag.isEmpty()...\n"); agentData->updateLastKnownViewFrustum(); agentData->setViewSent(true); } From 8f58f9f424203d825f22a18eff59f23f30978428 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 10:48:45 -0700 Subject: [PATCH 06/41] merge cleanup --- interface/src/Application.cpp | 5 +---- libraries/voxels/src/VoxelTree.h | 4 +++- voxel-server/src/main.cpp | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3ce4d7b9f3..6a37fe6ae2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1749,13 +1749,10 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { float farClip = camera.getFarClip(); glm::quat rotation = camera.getRotation(); - glm::vec3 direction = rotation * AVATAR_FRONT; - glm::vec3 up = rotation * AVATAR_UP; - glm::vec3 right = rotation * AVATAR_RIGHT; // Set the viewFrustum up with the correct position and orientation of the camera viewFrustum.setPosition(position); - viewFrustum.setOrientation(o.getQuat()); + viewFrustum.setOrientation(rotation); // Also make sure it's got the correct lens details from the camera viewFrustum.setFieldOfView(fov); diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index b276b6e47f..fce051eda9 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -28,6 +28,7 @@ typedef enum {GRADIENT, RANDOM, NATURAL} creationMode; #define ACTUALLY_DELETE false #define COLLAPSE_EMPTY_TREE true #define DONT_COLLAPSE false +#define DONT_CHOP_LEVELS 0 class VoxelTree { public: @@ -71,7 +72,8 @@ public: int encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, const ViewFrustum* viewFrustum, - bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, int chopLevels = 0, + bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, + int chopLevels = DONT_CHOP_LEVELS, bool deltaViewFrustum = false, const ViewFrustum* lastViewFrustum = NULL, double lastViewFrustumSent = 0) const; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index ef9e7cd257..fe4276955b 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -313,7 +313,7 @@ void deepestLevelVoxelDistributor(AgentList* agentList, bytesWritten = randomTree.encodeTreeBitstream(INT_MAX, subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, agentData->nodeBag, &agentData->getCurrentViewFrustum(), - agentData->getWantColor(), WANT_EXISTS_BITS, + agentData->getWantColor(), WANT_EXISTS_BITS, DONT_CHOP_LEVELS, wantDelta, lastViewFrustum, agentData->getLastViewSent()); if (agentData->getAvailable() >= bytesWritten) { From 93e5991c68c0b453eb71599b54c4b93a6db311f0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 5 Jun 2013 10:31:24 -0700 Subject: [PATCH 07/41] add markWithChangedTime() method as public method --- libraries/voxels/src/VoxelNode.cpp | 20 +++++++++----------- libraries/voxels/src/VoxelNode.h | 2 ++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index a9a1f4eb12..0a4d813ec7 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -46,9 +46,7 @@ void VoxelNode::init(unsigned char * octalCode) { _isDirty = true; _shouldRender = false; _isStagedForDeletion = false; - - _lastChanged = usecTimestampNow(); - + markWithChangedTime(); calculateAABox(); } @@ -68,7 +66,7 @@ void VoxelNode::setShouldRender(bool shouldRender) { if (shouldRender != _shouldRender) { _shouldRender = shouldRender; _isDirty = true; - _lastChanged = usecTimestampNow(); + markWithChangedTime(); } } @@ -92,7 +90,7 @@ void VoxelNode::deleteChildAtIndex(int childIndex) { delete _children[childIndex]; _children[childIndex] = NULL; _isDirty = true; - _lastChanged = usecTimestampNow(); + markWithChangedTime(); _childCount--; } } @@ -103,7 +101,7 @@ VoxelNode* VoxelNode::removeChildAtIndex(int childIndex) { if (_children[childIndex]) { _children[childIndex] = NULL; _isDirty = true; - _lastChanged = usecTimestampNow(); + markWithChangedTime(); _childCount--; } return returnedChild; @@ -113,7 +111,7 @@ void VoxelNode::addChildAtIndex(int childIndex) { if (!_children[childIndex]) { _children[childIndex] = new VoxelNode(childOctalCode(_octalCode, childIndex)); _isDirty = true; - _lastChanged = usecTimestampNow(); + markWithChangedTime(); _childCount++; } } @@ -141,7 +139,7 @@ void VoxelNode::safeDeepDeleteChildAtIndex(int childIndex, bool& stagedForDeleti deleteChildAtIndex(childIndex); _isDirty = true; } - _lastChanged = usecTimestampNow(); + markWithChangedTime(); } } @@ -185,7 +183,7 @@ void VoxelNode::setFalseColor(colorPart red, colorPart green, colorPart blue) { _currentColor[2] = blue; _currentColor[3] = 1; // XXXBHG - False colors are always considered set _isDirty = true; - _lastChanged = usecTimestampNow(); + markWithChangedTime(); } } @@ -197,7 +195,7 @@ void VoxelNode::setFalseColored(bool isFalseColored) { } _falseColored = isFalseColored; _isDirty = true; - _lastChanged = usecTimestampNow(); + markWithChangedTime(); } }; @@ -211,7 +209,7 @@ void VoxelNode::setColor(const nodeColor& color) { memcpy(&_currentColor,&color,sizeof(nodeColor)); } _isDirty = true; - _lastChanged = usecTimestampNow(); + markWithChangedTime(); } } #endif diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index ca00260ace..39fc38925c 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -9,6 +9,7 @@ #ifndef __hifi__VoxelNode__ #define __hifi__VoxelNode__ +#include #include "AABox.h" #include "ViewFrustum.h" #include "VoxelConstants.h" @@ -78,6 +79,7 @@ public: bool isDirty() const { return _isDirty; }; void clearDirtyBit() { _isDirty = false; }; bool hasChangedSince(double time) const { return (_lastChanged > time); }; + void markWithChangedTime() { _lastChanged = usecTimestampNow(); }; glBufferIndex getBufferIndex() const { return _glBufferIndex; }; bool isKnownBufferIndex() const { return (_glBufferIndex != GLBUFFER_INDEX_UNKNOWN); }; From 00c29e5edafc547aff3e931e198a4a8ee972d1f3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 5 Jun 2013 10:32:36 -0700 Subject: [PATCH 08/41] changed deleteVoxelCodeFromTree() to use recursion to allow for proper unwinding, updating of parent path --- libraries/voxels/src/VoxelTree.cpp | 132 +++++++++++++++++++++-------- libraries/voxels/src/VoxelTree.h | 3 +- 2 files changed, 99 insertions(+), 36 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 904826f440..e6960bf159 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -264,61 +264,123 @@ void VoxelTree::deleteVoxelAt(float x, float y, float z, float s, bool stage) { reaverageVoxelColors(rootNode); } +class DeleteVoxelCodeFromTreeArgs { +public: + bool stage; + bool collapseEmptyTrees; + unsigned char* codeBuffer; + int lengthOfCode; + bool deleteLastChild; + bool pathChanged; +}; // Note: uses the codeColorBuffer format, but the color's are ignored, because // this only finds and deletes the node from the tree. void VoxelTree::deleteVoxelCodeFromTree(unsigned char* codeBuffer, bool stage, bool collapseEmptyTrees) { - VoxelNode* parentNode = NULL; - VoxelNode* nodeToDelete = nodeForOctalCode(rootNode, codeBuffer, &parentNode); - // If the node exists... - int lengthInBytes = bytesRequiredForCodeLength(*codeBuffer); // includes octet count, not color! - // if the code we got back matches our target, then we know we can actually delete it - if (memcmp(nodeToDelete->getOctalCode(), codeBuffer, lengthInBytes) == 0) { - if (parentNode) { - int childIndex = branchIndexWithDescendant(parentNode->getOctalCode(), codeBuffer); - if (stage) { - nodeToDelete->stageForDeletion(); - } else { - parentNode->deleteChildAtIndex(childIndex); - if (_shouldReaverage) { - parentNode->setColorFromAverageOfChildren(); - } - } + // recurse the tree while decoding the codeBuffer, once you find the node in question, recurse + // back and implement color reaveraging, and marking of lastChanged + DeleteVoxelCodeFromTreeArgs args; + args.stage = stage; + args.collapseEmptyTrees = collapseEmptyTrees; + args.codeBuffer = codeBuffer; + args.lengthOfCode = numberOfThreeBitSectionsInCode(codeBuffer); + args.deleteLastChild = false; + args.pathChanged = false; + + VoxelNode* node = rootNode; + deleteVoxelCodeFromTreeRecursion(node, &args); +} - // If we're in collapseEmptyTrees mode, and we're the last child of this parent, then delete the parent. - // This will collapse the empty tree above us. - if (collapseEmptyTrees && parentNode->getChildCount() == 0) { - // Can't delete the root this way. - if (parentNode != rootNode) { - deleteVoxelCodeFromTree(parentNode->getOctalCode(), stage, collapseEmptyTrees); - } - } - _isDirty = true; - } - } else if (nodeToDelete->isLeaf()) { +void VoxelTree::deleteVoxelCodeFromTreeRecursion(VoxelNode* node, void* extraData) { + DeleteVoxelCodeFromTreeArgs* args = (DeleteVoxelCodeFromTreeArgs*)extraData; + + int lengthOfNodeCode = numberOfThreeBitSectionsInCode(node->getOctalCode()); + + // Since we traverse the tree in code order, we know that if our code + // matches, then we've reached our target node. + if (lengthOfNodeCode == args->lengthOfCode) { + // we've reached our target, depending on how we're called we may be able to operate on it + // if we're in "stage" mode, then we can could have the node staged, otherwise we can't really delete + // it here, we need to recurse up, and delete it there. So we handle these cases the same to keep + // the logic consistent. + args->deleteLastChild = true; + return; + } + + // Ok, we know we haven't reached our target node yet, so keep looking + int childIndex = branchIndexWithDescendant(node->getOctalCode(), args->codeBuffer); + VoxelNode* childNode = node->getChildAtIndex(childIndex); + + // If there is no child at the target location, then it likely means we were asked to delete a child out + // of a larger leaf voxel. We support this by breaking up the parent voxel into smaller pieces. + if (!childNode) { // we need to break up ancestors until we get to the right level - VoxelNode* ancestorNode = nodeToDelete; + VoxelNode* ancestorNode = node; while (true) { - int index = branchIndexWithDescendant(ancestorNode->getOctalCode(), codeBuffer); - for (int i = 0; i < 8; i++) { + int index = branchIndexWithDescendant(ancestorNode->getOctalCode(), args->codeBuffer); + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (i != index) { ancestorNode->addChildAtIndex(i); - if (nodeToDelete->isColored()) { - ancestorNode->getChildAtIndex(i)->setColor(nodeToDelete->getColor()); + if (node->isColored()) { + ancestorNode->getChildAtIndex(i)->setColor(node->getColor()); } } } - if (*ancestorNode->getOctalCode() == *codeBuffer - 1) { + int lengthOfancestorNode = numberOfThreeBitSectionsInCode(ancestorNode->getOctalCode()); + + // If we've reached the parent of the target, then stop breaking up children + if (lengthOfancestorNode == (args->lengthOfCode - 1)) { break; } ancestorNode->addChildAtIndex(index); ancestorNode = ancestorNode->getChildAtIndex(index); - if (nodeToDelete->isColored()) { - ancestorNode->setColor(nodeToDelete->getColor()); + if (node->isColored()) { + ancestorNode->setColor(node->getColor()); } } _isDirty = true; + args->pathChanged = true; + + // ends recursion, unwinds up stack + return; + } + + // recurse... + deleteVoxelCodeFromTreeRecursion(childNode, args); + + // If the lower level determined it needs to be deleted, then we should delete now. + if (args->deleteLastChild) { + if (args->stage) { + childNode->stageForDeletion(); + } else { + node->deleteChildAtIndex(childIndex); // note: this will track dirtiness and lastChanged for this node + if (_shouldReaverage) { + node->setColorFromAverageOfChildren(); + } + } + + // track our tree dirtiness + _isDirty = true; + + // track that path has changed + args->pathChanged = true; + + // If we're in collapseEmptyTrees mode, and this was the last child of this node, then we also want + // to delete this node. This will collapse the empty tree above us. + if (args->collapseEmptyTrees && node->getChildCount() == 0) { + // Can't delete the root this way. + if (node == rootNode) { + args->deleteLastChild = false; // reset so that further up the unwinding chain we don't do anything + } + } else { + args->deleteLastChild = false; // reset so that further up the unwinding chain we don't do anything + } + } + + // If the lower level did some work, then we need to track our lastChanged status. + if (args->pathChanged) { + node->markWithChangedTime(); } } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index fce051eda9..db7ad55ef7 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -10,7 +10,6 @@ #define __hifi__VoxelTree__ #include "SimpleMovingAverage.h" - #include "ViewFrustum.h" #include "VoxelNode.h" #include "VoxelNodeBag.h" @@ -104,6 +103,8 @@ public: void copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destinationNode); private: + void deleteVoxelCodeFromTreeRecursion(VoxelNode* node, void* extraData); + int encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor, bool includeExistsBits, From 736e38ceb0e03995148dcfb5f2575e68ffc3cdaf Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 7 Jun 2013 10:04:30 -0700 Subject: [PATCH 09/41] fix merge issue --- libraries/voxels/src/VoxelNode.h | 2 -- libraries/voxels/src/VoxelTree.cpp | 10 ---------- 2 files changed, 12 deletions(-) diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index adb0744e10..9250d76594 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -41,8 +41,6 @@ private: void init(unsigned char * octalCode); - double _lastChanged; - public: VoxelNode(); // root node constructor VoxelNode(unsigned char * octalCode); // regular constructor diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index cd3c0565a5..bc4d7569bf 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -274,16 +274,6 @@ public: bool pathChanged; }; -class DeleteVoxelCodeFromTreeArgs { -public: - bool stage; - bool collapseEmptyTrees; - unsigned char* codeBuffer; - int lengthOfCode; - bool deleteLastChild; - bool pathChanged; -}; - // Note: uses the codeColorBuffer format, but the color's are ignored, because // this only finds and deletes the node from the tree. void VoxelTree::deleteVoxelCodeFromTree(unsigned char* codeBuffer, bool stage, bool collapseEmptyTrees) { From e6b751e53840b2caad5203b4068146a2866c41a4 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Fri, 12 Jul 2013 14:32:14 -0700 Subject: [PATCH 10/41] more work on particle system --- interface/src/Application.cpp | 4 +- interface/src/ParticleSystem.cpp | 178 +++++++++++++++++++++---------- interface/src/ParticleSystem.h | 17 ++- 3 files changed, 138 insertions(+), 61 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6f70c89f3b..591889a83a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -73,7 +73,7 @@ using namespace std; static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; static char STAR_CACHE_FILE[] = "cachedStars.txt"; -static const bool TESTING_PARTICLE_SYSTEM = false; +static const bool TESTING_PARTICLE_SYSTEM = true; static const int BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH = 6; // farther dragged clicks are ignored @@ -2010,6 +2010,8 @@ void Application::update(float deltaTime) { #endif if (TESTING_PARTICLE_SYSTEM) { + glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.0f, 5.0f); + _particleSystem.setEmitterPosition(0, particleEmitterPosition); _particleSystem.simulate(deltaTime); } } diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index 3c27f3a8df..383f3eeecb 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -8,59 +8,91 @@ #include #include "InterfaceConfig.h" #include - #include "ParticleSystem.h" +#include "Application.h" ParticleSystem::ParticleSystem() { - _numberOfParticles = 1500; - assert(_numberOfParticles <= MAX_PARTICLES); - - _bounce = 0.9f; - _timer = 0.0f; - _airFriction = 6.0f; - _jitter = 0.1f; - _homeAttraction = 0.0f; - _tornadoForce = 0.0f; - _neighborAttraction = 0.02f; - _neighborRepulsion = 0.9f; - _tornadoAxis = glm::normalize(glm::vec3(0.1f, 1.0f, 0.1f)); - _home = glm::vec3(5.0f, 1.0f, 5.0f); - - _TEST_bigSphereRadius = 0.5f; + _gravity = 0.005; + _numEmitters = 1; + _bounce = 0.9f; + _timer = 0.0f; + _airFriction = 6.0f; + _jitter = 0.1f; + _homeAttraction = 0.0f; + _tornadoForce = 0.0f; + _neighborAttraction = 0.02f; + _neighborRepulsion = 0.9f; + _TEST_bigSphereRadius = 0.5f; _TEST_bigSpherePosition = glm::vec3( 5.0f, _TEST_bigSphereRadius, 5.0f); - - for (unsigned int p = 0; p < _numberOfParticles; p++) { - _particle[p].position = _home; - _particle[p].velocity = glm::vec3(0.0f, 0.0f, 0.0f); + _numParticles = 1500; + + for (unsigned int e = 0; e < _numEmitters; e++) { + + _emitter[e].position = glm::vec3(0.0f, 0.0f, 0.0f); + _emitter[e].rotation = glm::quat(); + _emitter[e].right = IDENTITY_RIGHT; + _emitter[e].up = IDENTITY_UP; + _emitter[e].front = IDENTITY_FRONT; + }; + + for (unsigned int p = 0; p < _numParticles; p++) { - float radian = ((float)p / (float)_numberOfParticles) * PI_TIMES_TWO; + float radian = ((float)p / (float)_numParticles) * PI_TIMES_TWO; float wave = sinf(radian); float red = 0.5f + 0.5f * wave; float green = 0.3f + 0.3f * wave; float blue = 0.2f - 0.2f * wave; - _particle[p].color = glm::vec3(red, green, blue); - _particle[p].age = 0.0f; - _particle[p].radius = 0.01f; + _particle[p].color = glm::vec3(red, green, blue); + _particle[p].age = 0.0f; + _particle[p].radius = 0.01f; + _particle[p].emitterIndex = 0; + _particle[p].position = glm::vec3(0.0f, 0.0f, 0.0f); + _particle[p].velocity = glm::vec3(0.0f, 0.0f, 0.0f); } + + assert(_numParticles <= MAX_PARTICLES); + assert(_numEmitters <= MAX_EMITTERS ); } + void ParticleSystem::simulate(float deltaTime) { - runSpecialEffectsTest(deltaTime); - - for (unsigned int p = 0; p < _numberOfParticles; p++) { + // update emitters + for (unsigned int e = 0; e < _numEmitters; e++) { + updateEmitter(e, deltaTime); + } + + // update particles + for (unsigned int p = 0; p < _numParticles; p++) { updateParticle(p, deltaTime); } + + // apply special effects + runSpecialEffectsTest(deltaTime); } +void ParticleSystem::updateEmitter(int e, float deltaTime) { + _emitter[e].front = _emitter[e].rotation * IDENTITY_FRONT; + _emitter[e].right = _emitter[e].rotation * IDENTITY_RIGHT; + _emitter[e].up = _emitter[e].rotation * IDENTITY_UP; +} void ParticleSystem::runSpecialEffectsTest(float deltaTime) { - + _timer += deltaTime; + + glm::vec3 tilt = glm::vec3 + ( + 30.0f * sinf( _timer * 0.55f ), + 0.0f, + 30.0f * cosf( _timer * 0.75f ) + ); + + _emitter[0].rotation = glm::quat(glm::radians(tilt)); _gravity = 0.01f + 0.01f * sinf( _timer * 0.52f ); _airFriction = 3.0f + 2.0f * sinf( _timer * 0.32f ); @@ -69,13 +101,6 @@ void ParticleSystem::runSpecialEffectsTest(float deltaTime) { _tornadoForce = 0.0f + 0.03f * sinf( _timer * 0.7f ); _neighborAttraction = 0.1f + 0.1f * cosf( _timer * 0.8f ); _neighborRepulsion = 0.4f + 0.3f * sinf( _timer * 0.4f ); - - _tornadoAxis = glm::vec3 - ( - 0.0f + 0.5f * sinf( _timer * 0.55f ), - 1.0f, - 0.0f + 0.5f * cosf( _timer * 0.75f ) - ); } @@ -95,12 +120,12 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { // apply attraction to home position - glm::vec3 vectorToHome = _home - _particle[p].position; + glm::vec3 vectorToHome = _emitter[_particle[p].emitterIndex].position - _particle[p].position; _particle[p].velocity += vectorToHome * _homeAttraction * deltaTime; // apply neighbor attraction int neighbor = p + 1; - if (neighbor == _numberOfParticles ) { + if (neighbor == _numParticles ) { neighbor = 0; } glm::vec3 vectorToNeighbor = _particle[p].position - _particle[neighbor].position; @@ -113,8 +138,9 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { } // apply tornado force - glm::vec3 tornadoDirection = glm::cross(vectorToHome, _tornadoAxis); - _particle[p].velocity += tornadoDirection * _tornadoForce * deltaTime; + //glm::vec3 tornadoDirection = glm::cross(vectorToHome, _emitter[_particle[p].emitterIndex].up); + //_particle[p].velocity += tornadoDirection * _tornadoForce * deltaTime; + //_particle[p].velocity += _emitter[_particle[p].emitterIndex].up * _tornadoForce * deltaTime; // apply air friction float drag = 1.0 - _airFriction * deltaTime; @@ -155,29 +181,69 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { void ParticleSystem::render() { - for (unsigned int p = 0; p < _numberOfParticles; p++) { - glColor3f(_particle[p].color.x, _particle[p].color.y, _particle[p].color.z); - glPushMatrix(); - glTranslatef(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z); - glutSolidSphere(_particle[p].radius, 6, 6); - glPopMatrix(); - - // render velocity lines - glColor4f( _particle[p].color.x, _particle[p].color.y, _particle[p].color.z, 0.5f); - glm::vec3 end = _particle[p].position - _particle[p].velocity * 2.0f; - glBegin(GL_LINES); - glVertex3f(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z); - glVertex3f(end.x, end.y, end.z); - - glEnd(); - + // render the emitters + for (unsigned int e = 0; e < _numEmitters; e++) { + renderEmitter(e, 0.2f); + }; + + // render the particles + for (unsigned int p = 0; p < _numParticles; p++) { + renderParticle(p); } } +void ParticleSystem::renderParticle(int p) { + + glColor3f(_particle[p].color.x, _particle[p].color.y, _particle[p].color.z); + glPushMatrix(); + glTranslatef(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z); + glutSolidSphere(_particle[p].radius, 6, 6); + glPopMatrix(); + + // render velocity lines + glColor4f( _particle[p].color.x, _particle[p].color.y, _particle[p].color.z, 0.5f); + glm::vec3 end = _particle[p].position - _particle[p].velocity * 2.0f; + glBegin(GL_LINES); + glVertex3f(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z); + glVertex3f(end.x, end.y, end.z); + + glEnd(); +} + + + +void ParticleSystem::renderEmitter(int e, float size) { + + glm::vec3 r = _emitter[e].right * size; + glm::vec3 u = _emitter[e].up * size; + glm::vec3 f = _emitter[e].front * size; + + glLineWidth(2.0f); + + glColor3f(0.8f, 0.4, 0.4); + glBegin(GL_LINES); + glVertex3f(_emitter[e].position.x, _emitter[e].position.y, _emitter[e].position.z); + glVertex3f(_emitter[e].position.x + r.x, _emitter[e].position.y + r.y, _emitter[e].position.z + r.z); + glEnd(); + + glColor3f(0.4f, 0.8, 0.4); + glBegin(GL_LINES); + glVertex3f(_emitter[e].position.x, _emitter[e].position.y, _emitter[e].position.z); + glVertex3f(_emitter[e].position.x + u.x, _emitter[e].position.y + u.y, _emitter[e].position.z + u.z); + glEnd(); + + glColor3f(0.4f, 0.4, 0.8); + glBegin(GL_LINES); + glVertex3f(_emitter[e].position.x, _emitter[e].position.y, _emitter[e].position.z); + glVertex3f(_emitter[e].position.x + f.x, _emitter[e].position.y + f.y, _emitter[e].position.z + f.z); + glEnd(); +} + + + - diff --git a/interface/src/ParticleSystem.h b/interface/src/ParticleSystem.h index 38eb0a1777..79dfeb4752 100644 --- a/interface/src/ParticleSystem.h +++ b/interface/src/ParticleSystem.h @@ -9,6 +9,8 @@ #ifndef hifi_ParticleSystem_h #define hifi_ParticleSystem_h +#include + const int MAX_PARTICLES = 5000; const int MAX_EMITTERS = 10; @@ -16,6 +18,7 @@ class ParticleSystem { public: ParticleSystem(); + void setEmitterPosition(int e, glm::vec3 position) { _emitter[e].position = position; } void simulate(float deltaTime); void render(); @@ -27,11 +30,15 @@ private: glm::vec3 color; float age; float radius; + int emitterIndex; }; struct Emitter { glm::vec3 position; - glm::vec3 direction; + glm::quat rotation; + glm::vec3 right; + glm::vec3 up; + glm::vec3 front; }; float _bounce; @@ -39,9 +46,8 @@ private: float _timer; Emitter _emitter[MAX_EMITTERS]; Particle _particle[MAX_PARTICLES]; - int _numberOfParticles; - glm::vec3 _home; - glm::vec3 _tornadoAxis; + int _numParticles; + int _numEmitters; float _airFriction; float _jitter; float _homeAttraction; @@ -52,8 +58,11 @@ private: glm::vec3 _TEST_bigSpherePosition; // private methods + void updateEmitter(int e, float deltaTime); void updateParticle(int index, float deltaTime); void runSpecialEffectsTest(float deltaTime); + void renderEmitter(int emitterIndex, float size); + void renderParticle(int p); }; #endif From 3649c89c1292cae62c66eac3f13ba78f10a5c790 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Fri, 12 Jul 2013 16:19:31 -0700 Subject: [PATCH 11/41] more developing on the API for the particle system --- interface/src/Application.cpp | 28 +++++-- interface/src/Application.h | 1 + interface/src/ParticleSystem.cpp | 137 +++++++++++++++++++++---------- interface/src/ParticleSystem.h | 16 ++-- 4 files changed, 127 insertions(+), 55 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 591889a83a..209282b926 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -172,6 +172,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _frameCount(0), _fps(120.0f), _justStarted(true), + _particleSystemInitialized(false), _wantToKillLocalVoxels(false), _frustumDrawingMode(FRUSTUM_DRAW_MODE_ALL), _viewFrustumOffsetYaw(-135.0), @@ -1749,9 +1750,10 @@ void Application::init() { _palette.addTool(&_swatch); _palette.addAction(_colorVoxelMode, 0, 2); _palette.addAction(_eyedropperMode, 0, 3); - _palette.addAction(_selectVoxelMode, 0, 4); + _palette.addAction(_selectVoxelMode, 0, 4); } + const float MAX_AVATAR_EDIT_VELOCITY = 1.0f; const float MAX_VOXEL_EDIT_DISTANCE = 20.0f; const float HEAD_SPHERE_RADIUS = 0.07; @@ -2010,9 +2012,23 @@ void Application::update(float deltaTime) { #endif if (TESTING_PARTICLE_SYSTEM) { - glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.0f, 5.0f); - _particleSystem.setEmitterPosition(0, particleEmitterPosition); - _particleSystem.simulate(deltaTime); + if (_particleSystemInitialized) { + _particleSystem.simulate(deltaTime); + } else { + int coolDemoEmitter = _particleSystem.addEmitter(); + + if (coolDemoEmitter != -1) { + glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.3f, 5.0f); + _particleSystem.setEmitterPosition(coolDemoEmitter, particleEmitterPosition); + _particleSystem.emitParticlesNow(coolDemoEmitter, 1500); + } + + glm::vec3 collisionSpherePosition = glm::vec3( 5.0f, 0.5f, 5.0f ); + float collisionSphereRadius = 0.5f; + _particleSystem.setCollisionSphere(collisionSpherePosition, collisionSphereRadius); + _particleSystemInitialized = true; + _particleSystem.useOrangeBlueColorPalette(); + } } } @@ -2459,7 +2475,9 @@ void Application::displaySide(Camera& whichCamera) { } if (TESTING_PARTICLE_SYSTEM) { - _particleSystem.render(); + if (_particleSystemInitialized) { + _particleSystem.render(); + } } // Render the world box diff --git a/interface/src/Application.h b/interface/src/Application.h index c6bbd4eec2..37a8b40964 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -278,6 +278,7 @@ private: timeval _timerStart, _timerEnd; timeval _lastTimeUpdated; bool _justStarted; + bool _particleSystemInitialized; Stars _stars; diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index 383f3eeecb..0e762fdb0e 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -13,22 +13,22 @@ ParticleSystem::ParticleSystem() { - _gravity = 0.005; - _numEmitters = 1; - _bounce = 0.9f; - _timer = 0.0f; - _airFriction = 6.0f; - _jitter = 0.1f; - _homeAttraction = 0.0f; - _tornadoForce = 0.0f; - _neighborAttraction = 0.02f; - _neighborRepulsion = 0.9f; - _TEST_bigSphereRadius = 0.5f; - _TEST_bigSpherePosition = glm::vec3( 5.0f, _TEST_bigSphereRadius, 5.0f); - _numParticles = 1500; - - for (unsigned int e = 0; e < _numEmitters; e++) { + _gravity = 0.005; + _numEmitters = 0; + _bounce = 0.9f; + _timer = 0.0f; + _airFriction = 6.0f; + _jitter = 0.1f; + _homeAttraction = 0.0f; + _tornadoForce = 0.0f; + _neighborAttraction = 0.02f; + _neighborRepulsion = 0.9f; + _collisionSphereRadius = 0.0f; + _collisionSpherePosition = glm::vec3(0.0f, 0.0f, 0.0f); + _numParticles = 0; + _usingCollisionSphere = false; + for (unsigned int e = 0; e < MAX_EMITTERS; e++) { _emitter[e].position = glm::vec3(0.0f, 0.0f, 0.0f); _emitter[e].rotation = glm::quat(); _emitter[e].right = IDENTITY_RIGHT; @@ -36,25 +36,25 @@ ParticleSystem::ParticleSystem() { _emitter[e].front = IDENTITY_FRONT; }; - for (unsigned int p = 0; p < _numParticles; p++) { - - float radian = ((float)p / (float)_numParticles) * PI_TIMES_TWO; - float wave = sinf(radian); - - float red = 0.5f + 0.5f * wave; - float green = 0.3f + 0.3f * wave; - float blue = 0.2f - 0.2f * wave; - - _particle[p].color = glm::vec3(red, green, blue); + for (unsigned int p = 0; p < MAX_PARTICLES; p++) { + _particle[p].alive = false; _particle[p].age = 0.0f; _particle[p].radius = 0.01f; _particle[p].emitterIndex = 0; _particle[p].position = glm::vec3(0.0f, 0.0f, 0.0f); _particle[p].velocity = glm::vec3(0.0f, 0.0f, 0.0f); + } +} + + +int ParticleSystem::addEmitter() { + _numEmitters ++; + + if (_numEmitters > MAX_EMITTERS) { + return -1; } - assert(_numParticles <= MAX_PARTICLES); - assert(_numEmitters <= MAX_EMITTERS ); + return _numEmitters - 1; } @@ -67,9 +67,11 @@ void ParticleSystem::simulate(float deltaTime) { // update particles for (unsigned int p = 0; p < _numParticles; p++) { - updateParticle(p, deltaTime); + if (_particle[p].alive) { + updateParticle(p, deltaTime); + } } - + // apply special effects runSpecialEffectsTest(deltaTime); } @@ -81,6 +83,40 @@ void ParticleSystem::updateEmitter(int e, float deltaTime) { _emitter[e].up = _emitter[e].rotation * IDENTITY_UP; } + + +void ParticleSystem::emitParticlesNow(int e, int num) { + + _numParticles = num; + + if (_numParticles > MAX_PARTICLES) { + _numParticles = MAX_PARTICLES; + } + + for (unsigned int p = 0; p < num; p++) { + _particle[p].alive = true; + _particle[p].position = _emitter[e].position; + } +} + +void ParticleSystem::useOrangeBlueColorPalette() { + + for (unsigned int p = 0; p < _numParticles; p++) { + + float radian = ((float)p / (float)_numParticles) * PI_TIMES_TWO; + float wave = sinf(radian); + float red = 0.5f + 0.5f * wave; + float green = 0.3f + 0.3f * wave; + float blue = 0.2f - 0.2f * wave; + _particle[p].color = glm::vec3(red, green, blue); + } +} + + + + + + void ParticleSystem::runSpecialEffectsTest(float deltaTime) { _timer += deltaTime; @@ -93,14 +129,18 @@ void ParticleSystem::runSpecialEffectsTest(float deltaTime) { ); _emitter[0].rotation = glm::quat(glm::radians(tilt)); - - _gravity = 0.01f + 0.01f * sinf( _timer * 0.52f ); - _airFriction = 3.0f + 2.0f * sinf( _timer * 0.32f ); + + _gravity = 0.0f + 0.02f * sinf( _timer * 0.52f ); + _airFriction = 3.0f + 1.0f * sinf( _timer * 0.32f ); _jitter = 0.05f + 0.05f * sinf( _timer * 0.42f ); _homeAttraction = 0.01f + 0.01f * cosf( _timer * 0.6f ); _tornadoForce = 0.0f + 0.03f * sinf( _timer * 0.7f ); _neighborAttraction = 0.1f + 0.1f * cosf( _timer * 0.8f ); _neighborRepulsion = 0.4f + 0.3f * sinf( _timer * 0.4f ); + + if (_gravity < 0.0f) { + _gravity = 0.0f; + } } @@ -118,7 +158,6 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { -_jitter * ONE_HALF + _jitter * randFloat() ) * deltaTime; - // apply attraction to home position glm::vec3 vectorToHome = _emitter[_particle[p].emitterIndex].position - _particle[p].position; _particle[p].velocity += vectorToHome * _homeAttraction * deltaTime; @@ -138,9 +177,8 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { } // apply tornado force - //glm::vec3 tornadoDirection = glm::cross(vectorToHome, _emitter[_particle[p].emitterIndex].up); - //_particle[p].velocity += tornadoDirection * _tornadoForce * deltaTime; - //_particle[p].velocity += _emitter[_particle[p].emitterIndex].up * _tornadoForce * deltaTime; + glm::vec3 tornadoDirection = glm::cross(vectorToHome, _emitter[_particle[p].emitterIndex].up); + _particle[p].velocity += tornadoDirection * _tornadoForce * deltaTime; // apply air friction float drag = 1.0 - _airFriction * deltaTime; @@ -166,18 +204,25 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { } // collision with sphere - glm::vec3 vectorToSphereCenter = _TEST_bigSpherePosition - _particle[p].position; - float distanceToSphereCenter = glm::length(vectorToSphereCenter); - float combinedRadius = _TEST_bigSphereRadius + _particle[p].radius; - if (distanceToSphereCenter < combinedRadius) { - - if (distanceToSphereCenter > 0.0f){ - glm::vec3 directionToSphereCenter = vectorToSphereCenter / distanceToSphereCenter; - _particle[p].position = _TEST_bigSpherePosition - directionToSphereCenter * combinedRadius; + if (_usingCollisionSphere) { + glm::vec3 vectorToSphereCenter = _collisionSpherePosition - _particle[p].position; + float distanceToSphereCenter = glm::length(vectorToSphereCenter); + float combinedRadius = _collisionSphereRadius + _particle[p].radius; + if (distanceToSphereCenter < combinedRadius) { + + if (distanceToSphereCenter > 0.0f){ + glm::vec3 directionToSphereCenter = vectorToSphereCenter / distanceToSphereCenter; + _particle[p].position = _collisionSpherePosition - directionToSphereCenter * combinedRadius; + } } } } +void ParticleSystem::setCollisionSphere(glm::vec3 position, float radius) { + _usingCollisionSphere = true; + _collisionSpherePosition = position; + _collisionSphereRadius = radius; +} void ParticleSystem::render() { @@ -188,7 +233,9 @@ void ParticleSystem::render() { // render the particles for (unsigned int p = 0; p < _numParticles; p++) { - renderParticle(p); + if (_particle[p].alive) { + renderParticle(p); + } } } diff --git a/interface/src/ParticleSystem.h b/interface/src/ParticleSystem.h index 79dfeb4752..701d1c85b7 100644 --- a/interface/src/ParticleSystem.h +++ b/interface/src/ParticleSystem.h @@ -18,13 +18,18 @@ class ParticleSystem { public: ParticleSystem(); - void setEmitterPosition(int e, glm::vec3 position) { _emitter[e].position = position; } - void simulate(float deltaTime); - void render(); + int addEmitter(); // add (create) an emitter and get its unique id + void useOrangeBlueColorPalette(); // apply a nice preset color palette to the particles + void setCollisionSphere(glm::vec3 position, float radius); // specify a sphere for the particles to collide with + void emitParticlesNow(int e, int numParticles); // tell this emitter to generate this many particles right now + void simulate(float deltaTime); // run it + void render(); // show it + void setEmitterPosition(int e, glm::vec3 position) { _emitter[e].position = position; } // set the position of this emitter private: struct Particle { + bool alive; glm::vec3 position; glm::vec3 velocity; glm::vec3 color; @@ -54,8 +59,9 @@ private: float _tornadoForce; float _neighborAttraction; float _neighborRepulsion; - float _TEST_bigSphereRadius; - glm::vec3 _TEST_bigSpherePosition; + bool _usingCollisionSphere; + glm::vec3 _collisionSpherePosition; + float _collisionSphereRadius; // private methods void updateEmitter(int e, float deltaTime); From ae99ca5ec8846b12ecb496c57945078bcdce944c Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Fri, 12 Jul 2013 18:55:42 -0700 Subject: [PATCH 12/41] added more API for the particle system --- interface/src/Application.cpp | 26 ++++++-- interface/src/ParticleSystem.cpp | 111 +++++++++++++++++++------------ interface/src/ParticleSystem.h | 45 +++++++------ 3 files changed, 116 insertions(+), 66 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 209282b926..6ec2f7a2e2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2011,23 +2011,37 @@ void Application::update(float deltaTime) { _audio.eventuallyAnalyzePing(); #endif + if (TESTING_PARTICLE_SYSTEM) { if (_particleSystemInitialized) { - _particleSystem.simulate(deltaTime); - } else { - int coolDemoEmitter = _particleSystem.addEmitter(); + // update the particle system + _particleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f)); + _particleSystem.simulate(deltaTime); + _particleSystem.runSpecialEffectsTest(deltaTime); + } else { + // create a stable test emitter and spit out a bunch of particles + int coolDemoEmitter = _particleSystem.addEmitter(); if (coolDemoEmitter != -1) { - glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.3f, 5.0f); + glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.0f, 5.0f); _particleSystem.setEmitterPosition(coolDemoEmitter, particleEmitterPosition); - _particleSystem.emitParticlesNow(coolDemoEmitter, 1500); + float radius = 0.01f; + glm::vec4 color(0.0f, 0.0f, 0.0f, 1.0f); + glm::vec3 velocity(0.0f, 0.1f, 0.0f); + float lifespan = 100000.0f; + _particleSystem.emitParticlesNow(coolDemoEmitter, 1500, radius, color, velocity, lifespan); } + // determine a collision sphere glm::vec3 collisionSpherePosition = glm::vec3( 5.0f, 0.5f, 5.0f ); float collisionSphereRadius = 0.5f; _particleSystem.setCollisionSphere(collisionSpherePosition, collisionSphereRadius); + + // signal that the particle system has been initialized _particleSystemInitialized = true; - _particleSystem.useOrangeBlueColorPalette(); + + // apply a preset color palette + _particleSystem.setOrangeBlueColorPalette(); } } } diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index 0e762fdb0e..e6a3bfef7b 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -11,22 +11,28 @@ #include "ParticleSystem.h" #include "Application.h" +const float DEFAULT_PARTICLE_BOUNCE = 1.0f; +const float DEFAULT_PARTICLE_AIR_FRICTION = 2.0f; +const float DEFAULT_PARTICLE_JITTER = 0.05f; +const float DEFAULT_PARTICLE_GRAVITY = 0.05f; + ParticleSystem::ParticleSystem() { - _gravity = 0.005; - _numEmitters = 0; - _bounce = 0.9f; _timer = 0.0f; - _airFriction = 6.0f; - _jitter = 0.1f; - _homeAttraction = 0.0f; + _numEmitters = 0; + _gravity = DEFAULT_PARTICLE_GRAVITY; + _bounce = DEFAULT_PARTICLE_BOUNCE; + _airFriction = DEFAULT_PARTICLE_AIR_FRICTION; + _jitter = DEFAULT_PARTICLE_JITTER; + _emitterAttraction = 0.0f; _tornadoForce = 0.0f; - _neighborAttraction = 0.02f; - _neighborRepulsion = 0.9f; + _neighborAttraction = 0.0f; + _neighborRepulsion = 0.0f; _collisionSphereRadius = 0.0f; _collisionSpherePosition = glm::vec3(0.0f, 0.0f, 0.0f); _numParticles = 0; _usingCollisionSphere = false; + _upDirection = glm::vec3(0.0f, 1.0f, 0.0f); // default for (unsigned int e = 0; e < MAX_EMITTERS; e++) { _emitter[e].position = glm::vec3(0.0f, 0.0f, 0.0f); @@ -39,7 +45,8 @@ ParticleSystem::ParticleSystem() { for (unsigned int p = 0; p < MAX_PARTICLES; p++) { _particle[p].alive = false; _particle[p].age = 0.0f; - _particle[p].radius = 0.01f; + _particle[p].lifespan = 0.0f; + _particle[p].radius = 0.0f; _particle[p].emitterIndex = 0; _particle[p].position = glm::vec3(0.0f, 0.0f, 0.0f); _particle[p].velocity = glm::vec3(0.0f, 0.0f, 0.0f); @@ -71,9 +78,6 @@ void ParticleSystem::simulate(float deltaTime) { updateParticle(p, deltaTime); } } - - // apply special effects - runSpecialEffectsTest(deltaTime); } void ParticleSystem::updateEmitter(int e, float deltaTime) { @@ -84,39 +88,63 @@ void ParticleSystem::updateEmitter(int e, float deltaTime) { } - -void ParticleSystem::emitParticlesNow(int e, int num) { - - _numParticles = num; - - if (_numParticles > MAX_PARTICLES) { - _numParticles = MAX_PARTICLES; - } +void ParticleSystem::emitParticlesNow(int e, int num, float radius, glm::vec4 color, glm::vec3 velocity, float lifespan) { for (unsigned int p = 0; p < num; p++) { - _particle[p].alive = true; - _particle[p].position = _emitter[e].position; + createParticle(_emitter[e].position, velocity, radius, color, lifespan); } } -void ParticleSystem::useOrangeBlueColorPalette() { +void ParticleSystem::createParticle(glm::vec3 position, glm::vec3 velocity, float radius, glm::vec4 color, float lifespan) { + + for (unsigned int p = 0; p < MAX_PARTICLES; p++) { + if (!_particle[p].alive) { + + _particle[p].lifespan = lifespan; + _particle[p].alive = true; + _particle[p].age = 0.0f; + _particle[p].position = position; + _particle[p].velocity = velocity; + _particle[p].radius = radius; + _particle[p].color = color; + + _numParticles ++; + + assert(_numParticles <= MAX_PARTICLES); + + return; + } + } +} + +void ParticleSystem::killParticle(int p) { + + assert( p >= 0); + assert( p < MAX_PARTICLES); + assert( _numParticles > 0); + + _particle[p].alive = false; + _numParticles --; +} + + +void ParticleSystem::setOrangeBlueColorPalette() { for (unsigned int p = 0; p < _numParticles; p++) { float radian = ((float)p / (float)_numParticles) * PI_TIMES_TWO; float wave = sinf(radian); + float red = 0.5f + 0.5f * wave; float green = 0.3f + 0.3f * wave; float blue = 0.2f - 0.2f * wave; - _particle[p].color = glm::vec3(red, green, blue); + float alpha = 1.0f; + + _particle[p].color = glm::vec4(red, green, blue, alpha); } } - - - - void ParticleSystem::runSpecialEffectsTest(float deltaTime) { _timer += deltaTime; @@ -130,13 +158,13 @@ void ParticleSystem::runSpecialEffectsTest(float deltaTime) { _emitter[0].rotation = glm::quat(glm::radians(tilt)); - _gravity = 0.0f + 0.02f * sinf( _timer * 0.52f ); - _airFriction = 3.0f + 1.0f * sinf( _timer * 0.32f ); - _jitter = 0.05f + 0.05f * sinf( _timer * 0.42f ); - _homeAttraction = 0.01f + 0.01f * cosf( _timer * 0.6f ); - _tornadoForce = 0.0f + 0.03f * sinf( _timer * 0.7f ); - _neighborAttraction = 0.1f + 0.1f * cosf( _timer * 0.8f ); - _neighborRepulsion = 0.4f + 0.3f * sinf( _timer * 0.4f ); + _gravity = 0.0f + DEFAULT_PARTICLE_GRAVITY * sinf( _timer * 0.52f ); + _airFriction = (DEFAULT_PARTICLE_AIR_FRICTION + 0.5f) + 2.0f * sinf( _timer * 0.32f ); + _jitter = DEFAULT_PARTICLE_JITTER + DEFAULT_PARTICLE_JITTER * sinf( _timer * 0.42f ); + _emitterAttraction = 0.015f + 0.015f * cosf( _timer * 0.6f ); + _tornadoForce = 0.0f + 0.03f * sinf( _timer * 0.7f ); + _neighborAttraction = 0.1f + 0.1f * cosf( _timer * 0.8f ); + _neighborRepulsion = 0.2f + 0.2f * sinf( _timer * 0.4f ); if (_gravity < 0.0f) { _gravity = 0.0f; @@ -144,10 +172,13 @@ void ParticleSystem::runSpecialEffectsTest(float deltaTime) { } - void ParticleSystem::updateParticle(int p, float deltaTime) { _particle[p].age += deltaTime; + + if (_particle[p].age > _particle[p].lifespan) { + killParticle(p); + } // apply random jitter _particle[p].velocity += @@ -160,7 +191,7 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { // apply attraction to home position glm::vec3 vectorToHome = _emitter[_particle[p].emitterIndex].position - _particle[p].position; - _particle[p].velocity += vectorToHome * _homeAttraction * deltaTime; + _particle[p].velocity += vectorToHome * _emitterAttraction * deltaTime; // apply neighbor attraction int neighbor = p + 1; @@ -189,7 +220,7 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { } // apply gravity - _particle[p].velocity.y -= _gravity * deltaTime; + _particle[p].velocity -= _upDirection * _gravity * deltaTime; // update position by velocity _particle[p].position += _particle[p].velocity; @@ -239,11 +270,9 @@ void ParticleSystem::render() { } } - - void ParticleSystem::renderParticle(int p) { - glColor3f(_particle[p].color.x, _particle[p].color.y, _particle[p].color.z); + glColor4f(_particle[p].color.r, _particle[p].color.g, _particle[p].color.b, _particle[p].color.a ); glPushMatrix(); glTranslatef(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z); glutSolidSphere(_particle[p].radius, 6, 6); diff --git a/interface/src/ParticleSystem.h b/interface/src/ParticleSystem.h index 701d1c85b7..f7f0063dbc 100644 --- a/interface/src/ParticleSystem.h +++ b/interface/src/ParticleSystem.h @@ -11,33 +11,27 @@ #include -const int MAX_PARTICLES = 5000; +const int MAX_PARTICLES = 10000; const int MAX_EMITTERS = 10; class ParticleSystem { public: ParticleSystem(); - int addEmitter(); // add (create) an emitter and get its unique id - void useOrangeBlueColorPalette(); // apply a nice preset color palette to the particles + int addEmitter(); // add (create) an emitter and get its unique id + void emitParticlesNow(int e, int numParticles, float radius, glm::vec4 color, glm::vec3 velocity, float lifespan); + void simulate(float deltaTime); + void render(); + void runSpecialEffectsTest(float deltaTime); // for debugging and artistic exploration + + void setOrangeBlueColorPalette(); // apply a nice preset color palette to the particles void setCollisionSphere(glm::vec3 position, float radius); // specify a sphere for the particles to collide with - void emitParticlesNow(int e, int numParticles); // tell this emitter to generate this many particles right now - void simulate(float deltaTime); // run it - void render(); // show it void setEmitterPosition(int e, glm::vec3 position) { _emitter[e].position = position; } // set the position of this emitter + void setEmitterRotation(int e, glm::quat rotation) { _emitter[e].rotation = rotation; } // set the rotation of this emitter + void setUpDirection(glm::vec3 upDirection) {_upDirection = upDirection;} // tell particle system which direction is up private: - struct Particle { - bool alive; - glm::vec3 position; - glm::vec3 velocity; - glm::vec3 color; - float age; - float radius; - int emitterIndex; - }; - struct Emitter { glm::vec3 position; glm::quat rotation; @@ -45,7 +39,19 @@ private: glm::vec3 up; glm::vec3 front; }; - + + struct Particle { + bool alive; // is the particle active? + glm::vec3 position; // position + glm::vec3 velocity; // velocity + glm::vec4 color; // color (rgba) + float age; // age in seconds + float radius; // radius + float lifespan; // how long this particle stays alive (in seconds) + int emitterIndex; // which emitter created this particle? + }; + + glm::vec3 _upDirection; float _bounce; float _gravity; float _timer; @@ -55,7 +61,7 @@ private: int _numEmitters; float _airFriction; float _jitter; - float _homeAttraction; + float _emitterAttraction; float _tornadoForce; float _neighborAttraction; float _neighborRepulsion; @@ -66,7 +72,8 @@ private: // private methods void updateEmitter(int e, float deltaTime); void updateParticle(int index, float deltaTime); - void runSpecialEffectsTest(float deltaTime); + void createParticle(glm::vec3 position, glm::vec3 velocity, float radius, glm::vec4 color, float lifespan); + void killParticle(int p); void renderEmitter(int emitterIndex, float size); void renderParticle(int p); }; From 3bc6b4c0d4648c7cf190bee683fc44f2fb871672 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Fri, 12 Jul 2013 18:56:54 -0700 Subject: [PATCH 13/41] merge --- interface/src/Avatar.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 interface/src/Avatar.cpp diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp old mode 100755 new mode 100644 From 8b9e0426b24e6ec01ca53b9ec75683aadbb8fbcc Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 12 Jul 2013 21:34:48 -0700 Subject: [PATCH 14/41] Simple glassy collision sound --- interface/src/Application.h | 1 + interface/src/Audio.cpp | 25 ++++++++++++++++++++++--- interface/src/Audio.h | 6 +++++- interface/src/Avatar.cpp | 8 ++++++++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.h b/interface/src/Application.h index c6bbd4eec2..9e8e359479 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -84,6 +84,7 @@ public: const glm::vec3 getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel); Avatar* getAvatar() { return &_myAvatar; } + Audio* getAudio() { return &_audio; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } VoxelSystem* getVoxels() { return &_voxels; } diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 7af42478d5..540e7b1e1e 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -326,7 +326,9 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : _lastYawMeasuredMaximum(0), _flangeIntensity(0.0f), _flangeRate(0.0f), - _flangeWeight(0.0f) + _flangeWeight(0.0f), + _collisionSoundMagnitude(0.0f), + _proceduralEffectSample(0) { outputPortAudioError(Pa_Initialize()); @@ -591,12 +593,29 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) { float speed = glm::length(_lastVelocity); float volume = VOLUME_BASELINE * (1.f - speed / MAX_AUDIBLE_VELOCITY); + // Test tone (should be continuous!) + /* + for (int i = 0; i < numSamples; i++) { + inputBuffer[i] += (int16_t) (_proceduralEffectSample + i)%16 * 10; + }*/ + // Add a noise-modulated sinewave with volume that tapers off with speed increasing - if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { + if (0) { //((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { for (int i = 0; i < numSamples; i++) { - inputBuffer[i] += (int16_t)((sinf((float) i / SOUND_PITCH * speed) * randFloat()) * volume * speed); + inputBuffer[i] += (int16_t)((sinf((float) (_proceduralEffectSample + i) / SOUND_PITCH * speed) * (1.f + randFloat() * 0.0f)) * volume * speed); } } + const float COLLISION_SOUND_CUTOFF_LEVEL = 5.0f; + const float COLLISION_SOUND_PITCH_1 = 2.0f; + const float COLLISION_SOUND_DECAY = 1.f/1024.f; + const float COLLISION_VOLUME_BASELINE = 10.f; + if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) { + for (int i = 0; i < numSamples; i++) { + inputBuffer[i] += (int16_t) ((sinf((float) (_proceduralEffectSample + i) / COLLISION_SOUND_PITCH_1) * COLLISION_VOLUME_BASELINE * _collisionSoundMagnitude)); + _collisionSoundMagnitude *= (1.f - COLLISION_SOUND_DECAY); + } + } + _proceduralEffectSample += numSamples; } // ----------------------------------------------------------- diff --git a/interface/src/Audio.h b/interface/src/Audio.h index a3c8cf1046..78b298644b 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -44,6 +44,8 @@ public: void lowPassFilter(int16_t* inputBuffer); + void setCollisionSoundMagnitude(float collisionSoundMagnitude) { _collisionSoundMagnitude = collisionSoundMagnitude; } + void ping(); // Call periodically to eventually perform round trip time analysis, @@ -81,7 +83,9 @@ private: float _flangeIntensity; float _flangeRate; float _flangeWeight; - + float _collisionSoundMagnitude; + int _proceduralEffectSample; + // Audio callback in class context. inline void performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 881b436bf2..7d306b307a 100755 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -873,6 +873,7 @@ void Avatar::updateCollisionWithEnvironment() { _position - up * (_pelvisFloatingHeight - radius), _position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) { applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING); + } } @@ -910,6 +911,13 @@ void Avatar::applyHardCollision(const glm::vec3& penetration, float elasticity, // If moving really slowly after a collision, and not applying forces, stop altogether _velocity *= 0.f; } + // Push the collision into the audio system for procedural effects + const float AUDIBLE_COLLISION_THRESHOLD = 200.f; + const float COLLISION_VOLUME = 10000.f; + float collisionSoundLevel = penetrationLength * COLLISION_VOLUME; + if (collisionSoundLevel > AUDIBLE_COLLISION_THRESHOLD) { + Application::getInstance()->getAudio()->setCollisionSoundMagnitude(collisionSoundLevel); + } } } From 84b6adf5b05f5a725fa04371002579dc4febd5f0 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 15 Jul 2013 13:57:39 -0700 Subject: [PATCH 15/41] more work on particle emitter API --- interface/src/Application.cpp | 88 ++++++++++++++---- interface/src/Application.h | 2 + interface/src/ParticleSystem.cpp | 154 ++++++++++++++++--------------- interface/src/ParticleSystem.h | 35 +++---- 4 files changed, 171 insertions(+), 108 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6ec2f7a2e2..6f5fffd68c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -172,7 +172,9 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _frameCount(0), _fps(120.0f), _justStarted(true), - _particleSystemInitialized(false), + _particleSystemInitialized(false), + _coolDemoParticleEmitter(-1), + _fingerParticleEmitter(-1), _wantToKillLocalVoxels(false), _frustumDrawingMode(FRUSTUM_DRAW_MODE_ALL), _viewFrustumOffsetYaw(-135.0), @@ -2013,35 +2015,89 @@ void Application::update(float deltaTime) { if (TESTING_PARTICLE_SYSTEM) { - if (_particleSystemInitialized) { + if (!_particleSystemInitialized) { - // update the particle system - _particleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f)); - _particleSystem.simulate(deltaTime); - _particleSystem.runSpecialEffectsTest(deltaTime); - } else { // create a stable test emitter and spit out a bunch of particles - int coolDemoEmitter = _particleSystem.addEmitter(); - if (coolDemoEmitter != -1) { + _coolDemoParticleEmitter = _particleSystem.addEmitter(); + _fingerParticleEmitter = _particleSystem.addEmitter(); + + if (_coolDemoParticleEmitter != -1) { + _particleSystem.setShowingEmitter(_coolDemoParticleEmitter, true); glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.0f, 5.0f); - _particleSystem.setEmitterPosition(coolDemoEmitter, particleEmitterPosition); + _particleSystem.setEmitterPosition(_coolDemoParticleEmitter, particleEmitterPosition); float radius = 0.01f; glm::vec4 color(0.0f, 0.0f, 0.0f, 1.0f); glm::vec3 velocity(0.0f, 0.1f, 0.0f); float lifespan = 100000.0f; - _particleSystem.emitParticlesNow(coolDemoEmitter, 1500, radius, color, velocity, lifespan); + + // determine a collision sphere + glm::vec3 collisionSpherePosition = glm::vec3( 5.0f, 0.5f, 5.0f ); + float collisionSphereRadius = 0.5f; + _particleSystem.setCollisionSphere(_coolDemoParticleEmitter, collisionSpherePosition, collisionSphereRadius); + _particleSystem.emitParticlesNow(_coolDemoParticleEmitter, 1500, radius, color, velocity, lifespan); + } + + if (_fingerParticleEmitter != -1) { + _particleSystem.setShowingEmitter(_fingerParticleEmitter, false); } - // determine a collision sphere - glm::vec3 collisionSpherePosition = glm::vec3( 5.0f, 0.5f, 5.0f ); - float collisionSphereRadius = 0.5f; - _particleSystem.setCollisionSphere(collisionSpherePosition, collisionSphereRadius); // signal that the particle system has been initialized _particleSystemInitialized = true; // apply a preset color palette - _particleSystem.setOrangeBlueColorPalette(); + _particleSystem.setOrangeBlueColorPalette(); + } else { + // update the particle system + + + static float t = 0.0f; + t += deltaTime; + + + if (_coolDemoParticleEmitter != -1) { + + glm::vec3 tilt = glm::vec3 + ( + 30.0f * sinf( t * 0.55f ), + 0.0f, + 30.0f * cosf( t * 0.75f ) + ); + + _particleSystem.setEmitterRotation(_coolDemoParticleEmitter, glm::quat(glm::radians(tilt))); + } + + if (_fingerParticleEmitter != -1) { + + glm::vec3 particleEmitterPosition = + glm::vec3 + ( + 3.0f + sinf(t * 8.0f) * 0.02f, + 1.0f + cosf(t * 9.0f) * 0.02f, + 3.0f + sinf(t * 7.0f) * 0.02f + ); + + glm::vec3 tilt = glm::vec3 + ( + 30.0f * sinf( t * 0.55f ), + 0.0f, + 30.0f * cosf( t * 0.75f ) + ); + + glm::quat particleEmitterRotation = glm::quat(glm::radians(tilt)); + + _particleSystem.setEmitterPosition(_fingerParticleEmitter, particleEmitterPosition); + _particleSystem.setEmitterRotation(_fingerParticleEmitter, particleEmitterRotation); + + float radius = 0.01f; + glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); + glm::vec3 velocity(0.0f, 0.01f, 0.0f); + float lifespan = 0.4f; + _particleSystem.emitParticlesNow(_fingerParticleEmitter, 1, radius, color, velocity, lifespan); + } + + _particleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f)); + _particleSystem.simulate(deltaTime); } } } diff --git a/interface/src/Application.h b/interface/src/Application.h index 37a8b40964..879f039f8c 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -279,6 +279,8 @@ private: timeval _lastTimeUpdated; bool _justStarted; bool _particleSystemInitialized; + int _coolDemoParticleEmitter; + int _fingerParticleEmitter; Stars _stars; diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index e6a3bfef7b..14aaedbac9 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -13,33 +13,34 @@ const float DEFAULT_PARTICLE_BOUNCE = 1.0f; const float DEFAULT_PARTICLE_AIR_FRICTION = 2.0f; -const float DEFAULT_PARTICLE_JITTER = 0.05f; const float DEFAULT_PARTICLE_GRAVITY = 0.05f; ParticleSystem::ParticleSystem() { - _timer = 0.0f; - _numEmitters = 0; - _gravity = DEFAULT_PARTICLE_GRAVITY; - _bounce = DEFAULT_PARTICLE_BOUNCE; - _airFriction = DEFAULT_PARTICLE_AIR_FRICTION; - _jitter = DEFAULT_PARTICLE_JITTER; - _emitterAttraction = 0.0f; - _tornadoForce = 0.0f; - _neighborAttraction = 0.0f; - _neighborRepulsion = 0.0f; - _collisionSphereRadius = 0.0f; - _collisionSpherePosition = glm::vec3(0.0f, 0.0f, 0.0f); - _numParticles = 0; - _usingCollisionSphere = false; - _upDirection = glm::vec3(0.0f, 1.0f, 0.0f); // default - + _timer = 0.0f; + _numEmitters = 0; + _numParticles = 0; + _upDirection = glm::vec3(0.0f, 1.0f, 0.0f); // default + for (unsigned int e = 0; e < MAX_EMITTERS; e++) { - _emitter[e].position = glm::vec3(0.0f, 0.0f, 0.0f); - _emitter[e].rotation = glm::quat(); - _emitter[e].right = IDENTITY_RIGHT; - _emitter[e].up = IDENTITY_UP; - _emitter[e].front = IDENTITY_FRONT; + _emitter[e].position = glm::vec3(0.0f, 0.0f, 0.0f); + _emitter[e].rotation = glm::quat(); + _emitter[e].right = IDENTITY_RIGHT; + _emitter[e].up = IDENTITY_UP; + _emitter[e].front = IDENTITY_FRONT; + _emitter[e].bounce = DEFAULT_PARTICLE_BOUNCE; + _emitter[e].airFriction = DEFAULT_PARTICLE_AIR_FRICTION; + _emitter[e].gravity = DEFAULT_PARTICLE_GRAVITY; + _emitter[e].jitter = 0.0f; + _emitter[e].emitterAttraction = 0.0f; + _emitter[e].tornadoForce = 0.0f; + _emitter[e].neighborAttraction = 0.0f; + _emitter[e].neighborRepulsion = 0.0f; + _emitter[e].collisionSphereRadius = 0.0f; + _emitter[e].collisionSpherePosition = glm::vec3(0.0f, 0.0f, 0.0f); + _emitter[e].usingCollisionSphere = false; + _emitter[e].showingEmitter = false; + }; for (unsigned int p = 0; p < MAX_PARTICLES; p++) { @@ -69,9 +70,11 @@ void ParticleSystem::simulate(float deltaTime) { // update emitters for (unsigned int e = 0; e < _numEmitters; e++) { - updateEmitter(e, deltaTime); + updateEmitter(e, deltaTime); } + runSpecialEffectsTest(0, deltaTime); + // update particles for (unsigned int p = 0; p < _numParticles; p++) { if (_particle[p].alive) { @@ -91,22 +94,23 @@ void ParticleSystem::updateEmitter(int e, float deltaTime) { void ParticleSystem::emitParticlesNow(int e, int num, float radius, glm::vec4 color, glm::vec3 velocity, float lifespan) { for (unsigned int p = 0; p < num; p++) { - createParticle(_emitter[e].position, velocity, radius, color, lifespan); + createParticle(e, _emitter[e].position, velocity, radius, color, lifespan); } } -void ParticleSystem::createParticle(glm::vec3 position, glm::vec3 velocity, float radius, glm::vec4 color, float lifespan) { +void ParticleSystem::createParticle(int e, glm::vec3 position, glm::vec3 velocity, float radius, glm::vec4 color, float lifespan) { for (unsigned int p = 0; p < MAX_PARTICLES; p++) { if (!_particle[p].alive) { - _particle[p].lifespan = lifespan; - _particle[p].alive = true; - _particle[p].age = 0.0f; - _particle[p].position = position; - _particle[p].velocity = velocity; - _particle[p].radius = radius; - _particle[p].color = color; + _particle[p].emitterIndex = e; + _particle[p].lifespan = lifespan; + _particle[p].alive = true; + _particle[p].age = 0.0f; + _particle[p].position = position; + _particle[p].velocity = velocity; + _particle[p].radius = radius; + _particle[p].color = color; _numParticles ++; @@ -145,29 +149,20 @@ void ParticleSystem::setOrangeBlueColorPalette() { } -void ParticleSystem::runSpecialEffectsTest(float deltaTime) { +void ParticleSystem::runSpecialEffectsTest(int e, float deltaTime) { _timer += deltaTime; - - glm::vec3 tilt = glm::vec3 - ( - 30.0f * sinf( _timer * 0.55f ), - 0.0f, - 30.0f * cosf( _timer * 0.75f ) - ); - - _emitter[0].rotation = glm::quat(glm::radians(tilt)); - - _gravity = 0.0f + DEFAULT_PARTICLE_GRAVITY * sinf( _timer * 0.52f ); - _airFriction = (DEFAULT_PARTICLE_AIR_FRICTION + 0.5f) + 2.0f * sinf( _timer * 0.32f ); - _jitter = DEFAULT_PARTICLE_JITTER + DEFAULT_PARTICLE_JITTER * sinf( _timer * 0.42f ); - _emitterAttraction = 0.015f + 0.015f * cosf( _timer * 0.6f ); - _tornadoForce = 0.0f + 0.03f * sinf( _timer * 0.7f ); - _neighborAttraction = 0.1f + 0.1f * cosf( _timer * 0.8f ); - _neighborRepulsion = 0.2f + 0.2f * sinf( _timer * 0.4f ); + + _emitter[e].gravity = 0.0f + DEFAULT_PARTICLE_GRAVITY * sinf( _timer * 0.52f ); + _emitter[e].airFriction = (DEFAULT_PARTICLE_AIR_FRICTION + 0.5f) + 2.0f * sinf( _timer * 0.32f ); + _emitter[e].jitter = 0.05f + 0.05f * sinf( _timer * 0.42f ); + _emitter[e].emitterAttraction = 0.015f + 0.015f * cosf( _timer * 0.6f ); + _emitter[e].tornadoForce = 0.0f + 0.03f * sinf( _timer * 0.7f ); + _emitter[e].neighborAttraction = 0.1f + 0.1f * cosf( _timer * 0.8f ); + _emitter[e].neighborRepulsion = 0.2f + 0.2f * sinf( _timer * 0.4f ); - if (_gravity < 0.0f) { - _gravity = 0.0f; + if (_emitter[e].gravity < 0.0f) { + _emitter[e].gravity = 0.0f; } } @@ -179,40 +174,45 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { if (_particle[p].age > _particle[p].lifespan) { killParticle(p); } + + Emitter myEmitter = _emitter[_particle[p].emitterIndex]; // apply random jitter _particle[p].velocity += glm::vec3 ( - -_jitter * ONE_HALF + _jitter * randFloat(), - -_jitter * ONE_HALF + _jitter * randFloat(), - -_jitter * ONE_HALF + _jitter * randFloat() + -myEmitter.jitter * ONE_HALF + myEmitter.jitter * randFloat(), + -myEmitter.jitter * ONE_HALF + myEmitter.jitter * randFloat(), + -myEmitter.jitter * ONE_HALF + myEmitter.jitter * randFloat() ) * deltaTime; // apply attraction to home position - glm::vec3 vectorToHome = _emitter[_particle[p].emitterIndex].position - _particle[p].position; - _particle[p].velocity += vectorToHome * _emitterAttraction * deltaTime; + glm::vec3 vectorToHome = myEmitter.position - _particle[p].position; + _particle[p].velocity += vectorToHome * myEmitter.emitterAttraction * deltaTime; // apply neighbor attraction int neighbor = p + 1; if (neighbor == _numParticles ) { neighbor = 0; } - glm::vec3 vectorToNeighbor = _particle[p].position - _particle[neighbor].position; - _particle[p].velocity -= vectorToNeighbor * _neighborAttraction * deltaTime; + if ( _particle[neighbor].emitterIndex == _particle[p].emitterIndex) { + glm::vec3 vectorToNeighbor = _particle[p].position - _particle[neighbor].position; + + _particle[p].velocity -= vectorToNeighbor * myEmitter.neighborAttraction * deltaTime; - float distanceToNeighbor = glm::length(vectorToNeighbor); - if (distanceToNeighbor > 0.0f) { - _particle[neighbor].velocity += (vectorToNeighbor / ( 1.0f + distanceToNeighbor * distanceToNeighbor)) * _neighborRepulsion * deltaTime; + float distanceToNeighbor = glm::length(vectorToNeighbor); + if (distanceToNeighbor > 0.0f) { + _particle[neighbor].velocity += (vectorToNeighbor / ( 1.0f + distanceToNeighbor * distanceToNeighbor)) * myEmitter.neighborRepulsion * deltaTime; + } } // apply tornado force - glm::vec3 tornadoDirection = glm::cross(vectorToHome, _emitter[_particle[p].emitterIndex].up); - _particle[p].velocity += tornadoDirection * _tornadoForce * deltaTime; + glm::vec3 tornadoDirection = glm::cross(vectorToHome, myEmitter.up); + _particle[p].velocity += tornadoDirection * myEmitter.tornadoForce * deltaTime; // apply air friction - float drag = 1.0 - _airFriction * deltaTime; + float drag = 1.0 - myEmitter.airFriction * deltaTime; if (drag < 0.0f) { _particle[p].velocity = glm::vec3(0.0f, 0.0f, 0.0f); } else { @@ -220,7 +220,7 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { } // apply gravity - _particle[p].velocity -= _upDirection * _gravity * deltaTime; + _particle[p].velocity -= _upDirection * myEmitter.gravity * deltaTime; // update position by velocity _particle[p].position += _particle[p].velocity; @@ -230,36 +230,38 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { _particle[p].position.y = _particle[p].radius; if (_particle[p].velocity.y < 0.0f) { - _particle[p].velocity.y *= -_bounce; + _particle[p].velocity.y *= -myEmitter.bounce; } } // collision with sphere - if (_usingCollisionSphere) { - glm::vec3 vectorToSphereCenter = _collisionSpherePosition - _particle[p].position; + if (myEmitter.usingCollisionSphere) { + glm::vec3 vectorToSphereCenter = myEmitter.collisionSpherePosition - _particle[p].position; float distanceToSphereCenter = glm::length(vectorToSphereCenter); - float combinedRadius = _collisionSphereRadius + _particle[p].radius; + float combinedRadius = myEmitter.collisionSphereRadius + _particle[p].radius; if (distanceToSphereCenter < combinedRadius) { if (distanceToSphereCenter > 0.0f){ glm::vec3 directionToSphereCenter = vectorToSphereCenter / distanceToSphereCenter; - _particle[p].position = _collisionSpherePosition - directionToSphereCenter * combinedRadius; + _particle[p].position = myEmitter.collisionSpherePosition - directionToSphereCenter * combinedRadius; } } } } -void ParticleSystem::setCollisionSphere(glm::vec3 position, float radius) { - _usingCollisionSphere = true; - _collisionSpherePosition = position; - _collisionSphereRadius = radius; +void ParticleSystem::setCollisionSphere(int e, glm::vec3 position, float radius) { + _emitter[e].usingCollisionSphere = true; + _emitter[e].collisionSpherePosition = position; + _emitter[e].collisionSphereRadius = radius; } void ParticleSystem::render() { // render the emitters for (unsigned int e = 0; e < _numEmitters; e++) { - renderEmitter(e, 0.2f); + if (_emitter[e].showingEmitter) { + renderEmitter(e, 0.2f); + } }; // render the particles diff --git a/interface/src/ParticleSystem.h b/interface/src/ParticleSystem.h index f7f0063dbc..3b8826d697 100644 --- a/interface/src/ParticleSystem.h +++ b/interface/src/ParticleSystem.h @@ -11,8 +11,8 @@ #include -const int MAX_PARTICLES = 10000; -const int MAX_EMITTERS = 10; +const int MAX_PARTICLES = 5000; +const int MAX_EMITTERS = 20; class ParticleSystem { public: @@ -22,13 +22,14 @@ public: void emitParticlesNow(int e, int numParticles, float radius, glm::vec4 color, glm::vec3 velocity, float lifespan); void simulate(float deltaTime); void render(); - void runSpecialEffectsTest(float deltaTime); // for debugging and artistic exploration void setOrangeBlueColorPalette(); // apply a nice preset color palette to the particles - void setCollisionSphere(glm::vec3 position, float radius); // specify a sphere for the particles to collide with + void setCollisionSphere(int e, glm::vec3 position, float radius); // specify a sphere for the particles to collide with void setEmitterPosition(int e, glm::vec3 position) { _emitter[e].position = position; } // set the position of this emitter void setEmitterRotation(int e, glm::quat rotation) { _emitter[e].rotation = rotation; } // set the rotation of this emitter void setUpDirection(glm::vec3 upDirection) {_upDirection = upDirection;} // tell particle system which direction is up + void setShowingEmitter(int e, bool showing) { _emitter[e].showingEmitter = showing;} + private: @@ -38,6 +39,18 @@ private: glm::vec3 right; glm::vec3 up; glm::vec3 front; + float bounce; + float gravity; + float airFriction; + float jitter; + float emitterAttraction; + float tornadoForce; + float neighborAttraction; + float neighborRepulsion; + bool usingCollisionSphere; + glm::vec3 collisionSpherePosition; + float collisionSphereRadius; + bool showingEmitter; }; struct Particle { @@ -52,27 +65,17 @@ private: }; glm::vec3 _upDirection; - float _bounce; - float _gravity; float _timer; Emitter _emitter[MAX_EMITTERS]; Particle _particle[MAX_PARTICLES]; int _numParticles; int _numEmitters; - float _airFriction; - float _jitter; - float _emitterAttraction; - float _tornadoForce; - float _neighborAttraction; - float _neighborRepulsion; - bool _usingCollisionSphere; - glm::vec3 _collisionSpherePosition; - float _collisionSphereRadius; // private methods void updateEmitter(int e, float deltaTime); void updateParticle(int index, float deltaTime); - void createParticle(glm::vec3 position, glm::vec3 velocity, float radius, glm::vec4 color, float lifespan); + void createParticle(int e, glm::vec3 position, glm::vec3 velocity, float radius, glm::vec4 color, float lifespan); + void runSpecialEffectsTest(int e, float deltaTime); // for debugging and artistic exploration void killParticle(int p); void renderEmitter(int emitterIndex, float size); void renderParticle(int p); From 83c779ad766e32caaea1ef846c2768041d2385bf Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 15 Jul 2013 14:08:04 -0700 Subject: [PATCH 16/41] merge --- libraries/shared/src/PacketHeaders.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index 230ca5bacc..f983b91d0b 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -63,4 +63,4 @@ int numBytesForPacketHeader(unsigned char* packetHeader) { // currently this need not be dynamic - there are 2 bytes for each packet header return 2; -} +} \ No newline at end of file From f8f6b295597bc0a747b6c0cc62d22932ed3e0d7b Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 15 Jul 2013 14:24:21 -0700 Subject: [PATCH 17/41] Audio collision sounds are played locally as well as injected --- interface/src/Audio.cpp | 39 ++++++++++++++++++++++++--------------- interface/src/Audio.h | 2 +- interface/src/Head.cpp | 6 ++++-- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 540e7b1e1e..a724f7b288 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -75,9 +75,12 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o NodeList* nodeList = NodeList::getInstance(); Application* interface = Application::getInstance(); Avatar* interfaceAvatar = interface->getAvatar(); - + + memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); + memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); + // Add Procedural effects to input samples - addProceduralSounds(inputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL); + addProceduralSounds(inputLeft, outputLeft, outputRight, BUFFER_LENGTH_SAMPLES_PER_CHANNEL); if (nodeList && inputLeft) { @@ -129,12 +132,8 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o interface->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO) .updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes); } - } - - memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); - memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); - + AudioRingBuffer* ringBuffer = &_ringBuffer; // if there is anything in the ring buffer, decide what to do: @@ -245,11 +244,11 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o } } #ifndef TEST_AUDIO_LOOPBACK - outputLeft[s] = leftSample; - outputRight[s] = rightSample; + outputLeft[s] += leftSample; + outputRight[s] += rightSample; #else - outputLeft[s] = inputLeft[s]; - outputRight[s] = inputLeft[s]; + outputLeft[s] += inputLeft[s]; + outputRight[s] += inputLeft[s]; #endif } ringBuffer->setNextOutput(ringBuffer->getNextOutput() + PACKET_LENGTH_SAMPLES); @@ -584,7 +583,10 @@ void Audio::lowPassFilter(int16_t* inputBuffer) { } // Take a pointer to the acquired microphone input samples and add procedural sounds -void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) { +void Audio::addProceduralSounds(int16_t* inputBuffer, + int16_t* outputLeft, + int16_t* outputRight, + int numSamples) { const float MAX_AUDIBLE_VELOCITY = 6.0; const float MIN_AUDIBLE_VELOCITY = 0.1; const int VOLUME_BASELINE = 400; @@ -600,18 +602,25 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) { }*/ // Add a noise-modulated sinewave with volume that tapers off with speed increasing - if (0) { //((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { + if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { for (int i = 0; i < numSamples; i++) { - inputBuffer[i] += (int16_t)((sinf((float) (_proceduralEffectSample + i) / SOUND_PITCH * speed) * (1.f + randFloat() * 0.0f)) * volume * speed); + //inputBuffer[i] += (int16_t)((sinf((float) (_proceduralEffectSample + i) / SOUND_PITCH * speed) * (1.f + randFloat() * 0.0f)) * volume * speed); + inputBuffer[i] += (int16_t)(sinf((float) (_proceduralEffectSample + i) / SOUND_PITCH ) * volume * (1.f + randFloat() * 0.25f) * speed); + + } } const float COLLISION_SOUND_CUTOFF_LEVEL = 5.0f; const float COLLISION_SOUND_PITCH_1 = 2.0f; const float COLLISION_SOUND_DECAY = 1.f/1024.f; const float COLLISION_VOLUME_BASELINE = 10.f; + int sample; if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) { for (int i = 0; i < numSamples; i++) { - inputBuffer[i] += (int16_t) ((sinf((float) (_proceduralEffectSample + i) / COLLISION_SOUND_PITCH_1) * COLLISION_VOLUME_BASELINE * _collisionSoundMagnitude)); + sample = (int16_t) ((sinf((float) (_proceduralEffectSample + i) / COLLISION_SOUND_PITCH_1) * COLLISION_VOLUME_BASELINE * _collisionSoundMagnitude)); + inputBuffer[i] += sample; + outputLeft[i] += sample; + outputRight[i] += sample; _collisionSoundMagnitude *= (1.f - COLLISION_SOUND_DECAY); } } diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 78b298644b..715cfeafc8 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -97,7 +97,7 @@ private: inline void analyzePing(); // Add sounds that we want the user to not hear themselves, by adding on top of mic input signal - void addProceduralSounds(int16_t* inputBuffer, int numSamples); + void addProceduralSounds(int16_t* inputBuffer, int16_t* outputLeft, int16_t* outputRight, int numSamples); // Audio callback called by portaudio. Calls 'performIO'. diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 44d62e695d..18141bc2b4 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -227,7 +227,8 @@ void Head::simulate(float deltaTime, bool isMine) { const float CAMERA_FOLLOW_HEAD_RATE_MAX = 0.5f; const float CAMERA_FOLLOW_HEAD_RATE_RAMP_RATE = 1.05f; const float CAMERA_STOP_TOLERANCE_DEGREES = 0.1f; - const float CAMERA_START_TOLERANCE_DEGREES = 2.0f; + const float CAMERA_PITCH_START_TOLERANCE_DEGREES = 10.0f; + const float CAMERA_YAW_START_TOLERANCE_DEGREES = 3.0f; float cameraHeadAngleDifference = glm::length(glm::vec2(_pitch - _cameraPitch, _yaw - _cameraYaw)); if (_isCameraMoving) { _cameraFollowHeadRate = glm::clamp(_cameraFollowHeadRate * CAMERA_FOLLOW_HEAD_RATE_RAMP_RATE, @@ -240,7 +241,8 @@ void Head::simulate(float deltaTime, bool isMine) { _isCameraMoving = false; } } else { - if (cameraHeadAngleDifference > CAMERA_START_TOLERANCE_DEGREES) { + if ((fabs(_pitch - _cameraPitch) > CAMERA_PITCH_START_TOLERANCE_DEGREES) || + (fabs(_yaw - _cameraYaw) > CAMERA_YAW_START_TOLERANCE_DEGREES)) { _isCameraMoving = true; _cameraFollowHeadRate = CAMERA_FOLLOW_HEAD_RATE_START; } From c0f319f077f4bec5a40a3780521f57a2cc23fd52 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 15 Jul 2013 14:36:11 -0700 Subject: [PATCH 18/41] merge --- interface/src/Application.cpp | 8 +++++++- libraries/avatars/src/HandData.h | 0 2 files changed, 7 insertions(+), 1 deletion(-) mode change 100755 => 100644 libraries/avatars/src/HandData.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 44c2bc5200..d7ff6fe959 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2037,7 +2037,6 @@ void Application::update(float deltaTime) { _audio.eventuallyAnalyzePing(); #endif - if (TESTING_PARTICLE_SYSTEM) { if (!_particleSystemInitialized) { @@ -2100,6 +2099,13 @@ void Application::update(float deltaTime) { 1.0f + cosf(t * 9.0f) * 0.02f, 3.0f + sinf(t * 7.0f) * 0.02f ); + + +//_myAvatar.getHand().setLeapFingers(LeapManager::getFingerTips(), LeapManager::getFingerRoots()); +//_myAvatar.getHand().setLeapHands(LeapManager::getHandPositions(), LeapManager::getHandNormals()); + + + glm::vec3 tilt = glm::vec3 ( diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h old mode 100755 new mode 100644 From 56d0c7d7e4954b7607f33204e1cc52be6bc4dc33 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 15 Jul 2013 15:45:31 -0700 Subject: [PATCH 19/41] added array of finger emitters for particle system --- interface/src/Application.cpp | 79 +++++++++++++++----------------- interface/src/Application.h | 2 +- interface/src/Hand.h | 1 + interface/src/LeapManager.cpp | 0 interface/src/ParticleSystem.cpp | 24 ++++++---- 5 files changed, 56 insertions(+), 50 deletions(-) mode change 100755 => 100644 interface/src/LeapManager.cpp diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d7ff6fe959..1b050bc874 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -174,7 +174,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _justStarted(true), _particleSystemInitialized(false), _coolDemoParticleEmitter(-1), - _fingerParticleEmitter(-1), _wantToKillLocalVoxels(false), _frustumDrawingMode(FRUSTUM_DRAW_MODE_ALL), _viewFrustumOffsetYaw(-135.0), @@ -210,6 +209,12 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _bytesCount(0), _swatch(NULL) { + + // initialize all finger particle emitters with an invalid id as default + for (int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) { + _fingerParticleEmitter[f] = -1; + } + _applicationStartupTime = startup_time; _window->setWindowTitle("Interface"); printLog("Interface Startup:\n"); @@ -2042,8 +2047,7 @@ void Application::update(float deltaTime) { // create a stable test emitter and spit out a bunch of particles _coolDemoParticleEmitter = _particleSystem.addEmitter(); - _fingerParticleEmitter = _particleSystem.addEmitter(); - + if (_coolDemoParticleEmitter != -1) { _particleSystem.setShowingEmitter(_coolDemoParticleEmitter, true); glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.0f, 5.0f); @@ -2060,11 +2064,11 @@ void Application::update(float deltaTime) { _particleSystem.emitParticlesNow(_coolDemoParticleEmitter, 1500, radius, color, velocity, lifespan); } - if (_fingerParticleEmitter != -1) { - _particleSystem.setShowingEmitter(_fingerParticleEmitter, false); + for ( int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) { + _fingerParticleEmitter[f] = _particleSystem.addEmitter(); + _particleSystem.setShowingEmitter(_fingerParticleEmitter[f], true); } - - + // signal that the particle system has been initialized _particleSystemInitialized = true; @@ -2073,11 +2077,9 @@ void Application::update(float deltaTime) { } else { // update the particle system - static float t = 0.0f; t += deltaTime; - if (_coolDemoParticleEmitter != -1) { glm::vec3 tilt = glm::vec3 @@ -2090,40 +2092,35 @@ void Application::update(float deltaTime) { _particleSystem.setEmitterRotation(_coolDemoParticleEmitter, glm::quat(glm::radians(tilt))); } - if (_fingerParticleEmitter != -1) { - - glm::vec3 particleEmitterPosition = - glm::vec3 - ( - 3.0f + sinf(t * 8.0f) * 0.02f, - 1.0f + cosf(t * 9.0f) * 0.02f, - 3.0f + sinf(t * 7.0f) * 0.02f - ); - - -//_myAvatar.getHand().setLeapFingers(LeapManager::getFingerTips(), LeapManager::getFingerRoots()); -//_myAvatar.getHand().setLeapHands(LeapManager::getHandPositions(), LeapManager::getHandNormals()); - - - - - glm::vec3 tilt = glm::vec3 - ( - 30.0f * sinf( t * 0.55f ), - 0.0f, - 30.0f * cosf( t * 0.75f ) - ); - - glm::quat particleEmitterRotation = glm::quat(glm::radians(tilt)); + const std::vector& fingerTips = _myAvatar.getHand().getFingerTips(); + const std::vector& fingerRoots = _myAvatar.getHand().getFingerRoots(); + const std::vector& handPositions = _myAvatar.getHand().getHandPositions(); + const std::vector& handNormals = _myAvatar.getHand().getHandNormals(); - _particleSystem.setEmitterPosition(_fingerParticleEmitter, particleEmitterPosition); - _particleSystem.setEmitterRotation(_fingerParticleEmitter, particleEmitterRotation); + for ( int f = 0; f< fingerTips.size(); f ++ ) { - float radius = 0.01f; - glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); - glm::vec3 velocity(0.0f, 0.01f, 0.0f); - float lifespan = 0.4f; - _particleSystem.emitParticlesNow(_fingerParticleEmitter, 1, radius, color, velocity, lifespan); + if (_fingerParticleEmitter[f] != -1) { + + glm::vec3 particleEmitterPosition = _myAvatar.getHand().leapPositionToWorldPosition(fingerTips[f]); + + glm::vec3 tilt = glm::vec3 + ( + 30.0f * sinf( t * 0.55f ), + 0.0f, + 30.0f * cosf( t * 0.75f ) + ); + + glm::quat particleEmitterRotation = glm::quat(glm::radians(tilt)); + + _particleSystem.setEmitterPosition(_fingerParticleEmitter[0], particleEmitterPosition); + _particleSystem.setEmitterRotation(_fingerParticleEmitter[0], particleEmitterRotation); + + float radius = 0.01f; + glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); + glm::vec3 velocity(0.0f, 0.01f, 0.0f); + float lifespan = 0.4f; + _particleSystem.emitParticlesNow(_fingerParticleEmitter[0], 1, radius, color, velocity, lifespan); + } } _particleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f)); diff --git a/interface/src/Application.h b/interface/src/Application.h index 789b18e011..2800904c3f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -285,7 +285,7 @@ private: bool _justStarted; bool _particleSystemInitialized; int _coolDemoParticleEmitter; - int _fingerParticleEmitter; + int _fingerParticleEmitter[NUM_FINGERS_PER_HAND]; Stars _stars; diff --git a/interface/src/Hand.h b/interface/src/Hand.h index 1c25c85fbc..7056911871 100755 --- a/interface/src/Hand.h +++ b/interface/src/Hand.h @@ -18,6 +18,7 @@ #include #include +const int NUM_FINGERS_PER_HAND = 5; class Avatar; class ProgramObject; diff --git a/interface/src/LeapManager.cpp b/interface/src/LeapManager.cpp old mode 100755 new mode 100644 diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index 14aaedbac9..7364f215af 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -13,7 +13,6 @@ const float DEFAULT_PARTICLE_BOUNCE = 1.0f; const float DEFAULT_PARTICLE_AIR_FRICTION = 2.0f; -const float DEFAULT_PARTICLE_GRAVITY = 0.05f; ParticleSystem::ParticleSystem() { @@ -30,7 +29,7 @@ ParticleSystem::ParticleSystem() { _emitter[e].front = IDENTITY_FRONT; _emitter[e].bounce = DEFAULT_PARTICLE_BOUNCE; _emitter[e].airFriction = DEFAULT_PARTICLE_AIR_FRICTION; - _emitter[e].gravity = DEFAULT_PARTICLE_GRAVITY; + _emitter[e].gravity = 0.0f; _emitter[e].jitter = 0.0f; _emitter[e].emitterAttraction = 0.0f; _emitter[e].tornadoForce = 0.0f; @@ -56,11 +55,20 @@ ParticleSystem::ParticleSystem() { int ParticleSystem::addEmitter() { + + printf( "\n" ); + printf( "ParticleSystem::addEmitter\n" ); + _numEmitters ++; if (_numEmitters > MAX_EMITTERS) { + + printf( "Oops! _numEmitters > MAX_EMITTERS... returning -1\n" ); + return -1; } + + printf( "ok, _numEmitters is %d,and the index of this newly added emitter is %d.\n", _numEmitters, _numEmitters-1 ); return _numEmitters - 1; } @@ -153,13 +161,13 @@ void ParticleSystem::runSpecialEffectsTest(int e, float deltaTime) { _timer += deltaTime; - _emitter[e].gravity = 0.0f + DEFAULT_PARTICLE_GRAVITY * sinf( _timer * 0.52f ); + _emitter[e].gravity = 0.0f + 0.05f * sinf( _timer * 0.52f ); _emitter[e].airFriction = (DEFAULT_PARTICLE_AIR_FRICTION + 0.5f) + 2.0f * sinf( _timer * 0.32f ); - _emitter[e].jitter = 0.05f + 0.05f * sinf( _timer * 0.42f ); - _emitter[e].emitterAttraction = 0.015f + 0.015f * cosf( _timer * 0.6f ); - _emitter[e].tornadoForce = 0.0f + 0.03f * sinf( _timer * 0.7f ); - _emitter[e].neighborAttraction = 0.1f + 0.1f * cosf( _timer * 0.8f ); - _emitter[e].neighborRepulsion = 0.2f + 0.2f * sinf( _timer * 0.4f ); + _emitter[e].jitter = 0.05f + 0.05f * sinf( _timer * 0.42f ); + _emitter[e].emitterAttraction = 0.015f + 0.015f * cosf( _timer * 0.6f ); + _emitter[e].tornadoForce = 0.0f + 0.03f * sinf( _timer * 0.7f ); + _emitter[e].neighborAttraction = 0.1f + 0.1f * cosf( _timer * 0.8f ); + _emitter[e].neighborRepulsion = 0.2f + 0.2f * sinf( _timer * 0.4f ); if (_emitter[e].gravity < 0.0f) { _emitter[e].gravity = 0.0f; From 26c0eb2dea0556bf0bd011d08a0c576d429b3c3e Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 15 Jul 2013 16:27:46 -0700 Subject: [PATCH 20/41] Start to add heartbeat --- interface/src/Audio.cpp | 10 +++++++++- interface/src/Audio.h | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index a724f7b288..a2b3f08535 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -327,7 +327,8 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : _flangeRate(0.0f), _flangeWeight(0.0f), _collisionSoundMagnitude(0.0f), - _proceduralEffectSample(0) + _proceduralEffectSample(0), + _heartbeatMagnitude(0.0f) { outputPortAudioError(Pa_Initialize()); @@ -601,6 +602,9 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, inputBuffer[i] += (int16_t) (_proceduralEffectSample + i)%16 * 10; }*/ + // + // Travelling noise + // // Add a noise-modulated sinewave with volume that tapers off with speed increasing if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { for (int i = 0; i < numSamples; i++) { @@ -624,6 +628,10 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, _collisionSoundMagnitude *= (1.f - COLLISION_SOUND_DECAY); } } + + //if (_heartbeatMagnitude > 0.0f) { + // + //} _proceduralEffectSample += numSamples; } diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 715cfeafc8..1ab671a30b 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -85,6 +85,7 @@ private: float _flangeWeight; float _collisionSoundMagnitude; int _proceduralEffectSample; + float _heartbeatMagnitude; // Audio callback in class context. inline void performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight); From 0481a81ca7639127b494267a71e0fbba93f20588 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 15 Jul 2013 17:58:17 -0700 Subject: [PATCH 21/41] moved finger particles over to hand.cpp --- interface/src/Application.cpp | 169 ++++++++++++++----------------- interface/src/Application.h | 3 +- interface/src/Hand.cpp | 61 ++++++++++- interface/src/Hand.h | 10 +- interface/src/ParticleSystem.cpp | 106 +++++++++---------- interface/src/ParticleSystem.h | 52 +++++----- 6 files changed, 225 insertions(+), 176 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1b050bc874..16af90ef12 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -73,7 +73,7 @@ using namespace std; static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; static char STAR_CACHE_FILE[] = "cachedStars.txt"; -static const bool TESTING_PARTICLE_SYSTEM = true; +static const bool TESTING_PARTICLE_SYSTEM = false; static const int BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH = 6; // farther dragged clicks are ignored @@ -209,12 +209,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _bytesCount(0), _swatch(NULL) { - - // initialize all finger particle emitters with an invalid id as default - for (int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) { - _fingerParticleEmitter[f] = -1; - } - _applicationStartupTime = startup_time; _window->setWindowTitle("Interface"); printLog("Interface Startup:\n"); @@ -1995,6 +1989,8 @@ void Application::update(float deltaTime) { _myAvatar.simulate(deltaTime, NULL); } + _myAvatar.getHand().simulate(deltaTime, true); + if (!OculusManager::isConnected()) { if (_lookingInMirror->isChecked()) { if (_myCamera.getMode() != CAMERA_MODE_MIRROR) { @@ -2043,90 +2039,8 @@ void Application::update(float deltaTime) { #endif if (TESTING_PARTICLE_SYSTEM) { - if (!_particleSystemInitialized) { - - // create a stable test emitter and spit out a bunch of particles - _coolDemoParticleEmitter = _particleSystem.addEmitter(); - - if (_coolDemoParticleEmitter != -1) { - _particleSystem.setShowingEmitter(_coolDemoParticleEmitter, true); - glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.0f, 5.0f); - _particleSystem.setEmitterPosition(_coolDemoParticleEmitter, particleEmitterPosition); - float radius = 0.01f; - glm::vec4 color(0.0f, 0.0f, 0.0f, 1.0f); - glm::vec3 velocity(0.0f, 0.1f, 0.0f); - float lifespan = 100000.0f; - - // determine a collision sphere - glm::vec3 collisionSpherePosition = glm::vec3( 5.0f, 0.5f, 5.0f ); - float collisionSphereRadius = 0.5f; - _particleSystem.setCollisionSphere(_coolDemoParticleEmitter, collisionSpherePosition, collisionSphereRadius); - _particleSystem.emitParticlesNow(_coolDemoParticleEmitter, 1500, radius, color, velocity, lifespan); - } - - for ( int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) { - _fingerParticleEmitter[f] = _particleSystem.addEmitter(); - _particleSystem.setShowingEmitter(_fingerParticleEmitter[f], true); - } - - // signal that the particle system has been initialized - _particleSystemInitialized = true; - - // apply a preset color palette - _particleSystem.setOrangeBlueColorPalette(); - } else { - // update the particle system - - static float t = 0.0f; - t += deltaTime; - - if (_coolDemoParticleEmitter != -1) { - - glm::vec3 tilt = glm::vec3 - ( - 30.0f * sinf( t * 0.55f ), - 0.0f, - 30.0f * cosf( t * 0.75f ) - ); - - _particleSystem.setEmitterRotation(_coolDemoParticleEmitter, glm::quat(glm::radians(tilt))); - } - - const std::vector& fingerTips = _myAvatar.getHand().getFingerTips(); - const std::vector& fingerRoots = _myAvatar.getHand().getFingerRoots(); - const std::vector& handPositions = _myAvatar.getHand().getHandPositions(); - const std::vector& handNormals = _myAvatar.getHand().getHandNormals(); - - for ( int f = 0; f< fingerTips.size(); f ++ ) { - - if (_fingerParticleEmitter[f] != -1) { - - glm::vec3 particleEmitterPosition = _myAvatar.getHand().leapPositionToWorldPosition(fingerTips[f]); - - glm::vec3 tilt = glm::vec3 - ( - 30.0f * sinf( t * 0.55f ), - 0.0f, - 30.0f * cosf( t * 0.75f ) - ); - - glm::quat particleEmitterRotation = glm::quat(glm::radians(tilt)); - - _particleSystem.setEmitterPosition(_fingerParticleEmitter[0], particleEmitterPosition); - _particleSystem.setEmitterRotation(_fingerParticleEmitter[0], particleEmitterRotation); - - float radius = 0.01f; - glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); - glm::vec3 velocity(0.0f, 0.01f, 0.0f); - float lifespan = 0.4f; - _particleSystem.emitParticlesNow(_fingerParticleEmitter[0], 1, radius, color, velocity, lifespan); - } - } - - _particleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f)); - _particleSystem.simulate(deltaTime); - } - } + updateParticleSystem(deltaTime); + } } void Application::updateAvatar(float deltaTime) { @@ -3471,3 +3385,76 @@ void Application::exportSettings() { } + +void Application::updateParticleSystem(float deltaTime) { + + if (!_particleSystemInitialized) { + // create a stable test emitter and spit out a bunch of particles + _coolDemoParticleEmitter = _particleSystem.addEmitter(); + + if (_coolDemoParticleEmitter != -1) { + _particleSystem.setShowingEmitter(_coolDemoParticleEmitter, true); + glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.0f, 5.0f); + _particleSystem.setEmitterPosition(_coolDemoParticleEmitter, particleEmitterPosition); + float radius = 0.01f; + glm::vec4 color(0.0f, 0.0f, 0.0f, 1.0f); + glm::vec3 velocity(0.0f, 0.1f, 0.0f); + float lifespan = 100000.0f; + + // determine a collision sphere + glm::vec3 collisionSpherePosition = glm::vec3( 5.0f, 0.5f, 5.0f ); + float collisionSphereRadius = 0.5f; + _particleSystem.setCollisionSphere(_coolDemoParticleEmitter, collisionSpherePosition, collisionSphereRadius); + _particleSystem.emitParticlesNow(_coolDemoParticleEmitter, 1500, radius, color, velocity, lifespan); + } + + // signal that the particle system has been initialized + _particleSystemInitialized = true; + + // apply a preset color palette + _particleSystem.setOrangeBlueColorPalette(); + } else { + // update the particle system + + static float t = 0.0f; + t += deltaTime; + + if (_coolDemoParticleEmitter != -1) { + + glm::vec3 tilt = glm::vec3 + ( + 30.0f * sinf( t * 0.55f ), + 0.0f, + 30.0f * cosf( t * 0.75f ) + ); + + _particleSystem.setEmitterRotation(_coolDemoParticleEmitter, glm::quat(glm::radians(tilt))); + + ParticleSystem::ParticleAttributes attributes; + + attributes.gravity = 0.0f + 0.05f * sinf( t * 0.52f ); + attributes.airFriction = 2.5 + 2.0f * sinf( t * 0.32f ); + attributes.jitter = 0.05f + 0.05f * sinf( t * 0.42f ); + attributes.emitterAttraction = 0.015f + 0.015f * cosf( t * 0.6f ); + attributes.tornadoForce = 0.0f + 0.03f * sinf( t * 0.7f ); + attributes.neighborAttraction = 0.1f + 0.1f * cosf( t * 0.8f ); + attributes.neighborRepulsion = 0.2f + 0.2f * sinf( t * 0.4f ); + attributes.bounce = 1.0f; + attributes.usingCollisionSphere = true; + attributes.collisionSpherePosition = glm::vec3( 5.0f, 0.5f, 5.0f ); + attributes.collisionSphereRadius = 0.5f; + + if (attributes.gravity < 0.0f) { + attributes.gravity = 0.0f; + } + + _particleSystem.setParticleAttributesForEmitter(_coolDemoParticleEmitter, attributes); + } + + _particleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f)); + _particleSystem.simulate(deltaTime); + } +} + + + diff --git a/interface/src/Application.h b/interface/src/Application.h index 2800904c3f..7ecee0cbec 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -83,6 +83,8 @@ public: const glm::vec3 getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel); + void updateParticleSystem(float deltaTime); + Avatar* getAvatar() { return &_myAvatar; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } @@ -285,7 +287,6 @@ private: bool _justStarted; bool _particleSystemInitialized; int _coolDemoParticleEmitter; - int _fingerParticleEmitter[NUM_FINGERS_PER_HAND]; Stars _stars; diff --git a/interface/src/Hand.cpp b/interface/src/Hand.cpp index 29a2c32bf1..fa08db7f27 100755 --- a/interface/src/Hand.cpp +++ b/interface/src/Hand.cpp @@ -23,8 +23,13 @@ Hand::Hand(Avatar* owningAvatar) : _lookingInMirror(false), _ballColor(0.0, 0.0, 0.4), _position(0.0, 0.4, 0.0), - _orientation(0.0, 0.0, 0.0, 1.0) + _orientation(0.0, 0.0, 0.0, 1.0), + _particleSystemInitialized(false) { + // initialize all finger particle emitters with an invalid id as default + for (int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) { + _fingerParticleEmitter[f] = -1; + } } void Hand::init() { @@ -40,6 +45,7 @@ void Hand::reset() { } void Hand::simulate(float deltaTime, bool isMine) { + updateFingerParticles(deltaTime); } glm::vec3 Hand::leapPositionToWorldPosition(const glm::vec3& leapPosition) { @@ -69,6 +75,10 @@ void Hand::calculateGeometry() { void Hand::render(bool lookingInMirror) { + if (_particleSystemInitialized) { + _particleSystem.render(); + } + _renderAlpha = 1.0; _lookingInMirror = lookingInMirror; @@ -132,3 +142,52 @@ void Hand::setLeapHands(const std::vector& handPositions, } +void Hand::updateFingerParticles(float deltaTime) { + + if (!_particleSystemInitialized) { + for ( int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) { + _fingerParticleEmitter[f] = _particleSystem.addEmitter(); + _particleSystem.setShowingEmitter(_fingerParticleEmitter[f], true); + } + _particleSystemInitialized = true; + } else { + // update the particles + + static float t = 0.0f; + t += deltaTime; + + for ( int f = 0; f< _fingerTips.size(); f ++ ) { + + if (_fingerParticleEmitter[f] != -1) { + + glm::vec3 particleEmitterPosition = leapPositionToWorldPosition(_fingerTips[f]); + + // this aspect is still being designed.... + + glm::vec3 tilt = glm::vec3 + ( + 30.0f * sinf( t * 0.55f ), + 0.0f, + 30.0f * cosf( t * 0.75f ) + ); + + glm::quat particleEmitterRotation = glm::quat(glm::radians(tilt)); + + _particleSystem.setEmitterPosition(_fingerParticleEmitter[0], particleEmitterPosition); + _particleSystem.setEmitterRotation(_fingerParticleEmitter[0], particleEmitterRotation); + + float radius = 0.005f; + glm::vec4 color(1.0f, 0.6f, 0.0f, 0.5f); + glm::vec3 velocity(0.0f, 0.005f, 0.0f); + float lifespan = 0.3f; + _particleSystem.emitParticlesNow(_fingerParticleEmitter[0], 1, radius, color, velocity, lifespan); + } + } + + _particleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f)); + _particleSystem.simulate(deltaTime); + } +} + + + diff --git a/interface/src/Hand.h b/interface/src/Hand.h index 7056911871..f9c451ff84 100755 --- a/interface/src/Hand.h +++ b/interface/src/Hand.h @@ -15,6 +15,7 @@ #include "world.h" #include "InterfaceConfig.h" #include "SerialInterface.h" +#include "ParticleSystem.h" #include #include @@ -47,7 +48,9 @@ public: const std::vector& fingerRoots); void setLeapHands (const std::vector& handPositions, const std::vector& handNormals); - + + void updateFingerParticles(float deltaTime); + // getters const glm::vec3& getLeapBallPosition (int ball) const { return _leapBalls[ball].position;} @@ -58,6 +61,8 @@ private: // disallow copies of the Hand, copy of owning Avatar is disallowed too Hand(const Hand&); Hand& operator= (const Hand&); + + ParticleSystem _particleSystem; Avatar* _owningAvatar; float _renderAlpha; @@ -67,6 +72,9 @@ private: glm::quat _orientation; std::vector _leapBalls; + bool _particleSystemInitialized; + int _fingerParticleEmitter[NUM_FINGERS_PER_HAND]; + // private methods void renderHandSpheres(); void calculateGeometry(); diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index 7364f215af..fcc24a2663 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -22,24 +22,23 @@ ParticleSystem::ParticleSystem() { _upDirection = glm::vec3(0.0f, 1.0f, 0.0f); // default for (unsigned int e = 0; e < MAX_EMITTERS; e++) { - _emitter[e].position = glm::vec3(0.0f, 0.0f, 0.0f); - _emitter[e].rotation = glm::quat(); - _emitter[e].right = IDENTITY_RIGHT; - _emitter[e].up = IDENTITY_UP; - _emitter[e].front = IDENTITY_FRONT; - _emitter[e].bounce = DEFAULT_PARTICLE_BOUNCE; - _emitter[e].airFriction = DEFAULT_PARTICLE_AIR_FRICTION; - _emitter[e].gravity = 0.0f; - _emitter[e].jitter = 0.0f; - _emitter[e].emitterAttraction = 0.0f; - _emitter[e].tornadoForce = 0.0f; - _emitter[e].neighborAttraction = 0.0f; - _emitter[e].neighborRepulsion = 0.0f; - _emitter[e].collisionSphereRadius = 0.0f; - _emitter[e].collisionSpherePosition = glm::vec3(0.0f, 0.0f, 0.0f); - _emitter[e].usingCollisionSphere = false; - _emitter[e].showingEmitter = false; - + _emitter[e].position = glm::vec3(0.0f, 0.0f, 0.0f); + _emitter[e].rotation = glm::quat(); + _emitter[e].right = IDENTITY_RIGHT; + _emitter[e].up = IDENTITY_UP; + _emitter[e].front = IDENTITY_FRONT; + _emitter[e].showingEmitter = false; + _emitter[e].particleAttributes.bounce = DEFAULT_PARTICLE_BOUNCE; + _emitter[e].particleAttributes.airFriction = DEFAULT_PARTICLE_AIR_FRICTION; + _emitter[e].particleAttributes.gravity = 0.0f; + _emitter[e].particleAttributes.jitter = 0.0f; + _emitter[e].particleAttributes.emitterAttraction = 0.0f; + _emitter[e].particleAttributes.tornadoForce = 0.0f; + _emitter[e].particleAttributes.neighborAttraction = 0.0f; + _emitter[e].particleAttributes.neighborRepulsion = 0.0f; + _emitter[e].particleAttributes.collisionSphereRadius = 0.0f; + _emitter[e].particleAttributes.collisionSpherePosition = glm::vec3(0.0f, 0.0f, 0.0f); + _emitter[e].particleAttributes.usingCollisionSphere = false; }; for (unsigned int p = 0; p < MAX_PARTICLES; p++) { @@ -56,19 +55,11 @@ ParticleSystem::ParticleSystem() { int ParticleSystem::addEmitter() { - printf( "\n" ); - printf( "ParticleSystem::addEmitter\n" ); - _numEmitters ++; if (_numEmitters > MAX_EMITTERS) { - - printf( "Oops! _numEmitters > MAX_EMITTERS... returning -1\n" ); - return -1; } - - printf( "ok, _numEmitters is %d,and the index of this newly added emitter is %d.\n", _numEmitters, _numEmitters-1 ); return _numEmitters - 1; } @@ -81,8 +72,6 @@ void ParticleSystem::simulate(float deltaTime) { updateEmitter(e, deltaTime); } - runSpecialEffectsTest(0, deltaTime); - // update particles for (unsigned int p = 0; p < _numParticles; p++) { if (_particle[p].alive) { @@ -157,24 +146,23 @@ void ParticleSystem::setOrangeBlueColorPalette() { } -void ParticleSystem::runSpecialEffectsTest(int e, float deltaTime) { +void ParticleSystem::setParticleAttributesForEmitter(int emitterIndex, ParticleAttributes attributes) { - _timer += deltaTime; - - _emitter[e].gravity = 0.0f + 0.05f * sinf( _timer * 0.52f ); - _emitter[e].airFriction = (DEFAULT_PARTICLE_AIR_FRICTION + 0.5f) + 2.0f * sinf( _timer * 0.32f ); - _emitter[e].jitter = 0.05f + 0.05f * sinf( _timer * 0.42f ); - _emitter[e].emitterAttraction = 0.015f + 0.015f * cosf( _timer * 0.6f ); - _emitter[e].tornadoForce = 0.0f + 0.03f * sinf( _timer * 0.7f ); - _emitter[e].neighborAttraction = 0.1f + 0.1f * cosf( _timer * 0.8f ); - _emitter[e].neighborRepulsion = 0.2f + 0.2f * sinf( _timer * 0.4f ); - - if (_emitter[e].gravity < 0.0f) { - _emitter[e].gravity = 0.0f; - } + _emitter[emitterIndex].particleAttributes.bounce = attributes.bounce; + _emitter[emitterIndex].particleAttributes.gravity = attributes.gravity; + _emitter[emitterIndex].particleAttributes.airFriction = attributes.airFriction; + _emitter[emitterIndex].particleAttributes.jitter = attributes.jitter; + _emitter[emitterIndex].particleAttributes.emitterAttraction = attributes.emitterAttraction; + _emitter[emitterIndex].particleAttributes.tornadoForce = attributes.tornadoForce; + _emitter[emitterIndex].particleAttributes.neighborAttraction = attributes.neighborAttraction; + _emitter[emitterIndex].particleAttributes.neighborRepulsion = attributes.neighborRepulsion; + _emitter[emitterIndex].particleAttributes.usingCollisionSphere = attributes.usingCollisionSphere; + _emitter[emitterIndex].particleAttributes.collisionSpherePosition = attributes.collisionSpherePosition; + _emitter[emitterIndex].particleAttributes.collisionSphereRadius = attributes.collisionSphereRadius; } + void ParticleSystem::updateParticle(int p, float deltaTime) { _particle[p].age += deltaTime; @@ -189,14 +177,14 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { _particle[p].velocity += glm::vec3 ( - -myEmitter.jitter * ONE_HALF + myEmitter.jitter * randFloat(), - -myEmitter.jitter * ONE_HALF + myEmitter.jitter * randFloat(), - -myEmitter.jitter * ONE_HALF + myEmitter.jitter * randFloat() + -myEmitter.particleAttributes.jitter * ONE_HALF + myEmitter.particleAttributes.jitter * randFloat(), + -myEmitter.particleAttributes.jitter * ONE_HALF + myEmitter.particleAttributes.jitter * randFloat(), + -myEmitter.particleAttributes.jitter * ONE_HALF + myEmitter.particleAttributes.jitter * randFloat() ) * deltaTime; // apply attraction to home position glm::vec3 vectorToHome = myEmitter.position - _particle[p].position; - _particle[p].velocity += vectorToHome * myEmitter.emitterAttraction * deltaTime; + _particle[p].velocity += vectorToHome * myEmitter.particleAttributes.emitterAttraction * deltaTime; // apply neighbor attraction int neighbor = p + 1; @@ -207,20 +195,20 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { if ( _particle[neighbor].emitterIndex == _particle[p].emitterIndex) { glm::vec3 vectorToNeighbor = _particle[p].position - _particle[neighbor].position; - _particle[p].velocity -= vectorToNeighbor * myEmitter.neighborAttraction * deltaTime; + _particle[p].velocity -= vectorToNeighbor * myEmitter.particleAttributes.neighborAttraction * deltaTime; float distanceToNeighbor = glm::length(vectorToNeighbor); if (distanceToNeighbor > 0.0f) { - _particle[neighbor].velocity += (vectorToNeighbor / ( 1.0f + distanceToNeighbor * distanceToNeighbor)) * myEmitter.neighborRepulsion * deltaTime; + _particle[neighbor].velocity += (vectorToNeighbor / ( 1.0f + distanceToNeighbor * distanceToNeighbor)) * myEmitter.particleAttributes.neighborRepulsion * deltaTime; } } // apply tornado force glm::vec3 tornadoDirection = glm::cross(vectorToHome, myEmitter.up); - _particle[p].velocity += tornadoDirection * myEmitter.tornadoForce * deltaTime; + _particle[p].velocity += tornadoDirection * myEmitter.particleAttributes.tornadoForce * deltaTime; // apply air friction - float drag = 1.0 - myEmitter.airFriction * deltaTime; + float drag = 1.0 - myEmitter.particleAttributes.airFriction * deltaTime; if (drag < 0.0f) { _particle[p].velocity = glm::vec3(0.0f, 0.0f, 0.0f); } else { @@ -228,7 +216,7 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { } // apply gravity - _particle[p].velocity -= _upDirection * myEmitter.gravity * deltaTime; + _particle[p].velocity -= _upDirection * myEmitter.particleAttributes.gravity * deltaTime; // update position by velocity _particle[p].position += _particle[p].velocity; @@ -238,29 +226,29 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { _particle[p].position.y = _particle[p].radius; if (_particle[p].velocity.y < 0.0f) { - _particle[p].velocity.y *= -myEmitter.bounce; + _particle[p].velocity.y *= -myEmitter.particleAttributes.bounce; } } // collision with sphere - if (myEmitter.usingCollisionSphere) { - glm::vec3 vectorToSphereCenter = myEmitter.collisionSpherePosition - _particle[p].position; + if (myEmitter.particleAttributes.usingCollisionSphere) { + glm::vec3 vectorToSphereCenter = myEmitter.particleAttributes.collisionSpherePosition - _particle[p].position; float distanceToSphereCenter = glm::length(vectorToSphereCenter); - float combinedRadius = myEmitter.collisionSphereRadius + _particle[p].radius; + float combinedRadius = myEmitter.particleAttributes.collisionSphereRadius + _particle[p].radius; if (distanceToSphereCenter < combinedRadius) { if (distanceToSphereCenter > 0.0f){ glm::vec3 directionToSphereCenter = vectorToSphereCenter / distanceToSphereCenter; - _particle[p].position = myEmitter.collisionSpherePosition - directionToSphereCenter * combinedRadius; + _particle[p].position = myEmitter.particleAttributes.collisionSpherePosition - directionToSphereCenter * combinedRadius; } } } } void ParticleSystem::setCollisionSphere(int e, glm::vec3 position, float radius) { - _emitter[e].usingCollisionSphere = true; - _emitter[e].collisionSpherePosition = position; - _emitter[e].collisionSphereRadius = radius; + _emitter[e].particleAttributes.usingCollisionSphere = true; + _emitter[e].particleAttributes.collisionSpherePosition = position; + _emitter[e].particleAttributes.collisionSphereRadius = radius; } void ParticleSystem::render() { diff --git a/interface/src/ParticleSystem.h b/interface/src/ParticleSystem.h index 3b8826d697..c94acd03ba 100644 --- a/interface/src/ParticleSystem.h +++ b/interface/src/ParticleSystem.h @@ -16,29 +16,8 @@ const int MAX_EMITTERS = 20; class ParticleSystem { public: - ParticleSystem(); - - int addEmitter(); // add (create) an emitter and get its unique id - void emitParticlesNow(int e, int numParticles, float radius, glm::vec4 color, glm::vec3 velocity, float lifespan); - void simulate(float deltaTime); - void render(); - - void setOrangeBlueColorPalette(); // apply a nice preset color palette to the particles - void setCollisionSphere(int e, glm::vec3 position, float radius); // specify a sphere for the particles to collide with - void setEmitterPosition(int e, glm::vec3 position) { _emitter[e].position = position; } // set the position of this emitter - void setEmitterRotation(int e, glm::quat rotation) { _emitter[e].rotation = rotation; } // set the rotation of this emitter - void setUpDirection(glm::vec3 upDirection) {_upDirection = upDirection;} // tell particle system which direction is up - void setShowingEmitter(int e, bool showing) { _emitter[e].showingEmitter = showing;} - - -private: - struct Emitter { - glm::vec3 position; - glm::quat rotation; - glm::vec3 right; - glm::vec3 up; - glm::vec3 front; + struct ParticleAttributes { float bounce; float gravity; float airFriction; @@ -50,7 +29,34 @@ private: bool usingCollisionSphere; glm::vec3 collisionSpherePosition; float collisionSphereRadius; + }; + + ParticleSystem(); + + int addEmitter(); // add (create) an emitter and get its unique id + void emitParticlesNow(int e, int numParticles, float radius, glm::vec4 color, glm::vec3 velocity, float lifespan); + void simulate(float deltaTime); + void render(); + + void setParticleAttributesForEmitter(int emitterIndex, ParticleAttributes attributes); + void setOrangeBlueColorPalette(); // apply a nice preset color palette to the particles + void setUpDirection(glm::vec3 upDirection) {_upDirection = upDirection;} // tell particle system which direction is up + + void setCollisionSphere(int emitterIndex, glm::vec3 position, float radius); // specify a sphere for the particles to collide with + void setEmitterPosition(int emitterIndex, glm::vec3 position) { _emitter[emitterIndex].position = position; } // set position of emitter + void setEmitterRotation(int emitterIndex, glm::quat rotation) { _emitter[emitterIndex].rotation = rotation; } // set rotation of emitter + void setShowingEmitter (int emitterIndex, bool showing ) { _emitter[emitterIndex].showingEmitter = showing; } // set its visibiity + +private: + + struct Emitter { + glm::vec3 position; + glm::quat rotation; + glm::vec3 right; + glm::vec3 up; + glm::vec3 front; bool showingEmitter; + ParticleAttributes particleAttributes; }; struct Particle { @@ -75,7 +81,7 @@ private: void updateEmitter(int e, float deltaTime); void updateParticle(int index, float deltaTime); void createParticle(int e, glm::vec3 position, glm::vec3 velocity, float radius, glm::vec4 color, float lifespan); - void runSpecialEffectsTest(int e, float deltaTime); // for debugging and artistic exploration + //void runSpecialEffectsTest(int e, float deltaTime); // for debugging and artistic exploration void killParticle(int p); void renderEmitter(int emitterIndex, float size); void renderParticle(int p); From edf031b98566e73efe3dee0499e26bce90193c81 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 15 Jul 2013 22:42:55 -0700 Subject: [PATCH 22/41] improve collision sounds, difference between ground and voxels --- interface/src/Audio.cpp | 18 +++++++++++++----- interface/src/Audio.h | 5 +++++ interface/src/Avatar.cpp | 34 +++++++++++++++++++++++++++------- interface/src/Avatar.h | 1 + 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 1e04e563a2..8b2856a7c9 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -333,6 +333,9 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : _flangeRate(0.0f), _flangeWeight(0.0f), _collisionSoundMagnitude(0.0f), + _collisionSoundFrequency(0.0f), + _collisionSoundNoise(0.0f), + _collisionSoundDuration(0.0f), _proceduralEffectSample(0), _heartbeatMagnitude(0.0f) { @@ -621,17 +624,16 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, } } const float COLLISION_SOUND_CUTOFF_LEVEL = 5.0f; - const float COLLISION_SOUND_PITCH_1 = 2.0f; - const float COLLISION_SOUND_DECAY = 1.f/1024.f; - const float COLLISION_VOLUME_BASELINE = 10.f; int sample; if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) { for (int i = 0; i < numSamples; i++) { - sample = (int16_t) ((sinf((float) (_proceduralEffectSample + i) / COLLISION_SOUND_PITCH_1) * COLLISION_VOLUME_BASELINE * _collisionSoundMagnitude)); + sample = (int16_t) (((sinf(((float)_proceduralEffectSample + (float)i) * _collisionSoundFrequency) * (1.f - _collisionSoundNoise) + + ((randFloat() * 2.f - 1.0f) * _collisionSoundNoise)) + * _collisionSoundMagnitude)); inputBuffer[i] += sample; outputLeft[i] += sample; outputRight[i] += sample; - _collisionSoundMagnitude *= (1.f - COLLISION_SOUND_DECAY); + _collisionSoundMagnitude *= _collisionSoundDuration; } } @@ -641,6 +643,12 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, _proceduralEffectSample += numSamples; } +void Audio::startCollisionSound(float magnitude, float frequency, float noise, float duration) { + _collisionSoundMagnitude = magnitude; + _collisionSoundFrequency = frequency; + _collisionSoundNoise = noise; + _collisionSoundDuration = duration; +} // ----------------------------------------------------------- // Accoustic ping (audio system round trip time determination) // ----------------------------------------------------------- diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 1ab671a30b..a43e05e3ec 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -46,6 +46,8 @@ public: void setCollisionSoundMagnitude(float collisionSoundMagnitude) { _collisionSoundMagnitude = collisionSoundMagnitude; } + void startCollisionSound(float magnitude, float frequency, float noise, float duration); + void ping(); // Call periodically to eventually perform round trip time analysis, @@ -84,6 +86,9 @@ private: float _flangeRate; float _flangeWeight; float _collisionSoundMagnitude; + float _collisionSoundFrequency; + float _collisionSoundNoise; + float _collisionSoundDuration; int _proceduralEffectSample; float _heartbeatMagnitude; diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 289d5548c4..b3868f6ea7 100755 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -873,12 +873,15 @@ void Avatar::updateCollisionWithEnvironment() { float radius = _height * 0.125f; const float ENVIRONMENT_SURFACE_ELASTICITY = 1.0f; const float ENVIRONMENT_SURFACE_DAMPING = 0.01; + const float ENVIRONMENT_COLLISION_FREQUENCY = 0.05f; glm::vec3 penetration; if (Application::getInstance()->getEnvironment()->findCapsulePenetration( _position - up * (_pelvisFloatingHeight - radius), _position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) { + createCollisionSound(penetration, ENVIRONMENT_COLLISION_FREQUENCY); applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING); + } } @@ -887,10 +890,12 @@ void Avatar::updateCollisionWithVoxels() { float radius = _height * 0.125f; const float VOXEL_ELASTICITY = 1.4f; const float VOXEL_DAMPING = 0.0; + const float VOXEL_COLLISION_FREQUENCY = 0.5f; glm::vec3 penetration; if (Application::getInstance()->getVoxels()->findCapsulePenetration( _position - glm::vec3(0.0f, _pelvisFloatingHeight - radius, 0.0f), _position + glm::vec3(0.0f, _height - _pelvisFloatingHeight - radius, 0.0f), radius, penetration)) { + createCollisionSound(penetration, VOXEL_COLLISION_FREQUENCY); applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); } } @@ -916,16 +921,31 @@ void Avatar::applyHardCollision(const glm::vec3& penetration, float elasticity, // If moving really slowly after a collision, and not applying forces, stop altogether _velocity *= 0.f; } - // Push the collision into the audio system for procedural effects - const float AUDIBLE_COLLISION_THRESHOLD = 200.f; - const float COLLISION_VOLUME = 10000.f; - float collisionSoundLevel = penetrationLength * COLLISION_VOLUME; - if (collisionSoundLevel > AUDIBLE_COLLISION_THRESHOLD) { - Application::getInstance()->getAudio()->setCollisionSoundMagnitude(collisionSoundLevel); - } } } +void Avatar::createCollisionSound(const glm::vec3 &penetration, float frequency) { + // Push the collision into the audio system for procedural effects + const float AUDIBLE_COLLISION_THRESHOLD = 0.2f; + const float COLLISION_VOLUME = 1000.f; + const float MAX_COLLISION_VOLUME = 15000.f; + const float DURATION_SCALING = 0.004f; + float velocityTowardCollision = glm::dot(_velocity, glm::normalize(penetration)); + float velocityTangentToCollision = glm::length(_velocity) - velocityTowardCollision; + if (velocityTowardCollision > AUDIBLE_COLLISION_THRESHOLD) { + Application::getInstance()->getAudio()->startCollisionSound( + fmax(COLLISION_VOLUME * velocityTowardCollision, MAX_COLLISION_VOLUME), + frequency, + fmin(velocityTangentToCollision / velocityTowardCollision, 1.f), + 1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision); + + } + //float collisionSoundLevel = penetrationLength * COLLISION_VOLUME; + //if (collisionSoundLevel > AUDIBLE_COLLISION_THRESHOLD) { + // Application::getInstance()->getAudio()->setCollisionSoundMagnitude(collisionSoundLevel); + //} +} + void Avatar::updateAvatarCollisions(float deltaTime) { // Reset detector for nearest avatar diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 643a187a67..31c9b573b8 100755 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -262,6 +262,7 @@ private: void updateCollisionWithEnvironment(); void updateCollisionWithVoxels(); void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping); + void createCollisionSound(const glm::vec3& penetration, float frequency); void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime ); void checkForMouseRayTouching(); }; From 7becb943570a98c957f335f3fc6fba7a9067615d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 16 Jul 2013 09:41:34 -0700 Subject: [PATCH 23/41] reworking time stamps from doubles --- voxel-server/src/VoxelNodeData.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/voxel-server/src/VoxelNodeData.cpp b/voxel-server/src/VoxelNodeData.cpp index 28796435b5..2218724c79 100644 --- a/voxel-server/src/VoxelNodeData.cpp +++ b/voxel-server/src/VoxelNodeData.cpp @@ -84,8 +84,7 @@ void VoxelNodeData::updateLastKnownViewFrustum() { } // save that we know the view has been sent. - double now = usecTimestampNow(); - printf("updateLastKnownViewFrustum() setLastViewSent() to %lf\n", now); - setLastViewSent(now); + uint64_t now = usecTimestampNow(); + setLastTimeBagEmpty(now); // is this what we want? poor names } From 8626c95a20e14e585f7710767a599ef050670f06 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 16 Jul 2013 12:01:09 -0700 Subject: [PATCH 24/41] whitespace fix --- libraries/voxels/src/VoxelNode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 131371c02b..461a723a8a 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -41,7 +41,7 @@ private: void calculateAABox(); void init(unsigned char * octalCode); - + public: VoxelNode(); // root node constructor VoxelNode(unsigned char * octalCode); // regular constructor From fbc59de0810242feccac5bfbddcf3c4b02e4aafc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 16 Jul 2013 15:08:09 -0700 Subject: [PATCH 25/41] latest cut at dirty bit sending --- libraries/shared/src/OctalCode.cpp | 2 ++ libraries/voxels/src/VoxelConstants.h | 1 + libraries/voxels/src/VoxelNode.h | 1 + libraries/voxels/src/VoxelTree.cpp | 37 ++++++++++++++++++++++----- libraries/voxels/src/VoxelTree.h | 6 ++++- voxel-server/src/VoxelNodeData.cpp | 2 -- voxel-server/src/main.cpp | 13 +++++++--- 7 files changed, 49 insertions(+), 13 deletions(-) diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 3b92869104..b085a146a2 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -7,6 +7,7 @@ // #include // std:min +#include #include #include @@ -16,6 +17,7 @@ #include "OctalCode.h" int numberOfThreeBitSectionsInCode(unsigned char * octalCode) { + assert(octalCode); if (*octalCode == 255) { return *octalCode + numberOfThreeBitSectionsInCode(octalCode + 1); } else { diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 421c03f3b6..6fdfec1de9 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -21,6 +21,7 @@ const glm::vec3 IDENTITY_UP = glm::vec3( 0.0f, 1.0f, 0.0f); const glm::vec3 IDENTITY_FRONT = glm::vec3( 0.0f, 0.0f,-1.0f); const bool LOW_RES_MONO = false; // while in "low res mode" do voxels switch to monochrome +const uint64_t CHANGE_FUDGE = 1000*200; // useconds of fudge in determining if we want to resend changed voxels const int TREE_SCALE = 128; diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 461a723a8a..8e3b9cb5db 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -85,6 +85,7 @@ public: void clearDirtyBit() { _isDirty = false; }; bool hasChangedSince(uint64_t time) const { return (_lastChanged > time); }; void markWithChangedTime() { _lastChanged = usecTimestampNow(); }; + uint64_t getLastChanged() const { return _lastChanged; }; void handleSubtreeChanged(VoxelTree* myTree); glBufferIndex getBufferIndex() const { return _glBufferIndex; }; diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 88c523dbfe..461292a28e 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1012,12 +1012,18 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, unsigned char* outputBuffer, // How many bytes have we written so far at this level; int bytesWritten = 0; + + // These two cases should not ever happen... but if they do, we don't want to crash. + if (!node || !node->getOctalCode()) { + qDebug("VoxelTree::encodeTreeBitstream() BAD VoxelNode! Bailing!"); + return bytesWritten; + } // 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 (params.viewFrustum && !node->isInView(*params.viewFrustum)) { return bytesWritten; } - + // write the octal code int codeLength; if (params.chopLevels) { @@ -1076,7 +1082,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp if (currentEncodeLevel >= params.maxEncodeLevel) { return bytesAtThisLevel; } - + // caller can pass NULL as viewFrustum if they want everything if (params.viewFrustum) { float distance = node->distanceToCamera(*params.viewFrustum); @@ -1109,10 +1115,26 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp } } - // If we were in view, then bail out early! - if (wasInView) { + // If we were in view, and haven't changed, then bail out early! + if (wasInView && params.deltaViewFrustum) { + printf("wasInView... params.lastViewFrustumSent=[%lld] getLastChanged()=%lld\n", + params.lastViewFrustumSent, node->getLastChanged()); + } + + if (wasInView && !(params.deltaViewFrustum && node->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE))) { + //if (wasInView) { return bytesAtThisLevel; - } + } + +/** + // now, if we're not in delta sending mode, but the voxel hasn't changed, then we can bail early... + if (!params.deltaViewFrustum && !node->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE)) { + printf("not delta sending, and the node hasn't changed, bail early... params.lastViewFrustumSent=[%lld] getLastChanged()=%lld\n", + params.lastViewFrustumSent, node->getLastChanged()); + 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 @@ -1258,7 +1280,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp bool shouldRender = !params.viewFrustum ? true : childNode->calculateShouldRender(params.viewFrustum, params.boundaryLevelAdjust); // track children with actual color, only if the child wasn't previously in view! - //(!childWasInView || childNode->hasChangedSince(lastViewFrustumSent) )) { if (shouldRender && !childIsOccluded) { bool childWasInView = false; @@ -1274,7 +1295,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp } // If our child wasn't in view (or we're ignoring wasInView) then we add it to our sending items - if (!childWasInView) { + if (!childWasInView || + (params.deltaViewFrustum && + childNode->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE))){ childrenColoredBits += (1 << (7 - originalIndex)); inViewWithColorCount++; } else { diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 9c8e6e7d16..bab66c5097 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -35,6 +35,7 @@ typedef enum {GRADIENT, RANDOM, NATURAL} creationMode; #define DONT_CHOP 0 #define NO_BOUNDARY_ADJUST 0 #define LOW_RES_MOVING_ADJUST 1 +#define IGNORE_LAST_SENT 0 class EncodeBitstreamParams { public: @@ -49,6 +50,7 @@ public: bool wantOcclusionCulling; long childWasInViewDiscarded; int boundaryLevelAdjust; + uint64_t lastViewFrustumSent; CoverageMap* map; @@ -62,7 +64,8 @@ public: const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM, bool wantOcclusionCulling= NO_OCCLUSION_CULLING, CoverageMap* map = IGNORE_COVERAGE_MAP, - int boundaryLevelAdjust = NO_BOUNDARY_ADJUST) : + int boundaryLevelAdjust = NO_BOUNDARY_ADJUST, + uint64_t lastViewFrustumSent = IGNORE_LAST_SENT) : maxEncodeLevel (maxEncodeLevel), maxLevelReached (0), viewFrustum (viewFrustum), @@ -74,6 +77,7 @@ public: wantOcclusionCulling (wantOcclusionCulling), childWasInViewDiscarded (0), boundaryLevelAdjust (boundaryLevelAdjust), + lastViewFrustumSent (lastViewFrustumSent), map (map) {} }; diff --git a/voxel-server/src/VoxelNodeData.cpp b/voxel-server/src/VoxelNodeData.cpp index 2218724c79..f3d87948aa 100644 --- a/voxel-server/src/VoxelNodeData.cpp +++ b/voxel-server/src/VoxelNodeData.cpp @@ -24,8 +24,6 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) : { _voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; _voxelPacketAt = _voxelPacket; - _lastViewFrustumSent = 0; - resetVoxelPacket(); } diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index df7011585d..bfb0e4505c 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -173,10 +173,10 @@ void deepestLevelVoxelDistributor(NodeList* nodeList, // If the current view frustum has changed OR we have nothing to send, then search against // the current view frustum for things to send. if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) { + uint64_t now = usecTimestampNow(); if (::debugVoxelSending) { printf("(viewFrustumChanged=%s || nodeData->nodeBag.isEmpty() =%s)...\n", debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty())); - uint64_t now = usecTimestampNow(); if (nodeData->getLastTimeBagEmpty() > 0) { float elapsedSceneSend = (now - nodeData->getLastTimeBagEmpty()) / 1000000.0f; if (viewFrustumChanged) { @@ -188,13 +188,19 @@ void deepestLevelVoxelDistributor(NodeList* nodeList, debug::valueOf(nodeData->getWantOcclusionCulling()), debug::valueOf(wantDelta), debug::valueOf(wantColor)); } - 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... if (viewFrustumChanged) { nodeData->nodeBag.deleteAll(); nodeData->map.erase(); + } + + if (!viewFrustumChanged && !nodeData->getWantDelta()) { + // only set our last sent time if we weren't resetting due to frustum change + uint64_t now = usecTimestampNow(); + nodeData->setLastTimeBagEmpty(now); + printf("ENTIRE SCENE SENT! nodeData->setLastTimeBagEmpty(now=[%lld])\n", now); } nodeData->nodeBag.insert(serverTree.rootNode); @@ -233,7 +239,8 @@ void deepestLevelVoxelDistributor(NodeList* nodeList, EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, - wantOcclusionCulling, coverageMap, boundaryLevelAdjust); + wantOcclusionCulling, coverageMap, boundaryLevelAdjust, + nodeData->getLastTimeBagEmpty()); bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, nodeData->nodeBag, params); From 192ae637893c3b22a16cbf3a3504595490cae64d Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 16 Jul 2013 16:40:50 -0700 Subject: [PATCH 26/41] Colliding with ground, voxels makes interesting sounds and flashes your display --- interface/src/Application.cpp | 6 +++- interface/src/Application.h | 7 +++- interface/src/Audio.cpp | 30 ++++++++--------- interface/src/Audio.h | 4 +-- interface/src/Avatar.cpp | 61 +++++++++++++++++++++-------------- interface/src/Avatar.h | 8 +++-- interface/src/Util.cpp | 34 +++++++++++++------ interface/src/Util.h | 5 ++- 8 files changed, 97 insertions(+), 58 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 644d5524f0..a2fe2072c6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -188,6 +188,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _isTouchPressed(false), _yawFromTouch(0.0f), _pitchFromTouch(0.0f), + _groundPlaneImpact(0.0f), _mousePressed(false), _mouseVoxelScale(1.0f / 1024.0f), _justEditedVoxel(false), @@ -2516,7 +2517,7 @@ void Application::displaySide(Camera& whichCamera) { //draw a grid ground plane.... if (_renderGroundPlaneOn->isChecked()) { - drawGroundPlaneGrid(EDGE_SIZE_GROUND_PLANE); + renderGroundPlaneGrid(EDGE_SIZE_GROUND_PLANE, _audio.getCollisionSoundMagnitude()); } // Draw voxels if (_renderVoxels->isChecked()) { @@ -2592,6 +2593,9 @@ void Application::displayOverlay() { glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); + // Display a single screen-size quad to + renderCollisionOverlay(_glWidget->width(), _glWidget->height(), _audio.getCollisionSoundMagnitude()); + #ifndef _WIN32 _audio.render(_glWidget->width(), _glWidget->height()); if (_oscilloscopeOn->isChecked()) { diff --git a/interface/src/Application.h b/interface/src/Application.h index b46ee20111..cb1896c4de 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -101,6 +101,9 @@ public: QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; } GeometryCache* getGeometryCache() { return &_geometryCache; } + void setGroundPlaneImpact(float groundPlaneImpact) { _groundPlaneImpact = groundPlaneImpact; } + + private slots: void timer(); @@ -206,7 +209,7 @@ private: void deleteVoxelUnderCursor(); void eyedropperVoxelUnderCursor(); void resetSensors(); - + void setMenuShortcutsEnabled(bool enabled); void updateCursor(); @@ -344,6 +347,8 @@ private: float _yawFromTouch; float _pitchFromTouch; + float _groundPlaneImpact; + VoxelDetail _mouseVoxelDragging; glm::vec3 _voxelThrust; bool _mousePressed; // true if mouse has been pressed (clear when finished) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 8b2856a7c9..dc36968c3b 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -605,11 +605,7 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, float speed = glm::length(_lastVelocity); float volume = VOLUME_BASELINE * (1.f - speed / MAX_AUDIBLE_VELOCITY); - // Test tone (should be continuous!) - /* - for (int i = 0; i < numSamples; i++) { - inputBuffer[i] += (int16_t) (_proceduralEffectSample + i)%16 * 10; - }*/ + int sample; // // Travelling noise @@ -617,32 +613,32 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, // Add a noise-modulated sinewave with volume that tapers off with speed increasing if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { for (int i = 0; i < numSamples; i++) { - //inputBuffer[i] += (int16_t)((sinf((float) (_proceduralEffectSample + i) / SOUND_PITCH * speed) * (1.f + randFloat() * 0.0f)) * volume * speed); inputBuffer[i] += (int16_t)(sinf((float) (_proceduralEffectSample + i) / SOUND_PITCH ) * volume * (1.f + randFloat() * 0.25f) * speed); - - } } - const float COLLISION_SOUND_CUTOFF_LEVEL = 5.0f; - int sample; + const float COLLISION_SOUND_CUTOFF_LEVEL = 0.01f; + const float COLLISION_SOUND_MAX_VOLUME = 1000.f; + const float UP_MAJOR_FIFTH = powf(1.5f, 4.0f); + float t; if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) { for (int i = 0; i < numSamples; i++) { - sample = (int16_t) (((sinf(((float)_proceduralEffectSample + (float)i) * _collisionSoundFrequency) * (1.f - _collisionSoundNoise) - + ((randFloat() * 2.f - 1.0f) * _collisionSoundNoise)) - * _collisionSoundMagnitude)); + t = (float) _proceduralEffectSample + (float) i; + sample = sinf(t * _collisionSoundFrequency) + + sinf(t * _collisionSoundFrequency / 4.f) + + sinf(t * _collisionSoundFrequency / 16.f * UP_MAJOR_FIFTH); + sample *= _collisionSoundMagnitude * COLLISION_SOUND_MAX_VOLUME; inputBuffer[i] += sample; outputLeft[i] += sample; outputRight[i] += sample; _collisionSoundMagnitude *= _collisionSoundDuration; } } - - //if (_heartbeatMagnitude > 0.0f) { - // - //} _proceduralEffectSample += numSamples; } +// +// Starts a collision sound. magnitude is 0-1, with 1 the loudest possible sound. +// void Audio::startCollisionSound(float magnitude, float frequency, float noise, float duration) { _collisionSoundMagnitude = magnitude; _collisionSoundFrequency = frequency; diff --git a/interface/src/Audio.h b/interface/src/Audio.h index a43e05e3ec..5954361444 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -43,10 +43,10 @@ public: int getJitterBufferSamples() { return _jitterBufferSamples; }; void lowPassFilter(int16_t* inputBuffer); - - void setCollisionSoundMagnitude(float collisionSoundMagnitude) { _collisionSoundMagnitude = collisionSoundMagnitude; } void startCollisionSound(float magnitude, float frequency, float noise, float duration); + float getCollisionSoundMagnitude() { return _collisionSoundMagnitude; }; + void ping(); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index b3868f6ea7..e34a4ff194 100755 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -545,8 +545,8 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { _position += _scale * _gravity * (GRAVITY_EARTH * deltaTime) * deltaTime; } - updateCollisionWithEnvironment(); - updateCollisionWithVoxels(); + updateCollisionWithEnvironment(deltaTime); + updateCollisionWithVoxels(deltaTime); updateAvatarCollisions(deltaTime); } @@ -867,7 +867,7 @@ void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float d } } -void Avatar::updateCollisionWithEnvironment() { +void Avatar::updateCollisionWithEnvironment(float deltaTime) { glm::vec3 up = getBodyUpDirection(); float radius = _height * 0.125f; @@ -878,7 +878,12 @@ void Avatar::updateCollisionWithEnvironment() { if (Application::getInstance()->getEnvironment()->findCapsulePenetration( _position - up * (_pelvisFloatingHeight - radius), _position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) { - createCollisionSound(penetration, ENVIRONMENT_COLLISION_FREQUENCY); + float velocityTowardCollision = glm::dot(_velocity, glm::normalize(penetration)); + if (velocityTowardCollision > 0.2) { + Application::getInstance()->setGroundPlaneImpact(1.0f); + } + updateCollisionSound(penetration, deltaTime, ENVIRONMENT_COLLISION_FREQUENCY); + applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING); @@ -886,7 +891,7 @@ void Avatar::updateCollisionWithEnvironment() { } -void Avatar::updateCollisionWithVoxels() { +void Avatar::updateCollisionWithVoxels(float deltaTime) { float radius = _height * 0.125f; const float VOXEL_ELASTICITY = 1.4f; const float VOXEL_DAMPING = 0.0; @@ -895,7 +900,7 @@ void Avatar::updateCollisionWithVoxels() { if (Application::getInstance()->getVoxels()->findCapsulePenetration( _position - glm::vec3(0.0f, _pelvisFloatingHeight - radius, 0.0f), _position + glm::vec3(0.0f, _height - _pelvisFloatingHeight - radius, 0.0f), radius, penetration)) { - createCollisionSound(penetration, VOXEL_COLLISION_FREQUENCY); + updateCollisionSound(penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); } } @@ -924,26 +929,34 @@ void Avatar::applyHardCollision(const glm::vec3& penetration, float elasticity, } } -void Avatar::createCollisionSound(const glm::vec3 &penetration, float frequency) { - // Push the collision into the audio system for procedural effects - const float AUDIBLE_COLLISION_THRESHOLD = 0.2f; - const float COLLISION_VOLUME = 1000.f; - const float MAX_COLLISION_VOLUME = 15000.f; +void Avatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) { + // consider whether to have the collision make a sound + const float AUDIBLE_COLLISION_THRESHOLD = 0.02f; + const float COLLISION_LOUDNESS = 1.f; const float DURATION_SCALING = 0.004f; - float velocityTowardCollision = glm::dot(_velocity, glm::normalize(penetration)); - float velocityTangentToCollision = glm::length(_velocity) - velocityTowardCollision; - if (velocityTowardCollision > AUDIBLE_COLLISION_THRESHOLD) { - Application::getInstance()->getAudio()->startCollisionSound( - fmax(COLLISION_VOLUME * velocityTowardCollision, MAX_COLLISION_VOLUME), - frequency, - fmin(velocityTangentToCollision / velocityTowardCollision, 1.f), - 1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision); - + const float NOISE_SCALING = 0.1f; + glm::vec3 velocity = _velocity; + glm::vec3 gravity = getGravity(); + + if (glm::length(gravity) > EPSILON) { + // If gravity is on, remove the effect of gravity on velocity for this + // frame, so that we are not constantly colliding with the surface + velocity -= _scale * glm::length(gravity) * GRAVITY_EARTH * deltaTime * glm::normalize(gravity); + } + float velocityTowardCollision = glm::dot(velocity, glm::normalize(penetration)); + float velocityTangentToCollision = glm::length(velocity) - velocityTowardCollision; + + if (velocityTowardCollision > AUDIBLE_COLLISION_THRESHOLD) { + // Volume is proportional to collision velocity + // Base frequency is modified upward by the angle of the collision + // Noise is a function of the angle of collision + // Duration of the sound is a function of both base frequency and velocity of impact + Application::getInstance()->getAudio()->startCollisionSound( + fmin(COLLISION_LOUDNESS * velocityTowardCollision, 1.f), + frequency * (1.f + velocityTangentToCollision / velocityTowardCollision), + fmin(velocityTangentToCollision / velocityTowardCollision * NOISE_SCALING, 1.f), + 1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision); } - //float collisionSoundLevel = penetrationLength * COLLISION_VOLUME; - //if (collisionSoundLevel > AUDIBLE_COLLISION_THRESHOLD) { - // Application::getInstance()->getAudio()->setCollisionSoundMagnitude(collisionSoundLevel); - //} } void Avatar::updateAvatarCollisions(float deltaTime) { diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 31c9b573b8..fa605fa425 100755 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -159,6 +159,8 @@ public: glm::quat getOrientation () const; glm::quat getWorldAlignedOrientation() const; + glm::vec3 getGravity () const { return _gravity; } + glm::vec3 getUprightHeadPosition() const; AvatarVoxelSystem* getVoxels() { return &_voxels; } @@ -259,10 +261,10 @@ private: void updateAvatarCollisions(float deltaTime); void updateArmIKAndConstraints( float deltaTime ); void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime ); - void updateCollisionWithEnvironment(); - void updateCollisionWithVoxels(); + void updateCollisionWithEnvironment(float deltaTime); + void updateCollisionWithVoxels(float deltaTime); void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping); - void createCollisionSound(const glm::vec3& penetration, float frequency); + void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime ); void checkForMouseRayTouching(); }; diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 65a277b623..ddce092896 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -326,22 +326,38 @@ void drawvec3(int x, int y, float scale, float rotate, float thick, int mono, gl glPopMatrix(); } +void renderCollisionOverlay(int width, int height, float magnitude) { + const float MIN_VISIBLE_COLLISION = 0.01f; + if (magnitude > MIN_VISIBLE_COLLISION) { + glColor4f(0, 0, 0, magnitude); + glBegin(GL_QUADS); + glVertex2f(0, 0); + glVertex2d(width, 0); + glVertex2d(width, height); + glVertex2d(0, height); + glEnd(); + } +} -void drawGroundPlaneGrid(float size) { - glColor3f(0.4f, 0.5f, 0.3f); +void renderGroundPlaneGrid(float size, float impact) { glLineWidth(2.0); - + glm::vec4 impactColor(1, 0, 0, 1); + glm::vec3 lineColor(0.4, 0.5, 0.3); + glm::vec4 surfaceColor(0.5, 0.5, 0.5, 0.4); + + glColor3fv(&lineColor.x); for (float x = 0; x <= size; x++) { glBegin(GL_LINES); - glVertex3f(x, 0.0f, 0); - glVertex3f(x, 0.0f, size); - glVertex3f(0, 0.0f, x); - glVertex3f(size, 0.0f, x); + glVertex3f(x, 0, 0); + glVertex3f(x, 0, size); + glVertex3f(0, 0, x); + glVertex3f(size, 0, x); glEnd(); } - // Draw a translucent quad just underneath the grid. - glColor4f(0.5, 0.5, 0.5, 0.4); + // Draw the floor, colored for recent impact + glm::vec4 floorColor = impact * impactColor + (1.f - impact) * surfaceColor; + glColor4fv(&floorColor.x); glBegin(GL_QUADS); glVertex3f(0, 0, 0); glVertex3f(size, 0, 0); diff --git a/interface/src/Util.h b/interface/src/Util.h index 37bd0595ec..8bc77a98ea 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -57,7 +57,10 @@ glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha); double diffclock(timeval *clock1,timeval *clock2); -void drawGroundPlaneGrid(float size); +void renderGroundPlaneGrid(float size, float impact); + +void renderCollisionOverlay(int width, int height, float magnitude); + void renderDiskShadow(glm::vec3 position, glm::vec3 upDirection, float radius, float darkness); From 75d052b997b46abbf23b85caff49f7b3ade23736 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 16 Jul 2013 16:46:58 -0700 Subject: [PATCH 27/41] cleanup --- libraries/voxels/src/VoxelTree.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 461292a28e..d11e26114c 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -449,7 +449,6 @@ void VoxelTree::deleteVoxelCodeFromTreeRecursion(VoxelNode* node, void* extraDat } } - // track our tree dirtiness _isDirty = true; args->pathChanged = true; From d54bae8e763f64fbf15b392523401e240b9cc36d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 16 Jul 2013 16:47:18 -0700 Subject: [PATCH 28/41] cleanup --- libraries/voxels/src/VoxelTree.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index d11e26114c..3b4df380f0 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -448,7 +448,6 @@ void VoxelTree::deleteVoxelCodeFromTreeRecursion(VoxelNode* node, void* extraDat ancestorNode->setColor(node->getColor()); } } - _isDirty = true; args->pathChanged = true; From 5ee691025628e757686c5810e285385595105738 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 16 Jul 2013 16:51:09 -0700 Subject: [PATCH 29/41] cleanup --- libraries/voxels/src/VoxelTree.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 3b4df380f0..d9e36b3388 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1113,26 +1113,21 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp } } - // If we were in view, and haven't changed, then bail out early! - if (wasInView && params.deltaViewFrustum) { - printf("wasInView... params.lastViewFrustumSent=[%lld] getLastChanged()=%lld\n", - params.lastViewFrustumSent, node->getLastChanged()); - } - + // If we were previously in the view, then we normally will return out of here and stop recursing. But + // if we're in deltaViewFrustum mode, and this node has changed since it was last sent, then we do + // need to send it. if (wasInView && !(params.deltaViewFrustum && node->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE))) { - //if (wasInView) { return bytesAtThisLevel; } -/** - // now, if we're not in delta sending mode, but the voxel hasn't changed, then we can bail early... + /** Not ready for production - coming soon. + // If we're not in delta sending mode, but the voxel hasn't changed, then we can also bail early... if (!params.deltaViewFrustum && !node->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE)) { - printf("not delta sending, and the node hasn't changed, bail early... params.lastViewFrustumSent=[%lld] getLastChanged()=%lld\n", + printf("not delta sending, and the node hasn't changed, bail early... lastSent=%lld getLastChanged=%lld\n", params.lastViewFrustumSent, node->getLastChanged()); 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 From bdb14fee33b997856967fa493b8de75796b11bfc Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 16 Jul 2013 16:53:15 -0700 Subject: [PATCH 30/41] cleanup --- libraries/voxels/src/VoxelTree.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index d9e36b3388..6ef9f293ee 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1287,7 +1287,9 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp } } - // If our child wasn't in view (or we're ignoring wasInView) then we add it to our sending items + // If our child wasn't in view (or we're ignoring wasInView) then we add it to our sending items. + // Or if we were previously in the view, but this node has changed since it was last sent, then we do + // need to send it. if (!childWasInView || (params.deltaViewFrustum && childNode->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE))){ From cf38a0e837c65f336c540fd3630b4faf163279bc Mon Sep 17 00:00:00 2001 From: Eric Johnston Date: Tue, 16 Jul 2013 17:02:40 -0700 Subject: [PATCH 31/41] Avatar's arm follows real or simulated Leap glove, if present. This is a tiny change, and the effect is pretty good. It's only active if there's a Leap device connected and you're using it, or else if you've used the Debug menu item to fake a Leap glove. --- interface/src/Avatar.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index e3f3032bdf..15ef875c75 100755 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -819,6 +819,12 @@ void Avatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMovem } else { _avatarTouch.setHasInteractingOther(false); } + + // If there's a leap-interaction hand visible, use that as the endpoint + if (getHand().getHandPositions().size() > 0) { + _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = + getHand().leapPositionToWorldPosition(getHand().getHandPositions()[0]); + } }//if (_isMine) //constrain right arm length and re-adjust elbow position as it bends From adc09cec68acfe6e5693e078f4961633976bde87 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 16 Jul 2013 17:21:28 -0700 Subject: [PATCH 32/41] some CR feedback --- libraries/voxels/src/VoxelConstants.h | 2 +- voxel-server/src/main.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 6fdfec1de9..452772ff07 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -21,7 +21,7 @@ const glm::vec3 IDENTITY_UP = glm::vec3( 0.0f, 1.0f, 0.0f); const glm::vec3 IDENTITY_FRONT = glm::vec3( 0.0f, 0.0f,-1.0f); const bool LOW_RES_MONO = false; // while in "low res mode" do voxels switch to monochrome -const uint64_t CHANGE_FUDGE = 1000*200; // useconds of fudge in determining if we want to resend changed voxels +const uint64_t CHANGE_FUDGE = 1000 * 200; // useconds of fudge in determining if we want to resend changed voxels const int TREE_SCALE = 128; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index bfb0e4505c..35bc4816c0 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -200,7 +200,9 @@ void deepestLevelVoxelDistributor(NodeList* nodeList, // only set our last sent time if we weren't resetting due to frustum change uint64_t now = usecTimestampNow(); nodeData->setLastTimeBagEmpty(now); - printf("ENTIRE SCENE SENT! nodeData->setLastTimeBagEmpty(now=[%lld])\n", now); + if (::debugVoxelSending) { + printf("ENTIRE SCENE SENT! nodeData->setLastTimeBagEmpty(now=[%lld])\n", now); + } } nodeData->nodeBag.insert(serverTree.rootNode); From 39130aef58424cd36e20cf04d2041989df91dc32 Mon Sep 17 00:00:00 2001 From: Eric Johnston Date: Tue, 16 Jul 2013 18:10:54 -0700 Subject: [PATCH 33/41] Rave Glove demo: activation mode and stage (dark backdrop) drawing. --- interface/src/Application.cpp | 1 + interface/src/Hand.cpp | 31 +++++++++++++++++++++++++++++++ interface/src/Hand.h | 4 ++++ 3 files changed, 36 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1bfba999b1..791353abdb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2033,6 +2033,7 @@ void Application::update(float deltaTime) { // Leap finger-sensing device LeapManager::enableFakeFingers(_simulateLeapHand->isChecked() || _testRaveGlove->isChecked()); LeapManager::nextFrame(); + _myAvatar.getHand().setRaveGloveActive(_testRaveGlove->isChecked()); _myAvatar.getHand().setLeapFingers(LeapManager::getFingerTips(), LeapManager::getFingerRoots()); _myAvatar.getHand().setLeapHands(LeapManager::getHandPositions(), LeapManager::getHandNormals()); diff --git a/interface/src/Hand.cpp b/interface/src/Hand.cpp index 29a2c32bf1..d0ff0abd5a 100755 --- a/interface/src/Hand.cpp +++ b/interface/src/Hand.cpp @@ -74,12 +74,43 @@ void Hand::render(bool lookingInMirror) { calculateGeometry(); + if (_isRaveGloveActive) + renderRaveGloveStage(); + glEnable(GL_DEPTH_TEST); glEnable(GL_RESCALE_NORMAL); renderHandSpheres(); } +void Hand::renderRaveGloveStage() { + if (_owningAvatar && _owningAvatar->isMyAvatar()) { + Head& head = _owningAvatar->getHead(); + glm::quat headOrientation = head.getOrientation(); + glm::vec3 headPosition = head.getPosition(); + float scale = 100.0f; + glm::vec3 vc = headOrientation * glm::vec3( 0.0f, 0.0f, -30.0f) + headPosition; + glm::vec3 v0 = headOrientation * (glm::vec3(-1.0f, -1.0f, 0.0f) * scale) + vc; + glm::vec3 v1 = headOrientation * (glm::vec3( 1.0f, -1.0f, 0.0f) * scale) + vc; + glm::vec3 v2 = headOrientation * (glm::vec3( 1.0f, 1.0f, 0.0f) * scale) + vc; + glm::vec3 v3 = headOrientation * (glm::vec3(-1.0f, 1.0f, 0.0f) * scale) + vc; + + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBegin(GL_TRIANGLE_FAN); + glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + glVertex3fv((float*)&vc); + glColor4f(0.0f, 0.0f, 0.0f, 0.5f); + glVertex3fv((float*)&v0); + glVertex3fv((float*)&v1); + glVertex3fv((float*)&v2); + glVertex3fv((float*)&v3); + glVertex3fv((float*)&v0); + glEnd(); + glEnable(GL_DEPTH_TEST); + } +} + void Hand::renderHandSpheres() { glPushMatrix(); // Draw the leap balls diff --git a/interface/src/Hand.h b/interface/src/Hand.h index 1c25c85fbc..e1b0dc9ff0 100755 --- a/interface/src/Hand.h +++ b/interface/src/Hand.h @@ -46,9 +46,11 @@ public: const std::vector& fingerRoots); void setLeapHands (const std::vector& handPositions, const std::vector& handNormals); + void setRaveGloveActive(bool active) { _isRaveGloveActive = active; } // getters const glm::vec3& getLeapBallPosition (int ball) const { return _leapBalls[ball].position;} + bool isRaveGloveActive () const { return _isRaveGloveActive; } // position conversion glm::vec3 leapPositionToWorldPosition(const glm::vec3& leapPosition); @@ -61,12 +63,14 @@ private: Avatar* _owningAvatar; float _renderAlpha; bool _lookingInMirror; + bool _isRaveGloveActive; glm::vec3 _ballColor; glm::vec3 _position; glm::quat _orientation; std::vector _leapBalls; // private methods + void renderRaveGloveStage(); void renderHandSpheres(); void calculateGeometry(); }; From 984332e63804da9c0329c96fcfc301abb0ad6935 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 17 Jul 2013 09:51:04 -0700 Subject: [PATCH 34/41] fixes per review --- interface/src/Audio.cpp | 8 +++++--- interface/src/Avatar.cpp | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 9f82559512..41090584f3 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -620,13 +620,15 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, const float COLLISION_SOUND_CUTOFF_LEVEL = 0.01f; const float COLLISION_SOUND_MAX_VOLUME = 1000.f; const float UP_MAJOR_FIFTH = powf(1.5f, 4.0f); + const float DOWN_TWO_OCTAVES = 4.f; + const float DOWN_FOUR_OCTAVES = 16.f; float t; if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) { for (int i = 0; i < numSamples; i++) { t = (float) _proceduralEffectSample + (float) i; sample = sinf(t * _collisionSoundFrequency) + - sinf(t * _collisionSoundFrequency / 4.f) + - sinf(t * _collisionSoundFrequency / 16.f * UP_MAJOR_FIFTH); + sinf(t * _collisionSoundFrequency / DOWN_TWO_OCTAVES) + + sinf(t * _collisionSoundFrequency / DOWN_FOUR_OCTAVES * UP_MAJOR_FIFTH); sample *= _collisionSoundMagnitude * COLLISION_SOUND_MAX_VOLUME; inputBuffer[i] += sample; outputLeft[i] += sample; @@ -638,7 +640,7 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, } // -// Starts a collision sound. magnitude is 0-1, with 1 the loudest possible sound. +// Starts a collision sound. magnitude is 0-1, with 1 the loudest possible sound. // void Audio::startCollisionSound(float magnitude, float frequency, float noise, float duration) { _collisionSoundMagnitude = magnitude; diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index ee613f5758..e92394af22 100755 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -881,12 +881,13 @@ void Avatar::updateCollisionWithEnvironment(float deltaTime) { const float ENVIRONMENT_SURFACE_ELASTICITY = 1.0f; const float ENVIRONMENT_SURFACE_DAMPING = 0.01; const float ENVIRONMENT_COLLISION_FREQUENCY = 0.05f; + const float VISIBLE_GROUND_COLLISION_VELOCITY = 0.2f; glm::vec3 penetration; if (Application::getInstance()->getEnvironment()->findCapsulePenetration( _position - up * (_pelvisFloatingHeight - radius), _position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) { float velocityTowardCollision = glm::dot(_velocity, glm::normalize(penetration)); - if (velocityTowardCollision > 0.2) { + if (velocityTowardCollision > VISIBLE_GROUND_COLLISION_VELOCITY) { Application::getInstance()->setGroundPlaneImpact(1.0f); } updateCollisionSound(penetration, deltaTime, ENVIRONMENT_COLLISION_FREQUENCY); From 98dd83dde81b3c53229b662083af7ad3bee2273c Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 17 Jul 2013 10:02:23 -0700 Subject: [PATCH 35/41] ahibfasubhdf --- interface/src/Application.cpp | 6 ++- interface/src/Application.h | 8 +++- interface/src/Audio.cpp | 70 ++++++++++++++++++++++++++++------- interface/src/Audio.h | 16 ++++++-- interface/src/Avatar.cpp | 50 +++++++++++++++++++++++-- interface/src/Avatar.h | 7 +++- interface/src/Head.cpp | 6 ++- interface/src/Util.cpp | 34 ++++++++++++----- interface/src/Util.h | 5 ++- 9 files changed, 165 insertions(+), 37 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0bd1826f6b..582bc4fcb4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -195,6 +195,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _isTouchPressed(false), _yawFromTouch(0.0f), _pitchFromTouch(0.0f), + _groundPlaneImpact(0.0f), _mousePressed(false), _mouseVoxelScale(1.0f / 1024.0f), _justEditedVoxel(false), @@ -2528,7 +2529,7 @@ void Application::displaySide(Camera& whichCamera) { //draw a grid ground plane.... if (_renderGroundPlaneOn->isChecked()) { - drawGroundPlaneGrid(EDGE_SIZE_GROUND_PLANE); + renderGroundPlaneGrid(EDGE_SIZE_GROUND_PLANE, _audio.getCollisionSoundMagnitude()); } // Draw voxels if (_renderVoxels->isChecked()) { @@ -2606,6 +2607,9 @@ void Application::displayOverlay() { glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); + // Display a single screen-size quad to + renderCollisionOverlay(_glWidget->width(), _glWidget->height(), _audio.getCollisionSoundMagnitude()); + #ifndef _WIN32 _audio.render(_glWidget->width(), _glWidget->height()); if (_oscilloscopeOn->isChecked()) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 37411aa9d5..9333808a27 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -87,6 +87,7 @@ public: void updateParticleSystem(float deltaTime); Avatar* getAvatar() { return &_myAvatar; } + Audio* getAudio() { return &_audio; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } VoxelSystem* getVoxels() { return &_voxels; } @@ -103,6 +104,9 @@ public: QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; } GeometryCache* getGeometryCache() { return &_geometryCache; } + void setGroundPlaneImpact(float groundPlaneImpact) { _groundPlaneImpact = groundPlaneImpact; } + + private slots: void timer(); @@ -208,7 +212,7 @@ private: void deleteVoxelUnderCursor(); void eyedropperVoxelUnderCursor(); void resetSensors(); - + void setMenuShortcutsEnabled(bool enabled); void updateCursor(); @@ -348,6 +352,8 @@ private: float _yawFromTouch; float _pitchFromTouch; + float _groundPlaneImpact; + VoxelDetail _mouseVoxelDragging; glm::vec3 _voxelThrust; bool _mousePressed; // true if mouse has been pressed (clear when finished) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 4c707de938..41090584f3 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -76,9 +76,12 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o NodeList* nodeList = NodeList::getInstance(); Application* interface = Application::getInstance(); Avatar* interfaceAvatar = interface->getAvatar(); - + + memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); + memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); + // Add Procedural effects to input samples - addProceduralSounds(inputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL); + addProceduralSounds(inputLeft, outputLeft, outputRight, BUFFER_LENGTH_SAMPLES_PER_CHANNEL); if (nodeList && inputLeft) { @@ -135,12 +138,8 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o + leadingBytes); } - } - - memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); - memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); - + AudioRingBuffer* ringBuffer = &_ringBuffer; // if there is anything in the ring buffer, decide what to do: @@ -251,11 +250,11 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o } } #ifndef TEST_AUDIO_LOOPBACK - outputLeft[s] = leftSample; - outputRight[s] = rightSample; + outputLeft[s] += leftSample; + outputRight[s] += rightSample; #else - outputLeft[s] = inputLeft[s]; - outputRight[s] = inputLeft[s]; + outputLeft[s] += inputLeft[s]; + outputRight[s] += inputLeft[s]; #endif } ringBuffer->setNextOutput(ringBuffer->getNextOutput() + PACKET_LENGTH_SAMPLES); @@ -333,7 +332,13 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : _lastYawMeasuredMaximum(0), _flangeIntensity(0.0f), _flangeRate(0.0f), - _flangeWeight(0.0f) + _flangeWeight(0.0f), + _collisionSoundMagnitude(0.0f), + _collisionSoundFrequency(0.0f), + _collisionSoundNoise(0.0f), + _collisionSoundDuration(0.0f), + _proceduralEffectSample(0), + _heartbeatMagnitude(0.0f) { outputPortAudioError(Pa_Initialize()); @@ -589,7 +594,10 @@ void Audio::lowPassFilter(int16_t* inputBuffer) { } // Take a pointer to the acquired microphone input samples and add procedural sounds -void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) { +void Audio::addProceduralSounds(int16_t* inputBuffer, + int16_t* outputLeft, + int16_t* outputRight, + int numSamples) { const float MAX_AUDIBLE_VELOCITY = 6.0; const float MIN_AUDIBLE_VELOCITY = 0.1; const int VOLUME_BASELINE = 400; @@ -598,14 +606,48 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) { float speed = glm::length(_lastVelocity); float volume = VOLUME_BASELINE * (1.f - speed / MAX_AUDIBLE_VELOCITY); + int sample; + + // + // Travelling noise + // // Add a noise-modulated sinewave with volume that tapers off with speed increasing if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { for (int i = 0; i < numSamples; i++) { - inputBuffer[i] += (int16_t)((sinf((float) i / SOUND_PITCH * speed) * randFloat()) * volume * speed); + inputBuffer[i] += (int16_t)(sinf((float) (_proceduralEffectSample + i) / SOUND_PITCH ) * volume * (1.f + randFloat() * 0.25f) * speed); } } + const float COLLISION_SOUND_CUTOFF_LEVEL = 0.01f; + const float COLLISION_SOUND_MAX_VOLUME = 1000.f; + const float UP_MAJOR_FIFTH = powf(1.5f, 4.0f); + const float DOWN_TWO_OCTAVES = 4.f; + const float DOWN_FOUR_OCTAVES = 16.f; + float t; + if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) { + for (int i = 0; i < numSamples; i++) { + t = (float) _proceduralEffectSample + (float) i; + sample = sinf(t * _collisionSoundFrequency) + + sinf(t * _collisionSoundFrequency / DOWN_TWO_OCTAVES) + + sinf(t * _collisionSoundFrequency / DOWN_FOUR_OCTAVES * UP_MAJOR_FIFTH); + sample *= _collisionSoundMagnitude * COLLISION_SOUND_MAX_VOLUME; + inputBuffer[i] += sample; + outputLeft[i] += sample; + outputRight[i] += sample; + _collisionSoundMagnitude *= _collisionSoundDuration; + } + } + _proceduralEffectSample += numSamples; } +// +// Starts a collision sound. magnitude is 0-1, with 1 the loudest possible sound. +// +void Audio::startCollisionSound(float magnitude, float frequency, float noise, float duration) { + _collisionSoundMagnitude = magnitude; + _collisionSoundFrequency = frequency; + _collisionSoundNoise = noise; + _collisionSoundDuration = duration; +} // ----------------------------------------------------------- // Accoustic ping (audio system round trip time determination) // ----------------------------------------------------------- diff --git a/interface/src/Audio.h b/interface/src/Audio.h index d11a14444a..37db447381 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -42,7 +42,11 @@ public: int getJitterBufferSamples() { return _jitterBufferSamples; }; void lowPassFilter(int16_t* inputBuffer); - + + void startCollisionSound(float magnitude, float frequency, float noise, float duration); + float getCollisionSoundMagnitude() { return _collisionSoundMagnitude; }; + + void ping(); // Call periodically to eventually perform round trip time analysis, @@ -80,7 +84,13 @@ private: float _flangeIntensity; float _flangeRate; float _flangeWeight; - + float _collisionSoundMagnitude; + float _collisionSoundFrequency; + float _collisionSoundNoise; + float _collisionSoundDuration; + int _proceduralEffectSample; + float _heartbeatMagnitude; + // Audio callback in class context. inline void performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight); @@ -92,7 +102,7 @@ private: inline void analyzePing(); // Add sounds that we want the user to not hear themselves, by adding on top of mic input signal - void addProceduralSounds(int16_t* inputBuffer, int numSamples); + void addProceduralSounds(int16_t* inputBuffer, int16_t* outputLeft, int16_t* outputRight, int numSamples); // Audio callback called by portaudio. Calls 'performIO'. diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 15ef875c75..e92394af22 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -546,8 +546,8 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { _position += _scale * _gravity * (GRAVITY_EARTH * deltaTime) * deltaTime; } - updateCollisionWithEnvironment(); - updateCollisionWithVoxels(); + updateCollisionWithEnvironment(deltaTime); + updateCollisionWithVoxels(deltaTime); updateAvatarCollisions(deltaTime); } @@ -874,29 +874,41 @@ void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float d } } -void Avatar::updateCollisionWithEnvironment() { +void Avatar::updateCollisionWithEnvironment(float deltaTime) { glm::vec3 up = getBodyUpDirection(); float radius = _height * 0.125f; const float ENVIRONMENT_SURFACE_ELASTICITY = 1.0f; const float ENVIRONMENT_SURFACE_DAMPING = 0.01; + const float ENVIRONMENT_COLLISION_FREQUENCY = 0.05f; + const float VISIBLE_GROUND_COLLISION_VELOCITY = 0.2f; glm::vec3 penetration; if (Application::getInstance()->getEnvironment()->findCapsulePenetration( _position - up * (_pelvisFloatingHeight - radius), _position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) { + float velocityTowardCollision = glm::dot(_velocity, glm::normalize(penetration)); + if (velocityTowardCollision > VISIBLE_GROUND_COLLISION_VELOCITY) { + Application::getInstance()->setGroundPlaneImpact(1.0f); + } + updateCollisionSound(penetration, deltaTime, ENVIRONMENT_COLLISION_FREQUENCY); + applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING); + + } } -void Avatar::updateCollisionWithVoxels() { +void Avatar::updateCollisionWithVoxels(float deltaTime) { float radius = _height * 0.125f; const float VOXEL_ELASTICITY = 1.4f; const float VOXEL_DAMPING = 0.0; + const float VOXEL_COLLISION_FREQUENCY = 0.5f; glm::vec3 penetration; if (Application::getInstance()->getVoxels()->findCapsulePenetration( _position - glm::vec3(0.0f, _pelvisFloatingHeight - radius, 0.0f), _position + glm::vec3(0.0f, _height - _pelvisFloatingHeight - radius, 0.0f), radius, penetration)) { + updateCollisionSound(penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); } } @@ -925,6 +937,36 @@ void Avatar::applyHardCollision(const glm::vec3& penetration, float elasticity, } } +void Avatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) { + // consider whether to have the collision make a sound + const float AUDIBLE_COLLISION_THRESHOLD = 0.02f; + const float COLLISION_LOUDNESS = 1.f; + const float DURATION_SCALING = 0.004f; + const float NOISE_SCALING = 0.1f; + glm::vec3 velocity = _velocity; + glm::vec3 gravity = getGravity(); + + if (glm::length(gravity) > EPSILON) { + // If gravity is on, remove the effect of gravity on velocity for this + // frame, so that we are not constantly colliding with the surface + velocity -= _scale * glm::length(gravity) * GRAVITY_EARTH * deltaTime * glm::normalize(gravity); + } + float velocityTowardCollision = glm::dot(velocity, glm::normalize(penetration)); + float velocityTangentToCollision = glm::length(velocity) - velocityTowardCollision; + + if (velocityTowardCollision > AUDIBLE_COLLISION_THRESHOLD) { + // Volume is proportional to collision velocity + // Base frequency is modified upward by the angle of the collision + // Noise is a function of the angle of collision + // Duration of the sound is a function of both base frequency and velocity of impact + Application::getInstance()->getAudio()->startCollisionSound( + fmin(COLLISION_LOUDNESS * velocityTowardCollision, 1.f), + frequency * (1.f + velocityTangentToCollision / velocityTowardCollision), + fmin(velocityTangentToCollision / velocityTowardCollision * NOISE_SCALING, 1.f), + 1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision); + } +} + void Avatar::updateAvatarCollisions(float deltaTime) { // Reset detector for nearest avatar diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index f41094173c..61207a2d8b 100755 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -162,6 +162,8 @@ public: glm::quat getOrientation () const; glm::quat getWorldAlignedOrientation() const; + glm::vec3 getGravity () const { return _gravity; } + glm::vec3 getUprightHeadPosition() const; AvatarVoxelSystem* getVoxels() { return &_voxels; } @@ -262,9 +264,10 @@ private: void updateAvatarCollisions(float deltaTime); void updateArmIKAndConstraints( float deltaTime ); void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime ); - void updateCollisionWithEnvironment(); - void updateCollisionWithVoxels(); + void updateCollisionWithEnvironment(float deltaTime); + void updateCollisionWithVoxels(float deltaTime); void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping); + void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime ); void checkForMouseRayTouching(); }; diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 131e0968cc..84ae9fffe9 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -227,7 +227,8 @@ void Head::simulate(float deltaTime, bool isMine) { const float CAMERA_FOLLOW_HEAD_RATE_MAX = 0.5f; const float CAMERA_FOLLOW_HEAD_RATE_RAMP_RATE = 1.05f; const float CAMERA_STOP_TOLERANCE_DEGREES = 0.1f; - const float CAMERA_START_TOLERANCE_DEGREES = 2.0f; + const float CAMERA_PITCH_START_TOLERANCE_DEGREES = 10.0f; + const float CAMERA_YAW_START_TOLERANCE_DEGREES = 3.0f; float cameraHeadAngleDifference = glm::length(glm::vec2(_pitch - _cameraPitch, _yaw - _cameraYaw)); if (_isCameraMoving) { _cameraFollowHeadRate = glm::clamp(_cameraFollowHeadRate * CAMERA_FOLLOW_HEAD_RATE_RAMP_RATE, @@ -240,7 +241,8 @@ void Head::simulate(float deltaTime, bool isMine) { _isCameraMoving = false; } } else { - if (cameraHeadAngleDifference > CAMERA_START_TOLERANCE_DEGREES) { + if ((fabs(_pitch - _cameraPitch) > CAMERA_PITCH_START_TOLERANCE_DEGREES) || + (fabs(_yaw - _cameraYaw) > CAMERA_YAW_START_TOLERANCE_DEGREES)) { _isCameraMoving = true; _cameraFollowHeadRate = CAMERA_FOLLOW_HEAD_RATE_START; } diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 20f33f924a..6aff15240e 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -325,22 +325,38 @@ void drawvec3(int x, int y, float scale, float rotate, float thick, int mono, gl glPopMatrix(); } +void renderCollisionOverlay(int width, int height, float magnitude) { + const float MIN_VISIBLE_COLLISION = 0.01f; + if (magnitude > MIN_VISIBLE_COLLISION) { + glColor4f(0, 0, 0, magnitude); + glBegin(GL_QUADS); + glVertex2f(0, 0); + glVertex2d(width, 0); + glVertex2d(width, height); + glVertex2d(0, height); + glEnd(); + } +} -void drawGroundPlaneGrid(float size) { - glColor3f(0.4f, 0.5f, 0.3f); +void renderGroundPlaneGrid(float size, float impact) { glLineWidth(2.0); - + glm::vec4 impactColor(1, 0, 0, 1); + glm::vec3 lineColor(0.4, 0.5, 0.3); + glm::vec4 surfaceColor(0.5, 0.5, 0.5, 0.4); + + glColor3fv(&lineColor.x); for (float x = 0; x <= size; x++) { glBegin(GL_LINES); - glVertex3f(x, 0.0f, 0); - glVertex3f(x, 0.0f, size); - glVertex3f(0, 0.0f, x); - glVertex3f(size, 0.0f, x); + glVertex3f(x, 0, 0); + glVertex3f(x, 0, size); + glVertex3f(0, 0, x); + glVertex3f(size, 0, x); glEnd(); } - // Draw a translucent quad just underneath the grid. - glColor4f(0.5, 0.5, 0.5, 0.4); + // Draw the floor, colored for recent impact + glm::vec4 floorColor = impact * impactColor + (1.f - impact) * surfaceColor; + glColor4fv(&floorColor.x); glBegin(GL_QUADS); glVertex3f(0, 0, 0); glVertex3f(size, 0, 0); diff --git a/interface/src/Util.h b/interface/src/Util.h index 37bd0595ec..8bc77a98ea 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -57,7 +57,10 @@ glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha); double diffclock(timeval *clock1,timeval *clock2); -void drawGroundPlaneGrid(float size); +void renderGroundPlaneGrid(float size, float impact); + +void renderCollisionOverlay(int width, int height, float magnitude); + void renderDiskShadow(glm::vec3 position, glm::vec3 upDirection, float radius, float darkness); From c33e4fe6f7860d70033c8e25587bbf931571dee5 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 17 Jul 2013 10:15:42 -0700 Subject: [PATCH 36/41] file mode reverts --- interface/src/Avatar.cpp | 0 interface/src/LeapManager.cpp | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 interface/src/Avatar.cpp mode change 100644 => 100755 interface/src/LeapManager.cpp diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp old mode 100644 new mode 100755 diff --git a/interface/src/LeapManager.cpp b/interface/src/LeapManager.cpp old mode 100644 new mode 100755 From a501659083610b29673c30172a09c229571566a2 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 17 Jul 2013 10:16:30 -0700 Subject: [PATCH 37/41] change mode of HandData to 644 --- libraries/avatars/src/HandData.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 libraries/avatars/src/HandData.cpp diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp old mode 100755 new mode 100644 From 2147a823986c8f7c89271a99b07ae667bc748da3 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 17 Jul 2013 10:16:45 -0700 Subject: [PATCH 38/41] change mode of HandData.cpp to 755 --- libraries/avatars/src/HandData.cpp | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 libraries/avatars/src/HandData.cpp diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp old mode 100644 new mode 100755 From 1aa06116c244f30e9f318bb4798f8ed43ede6ed5 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Wed, 17 Jul 2013 10:17:12 -0700 Subject: [PATCH 39/41] change mode of HandData.h to 755 --- libraries/avatars/src/HandData.h | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 libraries/avatars/src/HandData.h diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h old mode 100644 new mode 100755 From 9e9b379d66c357cfdd58d77c8a0ddaefb733ae8c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 17 Jul 2013 11:49:42 -0700 Subject: [PATCH 40/41] Fix crashing bug in voxel-server related to animation - added VoxelNodeDeleteHook mechanism that allows users of VoxelNode to register for delete notification call backs - added call back to VoxelNodeBag to remove and nodes from bags when the nodes get deleted. --- libraries/voxels/src/VoxelNode.cpp | 43 +++++++++++++++++++++ libraries/voxels/src/VoxelNode.h | 55 +++++++++++++++++---------- libraries/voxels/src/VoxelNodeBag.cpp | 14 +++++++ libraries/voxels/src/VoxelNodeBag.h | 9 ++--- voxel-server/src/main.cpp | 1 - 5 files changed, 95 insertions(+), 27 deletions(-) diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 76fae500dd..1268449ac6 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -54,6 +54,8 @@ void VoxelNode::init(unsigned char * octalCode) { } VoxelNode::~VoxelNode() { + notifyDeleteHooks(); + delete[] _octalCode; // delete all of this node's children @@ -387,3 +389,44 @@ float VoxelNode::distanceToPoint(const glm::vec3& point) const { float distance = sqrtf(glm::dot(temp, temp)); return distance; } + +VoxelNodeDeleteHook VoxelNode::_hooks[VOXEL_NODE_MAX_DELETE_HOOKS]; +void* VoxelNode::_hooksExtraData[VOXEL_NODE_MAX_DELETE_HOOKS]; +int VoxelNode::_hooksInUse = 0; + +int VoxelNode::addDeleteHook(VoxelNodeDeleteHook hook, void* extraData) { + // If first use, initialize the _hooks array + if (_hooksInUse == 0) { + memset(_hooks, 0, sizeof(_hooks)); + memset(_hooksExtraData, 0, sizeof(_hooksExtraData)); + } + // find first available slot + for (int i = 0; i < VOXEL_NODE_MAX_DELETE_HOOKS; i++) { + if (!_hooks[i]) { + _hooks[i] = hook; + _hooksExtraData[i] = extraData; + _hooksInUse++; + return i; + } + } + // if we got here, then we're out of room in our hooks, return error + return VOXEL_NODE_NO_MORE_HOOKS_AVAILABLE; +} + +void VoxelNode::removeDeleteHook(int hookID) { + if (_hooks[hookID]) { + _hooks[hookID] = NULL; + _hooksExtraData[hookID] = NULL; + _hooksInUse--; + } +} + +void VoxelNode::notifyDeleteHooks() { + if (_hooksInUse > 0) { + for (int i = 0; i < VOXEL_NODE_MAX_DELETE_HOOKS; i++) { + if (_hooks[i]) { + _hooks[i](this, _hooksExtraData[i]); + } + } + } +} diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 8e3b9cb5db..431592c2f9 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -15,33 +15,19 @@ #include "VoxelConstants.h" class VoxelTree; // forward delclaration +class VoxelNode; // forward delclaration typedef unsigned char colorPart; typedef unsigned char nodeColor[4]; typedef unsigned char rgbColor[3]; +// Callback function, for delete hook +typedef void (*VoxelNodeDeleteHook)(VoxelNode* node, void* extraData); +const int VOXEL_NODE_MAX_DELETE_HOOKS = 100; +const int VOXEL_NODE_NO_MORE_HOOKS_AVAILABLE = -1; + + class VoxelNode { -private: - nodeColor _trueColor; -#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color - nodeColor _currentColor; - bool _falseColored; -#endif - glBufferIndex _glBufferIndex; - bool _isDirty; - uint64_t _lastChanged; - bool _shouldRender; - bool _isStagedForDeletion; - AABox _box; - unsigned char* _octalCode; - VoxelNode* _children[8]; - int _childCount; - float _density; // If leaf: density = 1, if internal node: 0-1 density of voxels inside - - void calculateAABox(); - - void init(unsigned char * octalCode); - public: VoxelNode(); // root node constructor VoxelNode(unsigned char * octalCode); // regular constructor @@ -118,6 +104,33 @@ public: const nodeColor& getTrueColor() const { return _trueColor; }; const nodeColor& getColor() const { return _trueColor; }; #endif + + static int addDeleteHook(VoxelNodeDeleteHook hook, void* extraData = NULL); + static void removeDeleteHook(int hookID); +private: + void calculateAABox(); + void init(unsigned char * octalCode); + void notifyDeleteHooks(); + + nodeColor _trueColor; +#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color + nodeColor _currentColor; + bool _falseColored; +#endif + glBufferIndex _glBufferIndex; + bool _isDirty; + uint64_t _lastChanged; + bool _shouldRender; + bool _isStagedForDeletion; + AABox _box; + unsigned char* _octalCode; + VoxelNode* _children[8]; + int _childCount; + float _density; // If leaf: density = 1, if internal node: 0-1 density of voxels inside + + static VoxelNodeDeleteHook _hooks[VOXEL_NODE_MAX_DELETE_HOOKS]; + static void* _hooksExtraData[VOXEL_NODE_MAX_DELETE_HOOKS]; + static int _hooksInUse; }; #endif /* defined(__hifi__VoxelNode__) */ diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp index 20a469dec8..4f355116e4 100644 --- a/libraries/voxels/src/VoxelNodeBag.cpp +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -9,7 +9,15 @@ #include "VoxelNodeBag.h" #include +VoxelNodeBag::VoxelNodeBag() : + _bagElements(NULL), + _elementsInUse(0), + _sizeOfElementsArray(0) { + _hookID = VoxelNode::addDeleteHook(voxelNodeDeleteHook, (void*)this); +}; + VoxelNodeBag::~VoxelNodeBag() { + VoxelNode::removeDeleteHook(_hookID); deleteAll(); } @@ -118,3 +126,9 @@ void VoxelNodeBag::remove(VoxelNode* node) { } } +void VoxelNodeBag::voxelNodeDeleteHook(VoxelNode* node, void* extraData) { + VoxelNodeBag* theBag = (VoxelNodeBag*)extraData; + theBag->remove(node); // note: remove can safely handle nodes that aren't in it, so we don't need to check contains() +} + + diff --git a/libraries/voxels/src/VoxelNodeBag.h b/libraries/voxels/src/VoxelNodeBag.h index ee6e5045d0..27bd4e5b60 100644 --- a/libraries/voxels/src/VoxelNodeBag.h +++ b/libraries/voxels/src/VoxelNodeBag.h @@ -19,11 +19,7 @@ class VoxelNodeBag { public: - VoxelNodeBag() : - _bagElements(NULL), - _elementsInUse(0), - _sizeOfElementsArray(0) {}; - + VoxelNodeBag(); ~VoxelNodeBag(); void insert(VoxelNode* node); // put a node into the bag @@ -36,11 +32,14 @@ public: void deleteAll(); + static void voxelNodeDeleteHook(VoxelNode* node, void* extraData); + private: VoxelNode** _bagElements; int _elementsInUse; int _sizeOfElementsArray; + int _hookID; }; #endif /* defined(__hifi__VoxelNodeBag__) */ diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 5f5befafa6..f171d9b168 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -384,7 +384,6 @@ void attachVoxelNodeDataToNode(Node* newNode) { } int main(int argc, const char * argv[]) { - pthread_mutex_init(&::treeLock, NULL); qInstallMsgHandler(sharedMessageHandler); From 74eaf72d5301036714d1831ad13e5e6d64dc9d98 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 17 Jul 2013 11:52:50 -0700 Subject: [PATCH 41/41] removed bogus code that related to server crash --- libraries/voxels/src/VoxelTree.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 6ef9f293ee..91a31a6cd1 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1011,12 +1011,6 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, unsigned char* outputBuffer, // How many bytes have we written so far at this level; int bytesWritten = 0; - // These two cases should not ever happen... but if they do, we don't want to crash. - if (!node || !node->getOctalCode()) { - qDebug("VoxelTree::encodeTreeBitstream() BAD VoxelNode! Bailing!"); - return bytesWritten; - } - // 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 (params.viewFrustum && !node->isInView(*params.viewFrustum)) { return bytesWritten;