diff --git a/BUILD_OSX.md b/BUILD_OSX.md index 2598507c90..60fbb7cf92 100644 --- a/BUILD_OSX.md +++ b/BUILD_OSX.md @@ -12,6 +12,12 @@ We have a [homebrew formulas repository](https://github.com/highfidelity/homebre *Our [qt5 homebrew formula](https://raw.github.com/highfidelity/homebrew-formulas/master/qt5.rb) is for a patched version of Qt 5.4.x stable that removes wireless network scanning that can reduce real-time audio performance. We recommended you use this formula to install Qt.* +###Qt + +Assuming you've installed Qt 5 using the homebrew instructions above, you'll need to set QT_CMAKE_PREFIX_PATH so CMake can find your installation of Qt. For Qt 5.4.1 installed via homebrew, set QT_CMAKE_PREFIX_PATH as follows. + + export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.4.1/lib/cmake + ###Xcode If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles. @@ -19,4 +25,4 @@ If Xcode is your editor of choice, you can ask CMake to generate Xcode project f After running cmake, you will have the make files or Xcode project file necessary to build all of the components. Open the hifi.xcodeproj file, choose ALL_BUILD from the Product > Scheme menu (or target drop down), and click Run. -If the build completes successfully, you will have built targets for all components located in the `build/${target_name}/Debug` directories. \ No newline at end of file +If the build completes successfully, you will have built targets for all components located in the `build/${target_name}/Debug` directories. diff --git a/cmake/externals/polyvox/CMakeLists.txt b/cmake/externals/polyvox/CMakeLists.txt index 76302f9b4a..28aec6dab7 100644 --- a/cmake/externals/polyvox/CMakeLists.txt +++ b/cmake/externals/polyvox/CMakeLists.txt @@ -3,8 +3,8 @@ set(EXTERNAL_NAME polyvox) include(ExternalProject) ExternalProject_Add( ${EXTERNAL_NAME} - URL http://hifi-public.s3.amazonaws.com/dependencies/polyvox-master-2015-5-27.zip - URL_MD5 e3dd09a24df4db29ba370e3bea753388 + URL http://hifi-public.s3.amazonaws.com/dependencies/polyvox.zip + URL_MD5 904b840328278c9b36fa7a14be730c34 CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= BINARY_DIR ${EXTERNAL_PROJECT_PREFIX}/build LOG_DOWNLOAD 1 @@ -45,7 +45,7 @@ else () endif () -if (WIN32) +if (WIN32) set(${EXTERNAL_NAME_UPPER}_CORE_LIBRARY ${INSTALL_DIR}/PolyVoxCore/lib/PolyVoxCore.lib CACHE FILEPATH "polyvox core library") # set(${EXTERNAL_NAME_UPPER}_UTIL_LIBRARY ${INSTALL_DIR}/PolyVoxUtil/lib/PolyVoxUtil.lib CACHE FILEPATH "polyvox util library") elseif (APPLE) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 629a833be0..5cdaf1e225 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3495,7 +3495,9 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se { PerformanceTimer perfTimer("EngineRun"); render::RenderContext renderContext; - + + renderArgs->_shouldRender = LODManager::shouldRender; + renderContext.args = renderArgs; renderArgs->_viewFrustum = getDisplayViewFrustum(); _renderEngine->setRenderContext(renderContext); diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index cfc1c94995..79d49fd6f1 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -217,6 +217,47 @@ QString LODManager::getLODFeedbackText() { return result; } +bool LODManager::shouldRender(const RenderArgs* args, const AABox& bounds) { + const float maxScale = (float)TREE_SCALE; + const float octreeToMeshRatio = 4.0f; // must be this many times closer to a mesh than a voxel to see it. + float octreeSizeScale = args->_sizeScale; + int boundaryLevelAdjust = args->_boundaryLevelAdjust; + float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / octreeToMeshRatio; + float distanceToCamera = glm::length(bounds.calcCenter() - args->_viewFrustum->getPosition()); + float largestDimension = bounds.getLargestDimension(); + + static bool shouldRenderTableNeedsBuilding = true; + static QMap shouldRenderTable; + if (shouldRenderTableNeedsBuilding) { + + float SMALLEST_SCALE_IN_TABLE = 0.001f; // 1mm is plenty small + float scale = maxScale; + float factor = 1.0f; + + while (scale > SMALLEST_SCALE_IN_TABLE) { + scale /= 2.0f; + factor /= 2.0f; + shouldRenderTable[scale] = factor; + } + + shouldRenderTableNeedsBuilding = false; + } + + float closestScale = maxScale; + float visibleDistanceAtClosestScale = visibleDistanceAtMaxScale; + QMap::const_iterator lowerBound = shouldRenderTable.lowerBound(largestDimension); + if (lowerBound != shouldRenderTable.constEnd()) { + closestScale = lowerBound.key(); + visibleDistanceAtClosestScale = visibleDistanceAtMaxScale * lowerBound.value(); + } + + if (closestScale < largestDimension) { + visibleDistanceAtClosestScale *= 2.0f; + } + + return distanceToCamera <= visibleDistanceAtClosestScale; +}; + // TODO: This is essentially the same logic used to render octree cells, but since models are more detailed then octree cells // I've added a voxelToModelRatio that adjusts how much closer to a model you have to be to see it. bool LODManager::shouldRenderMesh(float largestDimension, float distanceToCamera) { diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 615bcec24d..98ababbda0 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -49,6 +49,8 @@ const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE; // do. But both are still culled using the same angular size logic. const float AVATAR_TO_ENTITY_RATIO = 2.0f; +class RenderArgs; +class AABox; class LODManager : public QObject, public Dependency { Q_OBJECT @@ -79,6 +81,7 @@ public: Q_INVOKABLE float getLODDecreaseFPS(); Q_INVOKABLE float getLODIncreaseFPS(); + static bool shouldRender(const RenderArgs* args, const AABox& bounds); bool shouldRenderMesh(float largestDimension, float distanceToCamera); void autoAdjustLOD(float currentFPS); diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 488fb3f1b1..d2af14f696 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -93,22 +93,24 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { if (_isFaceTrackerConnected) { _blendshapeCoefficients = faceTracker->getBlendshapeCoefficients(); - if (typeid(*faceTracker) == typeid(DdeFaceTracker) - && Menu::getInstance()->isOptionChecked(MenuOption::UseAudioForMouth)) { + if (typeid(*faceTracker) == typeid(DdeFaceTracker)) { - calculateMouthShapes(); + if (Menu::getInstance()->isOptionChecked(MenuOption::UseAudioForMouth)) { + calculateMouthShapes(); - const int JAW_OPEN_BLENDSHAPE = 21; - const int MMMM_BLENDSHAPE = 34; - const int FUNNEL_BLENDSHAPE = 40; - const int SMILE_LEFT_BLENDSHAPE = 28; - const int SMILE_RIGHT_BLENDSHAPE = 29; - _blendshapeCoefficients[JAW_OPEN_BLENDSHAPE] += _audioJawOpen; - _blendshapeCoefficients[SMILE_LEFT_BLENDSHAPE] += _mouth4; - _blendshapeCoefficients[SMILE_RIGHT_BLENDSHAPE] += _mouth4; - _blendshapeCoefficients[MMMM_BLENDSHAPE] += _mouth2; - _blendshapeCoefficients[FUNNEL_BLENDSHAPE] += _mouth3; + const int JAW_OPEN_BLENDSHAPE = 21; + const int MMMM_BLENDSHAPE = 34; + const int FUNNEL_BLENDSHAPE = 40; + const int SMILE_LEFT_BLENDSHAPE = 28; + const int SMILE_RIGHT_BLENDSHAPE = 29; + _blendshapeCoefficients[JAW_OPEN_BLENDSHAPE] += _audioJawOpen; + _blendshapeCoefficients[SMILE_LEFT_BLENDSHAPE] += _mouth4; + _blendshapeCoefficients[SMILE_RIGHT_BLENDSHAPE] += _mouth4; + _blendshapeCoefficients[MMMM_BLENDSHAPE] += _mouth2; + _blendshapeCoefficients[FUNNEL_BLENDSHAPE] += _mouth3; + } + applyEyelidOffset(getFinalOrientationInWorldFrame()); } } } @@ -203,6 +205,9 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { _mouth3, _mouth4, _blendshapeCoefficients); + + applyEyelidOffset(getOrientation()); + } else { _saccade = glm::vec3(); } @@ -218,7 +223,6 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { } } _eyePosition = calculateAverageEyePosition(); - } void Head::calculateMouthShapes() { @@ -249,6 +253,32 @@ void Head::calculateMouthShapes() { _mouth4 = glm::mix(_audioJawOpen, _mouth4, SMILE_PERIOD + randFloat() * SMILE_RANDOM_PERIOD); } +void Head::applyEyelidOffset(glm::quat headOrientation) { + // Adjusts the eyelid blendshape coefficients so that the eyelid follows the iris as the head pitches. + + glm::quat eyeRotation = rotationBetween(headOrientation * IDENTITY_FRONT, getCorrectedLookAtPosition() - _eyePosition); + eyeRotation = eyeRotation * glm::angleAxis(safeEulerAngles(headOrientation).y, IDENTITY_UP); // Rotation w.r.t. head + float eyePitch = safeEulerAngles(eyeRotation).x; + + const float EYE_PITCH_TO_COEFFICIENT = 1.6f; // Empirically determined + const float MAX_EYELID_OFFSET = 0.8f; // So that don't fully close eyes when looking way down + float eyelidOffset = glm::clamp(-eyePitch * EYE_PITCH_TO_COEFFICIENT, -1.0f, MAX_EYELID_OFFSET); + + for (int i = 0; i < 2; i++) { + const int LEFT_EYE = 8; + float eyeCoefficient = _blendshapeCoefficients[i] - _blendshapeCoefficients[LEFT_EYE + i]; // Raw value + eyeCoefficient = glm::clamp(eyelidOffset + eyeCoefficient * (1.0f - eyelidOffset), -1.0f, 1.0f); + if (eyeCoefficient > 0.0f) { + _blendshapeCoefficients[i] = eyeCoefficient; + _blendshapeCoefficients[LEFT_EYE + i] = 0.0f; + + } else { + _blendshapeCoefficients[i] = 0.0f; + _blendshapeCoefficients[LEFT_EYE + i] = -eyeCoefficient; + } + } +} + void Head::relaxLean(float deltaTime) { // restore rotation, lean to neutral positions const float LEAN_RELAXATION_PERIOD = 0.25f; // seconds diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index b8e6bf8c51..a208574c26 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -155,6 +155,7 @@ private: // private methods void renderLookatVectors(RenderArgs* renderArgs, glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition); void calculateMouthShapes(); + void applyEyelidOffset(glm::quat headOrientation); friend class FaceModel; }; diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index 40ca1ccbc9..19cc8d8412 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -17,4 +17,10 @@ find_package(PolyVox REQUIRED) target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${POLYVOX_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ${POLYVOX_LIBRARIES}) +# for changing the pitch of collision sounds +add_dependency_external_projects(soxr) +find_package(Soxr REQUIRED) +target_link_libraries(${TARGET_NAME} ${SOXR_LIBRARIES}) +target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SOXR_INCLUDE_DIRS}) + link_hifi_libraries(shared gpu script-engine render render-utils) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 949d73b10f..43f340119b 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include "EntityTreeRenderer.h" @@ -1203,7 +1205,30 @@ void EntityTreeRenderer::playEntityCollisionSound(const QUuid& myNodeID, EntityT options.stereo = sound->isStereo(); options.position = position; options.volume = volume; - AudioInjector* injector = new AudioInjector(sound.data(), options); + + // Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2) + const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f; + QByteArray samples = sound->getByteArray(); + soxr_io_spec_t spec = soxr_io_spec(SOXR_INT16_I, SOXR_INT16_I); + soxr_quality_spec_t qualitySpec = soxr_quality_spec(SOXR_MQ, 0); + const int channelCount = sound->isStereo() ? 2 : 1; + const float factor = log(1.0f + (entity->getMaximumAACube().getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2); + const int standardRate = AudioConstants::SAMPLE_RATE; + const int resampledRate = standardRate * factor; + const int nInputSamples = samples.size() / sizeof(int16_t); + const int nOutputSamples = nInputSamples * factor; + QByteArray resampled(nOutputSamples * sizeof(int16_t), '\0'); + const int16_t* receivedSamples = reinterpret_cast(samples.data()); + soxr_error_t soxError = soxr_oneshot(standardRate, resampledRate, channelCount, + receivedSamples, nInputSamples, NULL, + reinterpret_cast(resampled.data()), nOutputSamples, NULL, + &spec, &qualitySpec, 0); + if (soxError) { + qCDebug(entitiesrenderer) << "Unable to resample" << collisionSoundURL << "from" << nInputSamples << "@" << standardRate << "to" << nOutputSamples << "@" << resampledRate; + resampled = samples; + } + + AudioInjector* injector = new AudioInjector(resampled, options); injector->setLocalAudioInterface(_localAudioInterface); injector->triggerDeleteAfterFinish(); QThread* injectorThread = new QThread(); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index e6b5c89899..6977f6ff04 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -662,7 +662,7 @@ void EntityItem::adjustEditPacketForClockSkew(unsigned char* editPacketBuffer, s memcpy(&lastEditedInLocalTime, dataAt, sizeof(lastEditedInLocalTime)); quint64 lastEditedInServerTime = lastEditedInLocalTime + clockSkew; memcpy(dataAt, &lastEditedInServerTime, sizeof(lastEditedInServerTime)); - #if 1 //def WANT_DEBUG + #ifdef WANT_DEBUG qCDebug(entities, "EntityItem::adjustEditPacketForClockSkew()..."); qCDebug(entities) << " lastEditedInLocalTime: " << lastEditedInLocalTime; qCDebug(entities) << " clockSkew: " << clockSkew; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 4adc375a6a..1827515d37 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -310,10 +310,14 @@ void Model::init() { RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR), modelNormalMapVertex, modelNormalSpecularMapPixel); - + _renderPipelineLib.addRenderPipeline( - RenderKey(RenderKey::IS_TRANSLUCENT), - modelVertex, modelTranslucentPixel); + RenderKey(RenderKey::IS_TRANSLUCENT), + modelVertex, modelTranslucentPixel); + // FIXME Ignore lightmap for translucents meshpart + _renderPipelineLib.addRenderPipeline( + RenderKey(RenderKey::IS_TRANSLUCENT | RenderKey::HAS_LIGHTMAP), + modelVertex, modelTranslucentPixel); _renderPipelineLib.addRenderPipeline( RenderKey(RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT), diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 65353b5b99..f627bd27f6 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -55,44 +55,6 @@ void DrawSceneTask::run(const SceneContextPointer& sceneContext, const RenderCon Job::~Job() { } -/* -bool LODManager::shouldRenderMesh(float largestDimension, float distanceToCamera) { - const float octreeToMeshRatio = 4.0f; // must be this many times closer to a mesh than a voxel to see it. - float octreeSizeScale = getOctreeSizeScale(); - int boundaryLevelAdjust = getBoundaryLevelAdjust(); - float maxScale = (float)TREE_SCALE; - float visibleDistanceAtMaxScale = boundaryDistanceForRenderLevel(boundaryLevelAdjust, octreeSizeScale) / octreeToMeshRatio; - - if (_shouldRenderTableNeedsRebuilding) { - _shouldRenderTable.clear(); - - float SMALLEST_SCALE_IN_TABLE = 0.001f; // 1mm is plenty small - float scale = maxScale; - float visibleDistanceAtScale = visibleDistanceAtMaxScale; - - while (scale > SMALLEST_SCALE_IN_TABLE) { - scale /= 2.0f; - visibleDistanceAtScale /= 2.0f; - _shouldRenderTable[scale] = visibleDistanceAtScale; - } - _shouldRenderTableNeedsRebuilding = false; - } - - float closestScale = maxScale; - float visibleDistanceAtClosestScale = visibleDistanceAtMaxScale; - QMap::const_iterator lowerBound = _shouldRenderTable.lowerBound(largestDimension); - if (lowerBound != _shouldRenderTable.constEnd()) { - closestScale = lowerBound.key(); - visibleDistanceAtClosestScale = lowerBound.value(); - } - - if (closestScale < largestDimension) { - visibleDistanceAtClosestScale *= 2.0f; - } - - return (distanceToCamera <= visibleDistanceAtClosestScale); -}*/ - void render::cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDs& inItems, ItemIDs& outItems) { PerformanceTimer perfTimer("cullItems"); assert(renderContext->args); @@ -114,13 +76,10 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont // TODO: some entity types (like lights) might want to be rendered even // when they are outside of the view frustum... - - float distance = args->_viewFrustum->distanceToCamera(bound.calcCenter()); - bool outOfView = args->_viewFrustum->boxInFrustum(bound) == ViewFrustum::OUTSIDE; if (!outOfView) { - bool bigEnoughToRender = true; //_viewState->shouldRenderMesh(bound.getLargestDimension(), distance); - + bool bigEnoughToRender = (args->_shouldRender) ? args->_shouldRender(args, bound) : true; + if (bigEnoughToRender) { outItems.push_back(id); // One more Item to render args->_itemsRendered++; @@ -130,8 +89,7 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont } else { args->_itemsOutOfView++; } - } - + } } struct ItemBound { @@ -144,16 +102,16 @@ struct ItemBound { ItemBound(float centerDepth, float nearDepth, float farDepth, ItemID id) : _centerDepth(centerDepth), _nearDepth(nearDepth), _farDepth(farDepth), _id(id) {} }; -struct FrontToBackSort { - bool operator() (const ItemBound& left, const ItemBound& right) { - return (left._centerDepth < right._centerDepth); - } +struct FrontToBackSort { + bool operator() (const ItemBound& left, const ItemBound& right) { + return (left._centerDepth < right._centerDepth); + } }; -struct BackToFrontSort { - bool operator() (const ItemBound& left, const ItemBound& right) { - return (left._centerDepth > right._centerDepth); - } +struct BackToFrontSort { + bool operator() (const ItemBound& left, const ItemBound& right) { + return (left._centerDepth > right._centerDepth); + } }; void render::depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDs& inItems, ItemIDs& outItems) { diff --git a/libraries/shared/src/RenderArgs.h b/libraries/shared/src/RenderArgs.h index 08602dbacd..aefaca8a31 100644 --- a/libraries/shared/src/RenderArgs.h +++ b/libraries/shared/src/RenderArgs.h @@ -12,8 +12,11 @@ #ifndef hifi_RenderArgs_h #define hifi_RenderArgs_h -class ViewFrustum; +#include + +class AABox; class OctreeRenderer; +class ViewFrustum; namespace gpu { class Batch; class Context; @@ -21,6 +24,8 @@ class Context; class RenderArgs { public: + typedef std::function ShoudRenderFunctor; + enum RenderMode { DEFAULT_RENDER_MODE, SHADOW_RENDER_MODE, DIFFUSE_RENDER_MODE, NORMAL_RENDER_MODE, MIRROR_RENDER_MODE }; enum RenderSide { MONO, STEREO_LEFT, STEREO_RIGHT }; @@ -40,6 +45,7 @@ public: RenderSide renderSide = MONO, DebugFlags debugFlags = RENDER_DEBUG_NONE, gpu::Batch* batch = nullptr, + ShoudRenderFunctor shouldRender = nullptr, int elementsTouched = 0, int itemsRendered = 0, @@ -66,6 +72,7 @@ public: _renderSide(renderSide), _debugFlags(debugFlags), _batch(batch), + _shouldRender(shouldRender), _elementsTouched(elementsTouched), _itemsRendered(itemsRendered), @@ -94,6 +101,7 @@ public: RenderSide _renderSide; DebugFlags _debugFlags; gpu::Batch* _batch; + ShoudRenderFunctor _shouldRender; int _elementsTouched; int _itemsRendered;