diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 2f03f15da7..639e9f924b 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -96,7 +96,6 @@ Agent::Agent(ReceivedMessage& message) : DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -177,6 +176,8 @@ void Agent::run() { // Create ScriptEngines on threaded-assignment thread then move to main thread. DependencyManager::set(ScriptEngine::AGENT_SCRIPT)->moveToThread(qApp->thread()); + DependencyManager::set(); + // make sure we request our script once the agent connects to the domain auto nodeList = DependencyManager::get(); @@ -360,154 +361,178 @@ void Agent::scriptRequestFinished() { } void Agent::executeScript() { - _scriptEngine = scriptEngineFactory(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload); + // the following block is scoped so that any shared pointers we take here + // are cleared before we call setFinished at the end of the function + { + _scriptEngine = scriptEngineFactory(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload); - // setup an Avatar for the script to use - auto scriptedAvatar = DependencyManager::get(); + // setup an Avatar for the script to use + auto scriptedAvatar = DependencyManager::get(); - scriptedAvatar->setID(getSessionUUID()); + scriptedAvatar->setID(getSessionUUID()); - connect(_scriptEngine.data(), SIGNAL(update(float)), - scriptedAvatar.data(), SLOT(update(float)), Qt::ConnectionType::QueuedConnection); - scriptedAvatar->setForceFaceTrackerConnected(true); + connect(_scriptEngine.data(), SIGNAL(update(float)), + scriptedAvatar.data(), SLOT(update(float)), Qt::ConnectionType::QueuedConnection); + scriptedAvatar->setForceFaceTrackerConnected(true); - // call model URL setters with empty URLs so our avatar, if user, will have the default models - scriptedAvatar->setSkeletonModelURL(QUrl()); + // call model URL setters with empty URLs so our avatar, if user, will have the default models + scriptedAvatar->setSkeletonModelURL(QUrl()); - // force lazy initialization of the head data for the scripted avatar - // since it is referenced below by computeLoudness and getAudioLoudness - scriptedAvatar->getHeadOrientation(); + // force lazy initialization of the head data for the scripted avatar + // since it is referenced below by computeLoudness and getAudioLoudness + scriptedAvatar->getHeadOrientation(); - // give this AvatarData object to the script engine - _scriptEngine->registerGlobalObject("Avatar", scriptedAvatar.data()); + // give this AvatarData object to the script engine + _scriptEngine->registerGlobalObject("Avatar", scriptedAvatar.data()); - // give scripts access to the Users object - _scriptEngine->registerGlobalObject("Users", DependencyManager::get().data()); + // give scripts access to the Users object + _scriptEngine->registerGlobalObject("Users", DependencyManager::get().data()); - auto player = DependencyManager::get(); - connect(player.data(), &recording::Deck::playbackStateChanged, [=] { - if (player->isPlaying()) { - auto recordingInterface = DependencyManager::get(); - if (recordingInterface->getPlayFromCurrentLocation()) { - scriptedAvatar->setRecordingBasis(); + auto player = DependencyManager::get(); + connect(player.data(), &recording::Deck::playbackStateChanged, [&player, &scriptedAvatar] { + if (player->isPlaying()) { + auto recordingInterface = DependencyManager::get(); + if (recordingInterface->getPlayFromCurrentLocation()) { + scriptedAvatar->setRecordingBasis(); + } + + // these procedural movements are included in the recordings + scriptedAvatar->setHasProceduralEyeFaceMovement(false); + scriptedAvatar->setHasProceduralBlinkFaceMovement(false); + scriptedAvatar->setHasAudioEnabledFaceMovement(false); + } else { + scriptedAvatar->clearRecordingBasis(); + + // restore procedural blendshape movement + scriptedAvatar->setHasProceduralEyeFaceMovement(true); + scriptedAvatar->setHasProceduralBlinkFaceMovement(true); + scriptedAvatar->setHasAudioEnabledFaceMovement(true); } - } else { - scriptedAvatar->clearRecordingBasis(); - } - }); + }); - using namespace recording; - static const FrameType AVATAR_FRAME_TYPE = Frame::registerFrameType(AvatarData::FRAME_NAME); - Frame::registerFrameHandler(AVATAR_FRAME_TYPE, [scriptedAvatar](Frame::ConstPointer frame) { + using namespace recording; + static const FrameType AVATAR_FRAME_TYPE = Frame::registerFrameType(AvatarData::FRAME_NAME); + Frame::registerFrameHandler(AVATAR_FRAME_TYPE, [scriptedAvatar](Frame::ConstPointer frame) { + + auto recordingInterface = DependencyManager::get(); + bool useFrameSkeleton = recordingInterface->getPlayerUseSkeletonModel(); + + // FIXME - the ability to switch the avatar URL is not actually supported when playing back from a recording + if (!useFrameSkeleton) { + static std::once_flag warning; + std::call_once(warning, [] { + qWarning() << "Recording.setPlayerUseSkeletonModel(false) is not currently supported."; + }); + } + + AvatarData::fromFrame(frame->data, *scriptedAvatar); + }); + + using namespace recording; + static const FrameType AUDIO_FRAME_TYPE = Frame::registerFrameType(AudioConstants::getAudioFrameName()); + Frame::registerFrameHandler(AUDIO_FRAME_TYPE, [this, &scriptedAvatar](Frame::ConstPointer frame) { + static quint16 audioSequenceNumber{ 0 }; + + QByteArray audio(frame->data); + + if (_isNoiseGateEnabled) { + int16_t* samples = reinterpret_cast(audio.data()); + int numSamples = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL; + _audioGate.render(samples, samples, numSamples); + } + + computeLoudness(&audio, scriptedAvatar); + + // state machine to detect gate opening and closing + bool audioGateOpen = (scriptedAvatar->getAudioLoudness() != 0.0f); + bool openedInLastBlock = !_audioGateOpen && audioGateOpen; // the gate just opened + bool closedInLastBlock = _audioGateOpen && !audioGateOpen; // the gate just closed + _audioGateOpen = audioGateOpen; + Q_UNUSED(openedInLastBlock); + + // the codec must be flushed to silence before sending silent packets, + // so delay the transition to silent packets by one packet after becoming silent. + auto packetType = PacketType::MicrophoneAudioNoEcho; + if (!audioGateOpen && !closedInLastBlock) { + packetType = PacketType::SilentAudioFrame; + } + + Transform audioTransform; + auto headOrientation = scriptedAvatar->getHeadOrientation(); + audioTransform.setTranslation(scriptedAvatar->getWorldPosition()); + audioTransform.setRotation(headOrientation); + + QByteArray encodedBuffer; + if (_encoder) { + _encoder->encode(audio, encodedBuffer); + } else { + encodedBuffer = audio; + } + + AbstractAudioInterface::emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), audioSequenceNumber, false, + audioTransform, scriptedAvatar->getWorldPosition(), glm::vec3(0), + packetType, _selectedCodecName); + }); + + auto avatarHashMap = DependencyManager::set(); + _scriptEngine->registerGlobalObject("AvatarList", avatarHashMap.data()); + + // register ourselves to the script engine + _scriptEngine->registerGlobalObject("Agent", new AgentScriptingInterface(this)); + + _scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); + _scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get().data()); + + QScriptValue webSocketServerConstructorValue = _scriptEngine->newFunction(WebSocketServerClass::constructor); + _scriptEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue); + + auto entityScriptingInterface = DependencyManager::get(); + + _scriptEngine->registerGlobalObject("EntityViewer", &_entityViewer); + + _scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, + LocationScriptingInterface::locationSetter); auto recordingInterface = DependencyManager::get(); - bool useFrameSkeleton = recordingInterface->getPlayerUseSkeletonModel(); + _scriptEngine->registerGlobalObject("Recording", recordingInterface.data()); - // FIXME - the ability to switch the avatar URL is not actually supported when playing back from a recording - if (!useFrameSkeleton) { - static std::once_flag warning; - std::call_once(warning, [] { - qWarning() << "Recording.setPlayerUseSkeletonModel(false) is not currently supported."; - }); + entityScriptingInterface->init(); + + _entityViewer.init(); + + entityScriptingInterface->setEntityTree(_entityViewer.getTree()); + + DependencyManager::set(_entityViewer.getTree()); + + _avatarAudioTimer.start(); + + // Agents should run at 45hz + static const int AVATAR_DATA_HZ = 45; + static const int AVATAR_DATA_IN_MSECS = MSECS_PER_SECOND / AVATAR_DATA_HZ; + QTimer* avatarDataTimer = new QTimer(this); + connect(avatarDataTimer, &QTimer::timeout, this, &Agent::processAgentAvatar); + avatarDataTimer->setSingleShot(false); + avatarDataTimer->setInterval(AVATAR_DATA_IN_MSECS); + avatarDataTimer->setTimerType(Qt::PreciseTimer); + avatarDataTimer->start(); + + _scriptEngine->run(); + + Frame::clearFrameHandler(AUDIO_FRAME_TYPE); + Frame::clearFrameHandler(AVATAR_FRAME_TYPE); + + if (recordingInterface->isPlaying()) { + recordingInterface->stopPlaying(); } - AvatarData::fromFrame(frame->data, *scriptedAvatar); - }); - - using namespace recording; - static const FrameType AUDIO_FRAME_TYPE = Frame::registerFrameType(AudioConstants::getAudioFrameName()); - Frame::registerFrameHandler(AUDIO_FRAME_TYPE, [this, &scriptedAvatar](Frame::ConstPointer frame) { - static quint16 audioSequenceNumber{ 0 }; - - QByteArray audio(frame->data); - - if (_isNoiseGateEnabled) { - int16_t* samples = reinterpret_cast(audio.data()); - int numSamples = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL; - _audioGate.render(samples, samples, numSamples); + if (recordingInterface->isRecording()) { + recordingInterface->stopRecording(); } - computeLoudness(&audio, scriptedAvatar); + avatarDataTimer->stop(); + _avatarAudioTimer.stop(); + } - // state machine to detect gate opening and closing - bool audioGateOpen = (scriptedAvatar->getAudioLoudness() != 0.0f); - bool openedInLastBlock = !_audioGateOpen && audioGateOpen; // the gate just opened - bool closedInLastBlock = _audioGateOpen && !audioGateOpen; // the gate just closed - _audioGateOpen = audioGateOpen; - Q_UNUSED(openedInLastBlock); - - // the codec must be flushed to silence before sending silent packets, - // so delay the transition to silent packets by one packet after becoming silent. - auto packetType = PacketType::MicrophoneAudioNoEcho; - if (!audioGateOpen && !closedInLastBlock) { - packetType = PacketType::SilentAudioFrame; - } - - Transform audioTransform; - auto headOrientation = scriptedAvatar->getHeadOrientation(); - audioTransform.setTranslation(scriptedAvatar->getWorldPosition()); - audioTransform.setRotation(headOrientation); - - QByteArray encodedBuffer; - if (_encoder) { - _encoder->encode(audio, encodedBuffer); - } else { - encodedBuffer = audio; - } - - AbstractAudioInterface::emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), audioSequenceNumber, false, - audioTransform, scriptedAvatar->getWorldPosition(), glm::vec3(0), - packetType, _selectedCodecName); - }); - - auto avatarHashMap = DependencyManager::set(); - _scriptEngine->registerGlobalObject("AvatarList", avatarHashMap.data()); - - // register ourselves to the script engine - _scriptEngine->registerGlobalObject("Agent", new AgentScriptingInterface(this)); - - _scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); - _scriptEngine->registerGlobalObject("SoundCache", DependencyManager::get().data()); - - QScriptValue webSocketServerConstructorValue = _scriptEngine->newFunction(WebSocketServerClass::constructor); - _scriptEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue); - - auto entityScriptingInterface = DependencyManager::get(); - - _scriptEngine->registerGlobalObject("EntityViewer", &_entityViewer); - - _scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter, - LocationScriptingInterface::locationSetter); - - auto recordingInterface = DependencyManager::get(); - _scriptEngine->registerGlobalObject("Recording", recordingInterface.data()); - - entityScriptingInterface->init(); - - _entityViewer.init(); - - entityScriptingInterface->setEntityTree(_entityViewer.getTree()); - - DependencyManager::set(_entityViewer.getTree()); - - QMetaObject::invokeMethod(&_avatarAudioTimer, "start"); - - // Agents should run at 45hz - static const int AVATAR_DATA_HZ = 45; - static const int AVATAR_DATA_IN_MSECS = MSECS_PER_SECOND / AVATAR_DATA_HZ; - QTimer* avatarDataTimer = new QTimer(this); - connect(avatarDataTimer, &QTimer::timeout, this, &Agent::processAgentAvatar); - avatarDataTimer->setSingleShot(false); - avatarDataTimer->setInterval(AVATAR_DATA_IN_MSECS); - avatarDataTimer->setTimerType(Qt::PreciseTimer); - avatarDataTimer->start(); - - _scriptEngine->run(); - - Frame::clearFrameHandler(AUDIO_FRAME_TYPE); - Frame::clearFrameHandler(AVATAR_FRAME_TYPE); - - DependencyManager::destroy(); setFinished(true); } @@ -859,17 +884,25 @@ void Agent::aboutToFinish() { DependencyManager::destroy(); DependencyManager::destroy(); + DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); - DependencyManager::destroy(); + + // drop our shared pointer to the script engine, then ask ScriptEngines to shutdown scripting + // this ensures that the ScriptEngine goes down before ScriptEngines + _scriptEngine.clear(); + + { + DependencyManager::get()->shutdownScripting(); + } + + DependencyManager::destroy(); DependencyManager::destroy(); DependencyManager::destroy(); - QMetaObject::invokeMethod(&_avatarAudioTimer, "stop"); - // cleanup codec & encoder if (_codec && _encoder) { _codec->releaseEncoder(_encoder); diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index edbba20dc7..561afee296 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -654,6 +654,15 @@ void AvatarMixer::handleNodeIgnoreRequestPacket(QSharedPointer if (addToIgnore) { senderNode->addIgnoredNode(ignoredUUID); + + if (ignoredNode) { + // send a reliable kill packet to remove the sending avatar for the ignored avatar + auto killPacket = NLPacket::create(PacketType::KillAvatar, + NUM_BYTES_RFC4122_UUID + sizeof(KillAvatarReason), true); + killPacket->write(senderNode->getUUID().toRfc4122()); + killPacket->writePrimitive(KillAvatarReason::AvatarDisconnected); + nodeList->sendPacket(std::move(killPacket), *ignoredNode); + } } else { senderNode->removeIgnoredNode(ignoredUUID); } diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index 6f04cfa196..7d2b267a05 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -145,3 +145,15 @@ void ScriptableAvatar::update(float deltatime) { _clientTraitsHandler->sendChangedTraitsToMixer(); } + +void ScriptableAvatar::setHasProceduralBlinkFaceMovement(bool hasProceduralBlinkFaceMovement) { + _headData->setHasProceduralBlinkFaceMovement(hasProceduralBlinkFaceMovement); +} + +void ScriptableAvatar::setHasProceduralEyeFaceMovement(bool hasProceduralEyeFaceMovement) { + _headData->setHasProceduralEyeFaceMovement(hasProceduralEyeFaceMovement); +} + +void ScriptableAvatar::setHasAudioEnabledFaceMovement(bool hasAudioEnabledFaceMovement) { + _headData->setHasAudioEnabledFaceMovement(hasAudioEnabledFaceMovement); +} diff --git a/assignment-client/src/avatars/ScriptableAvatar.h b/assignment-client/src/avatars/ScriptableAvatar.h index 89f9369133..52beba72a1 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.h +++ b/assignment-client/src/avatars/ScriptableAvatar.h @@ -157,9 +157,16 @@ public: virtual QByteArray toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking = false) override; + void setHasProceduralBlinkFaceMovement(bool hasProceduralBlinkFaceMovement); + bool getHasProceduralBlinkFaceMovement() const override { return _headData->getHasProceduralBlinkFaceMovement(); } + void setHasProceduralEyeFaceMovement(bool hasProceduralEyeFaceMovement); + bool getHasProceduralEyeFaceMovement() const override { return _headData->getHasProceduralEyeFaceMovement(); } + void setHasAudioEnabledFaceMovement(bool hasAudioEnabledFaceMovement); + bool getHasAudioEnabledFaceMovement() const override { return _headData->getHasAudioEnabledFaceMovement(); } + private slots: void update(float deltatime); - + private: AnimationPointer _animation; AnimationDetails _animationDetails; diff --git a/cmake/macros/AutoScribeShader.cmake b/cmake/macros/AutoScribeShader.cmake index 1d1e5970d9..9c5ad70c78 100755 --- a/cmake/macros/AutoScribeShader.cmake +++ b/cmake/macros/AutoScribeShader.cmake @@ -9,7 +9,6 @@ # macro(AUTOSCRIBE_SHADER) - message(STATUS "Processing shader ${SHADER_FILE}") unset(SHADER_INCLUDE_FILES) # Grab include files foreach(includeFile ${ARGN}) diff --git a/cmake/macros/TargetJson.cmake b/cmake/macros/TargetJson.cmake index 057024cd0a..9262c2ce48 100644 --- a/cmake/macros/TargetJson.cmake +++ b/cmake/macros/TargetJson.cmake @@ -8,6 +8,5 @@ macro(TARGET_JSON) add_dependency_external_projects(json) find_package(JSON REQUIRED) - message("JSON_INCLUDE_DIRS ${JSON_INCLUDE_DIRS}") target_include_directories(${TARGET_NAME} PUBLIC ${JSON_INCLUDE_DIRS}) endmacro() \ No newline at end of file diff --git a/interface/resources/avatar/animations/idle.fbx b/interface/resources/avatar/animations/idle.fbx index 801237036f..88c79185a1 100644 Binary files a/interface/resources/avatar/animations/idle.fbx and b/interface/resources/avatar/animations/idle.fbx differ diff --git a/interface/resources/avatar/animations/jog_bwd.fbx b/interface/resources/avatar/animations/jog_bwd.fbx new file mode 100644 index 0000000000..479392d44c Binary files /dev/null and b/interface/resources/avatar/animations/jog_bwd.fbx differ diff --git a/interface/resources/avatar/animations/jump_in_air.fbx b/interface/resources/avatar/animations/jump_in_air.fbx index 72d8fc269c..2e6ad32f4f 100644 Binary files a/interface/resources/avatar/animations/jump_in_air.fbx and b/interface/resources/avatar/animations/jump_in_air.fbx differ diff --git a/interface/resources/avatar/animations/jump_land.fbx b/interface/resources/avatar/animations/jump_land.fbx index c0034bd091..f057c80085 100644 Binary files a/interface/resources/avatar/animations/jump_land.fbx and b/interface/resources/avatar/animations/jump_land.fbx differ diff --git a/interface/resources/avatar/animations/jump_running_launch_land.fbx b/interface/resources/avatar/animations/jump_running_launch_land.fbx new file mode 100644 index 0000000000..ad922d948e Binary files /dev/null and b/interface/resources/avatar/animations/jump_running_launch_land.fbx differ diff --git a/interface/resources/avatar/animations/jump_standing_apex.fbx b/interface/resources/avatar/animations/jump_standing_apex.fbx index 6385766b4a..53b79758aa 100644 Binary files a/interface/resources/avatar/animations/jump_standing_apex.fbx and b/interface/resources/avatar/animations/jump_standing_apex.fbx differ diff --git a/interface/resources/avatar/animations/jump_standing_land.fbx b/interface/resources/avatar/animations/jump_standing_land.fbx index fd97dae92a..aaeeb186fc 100644 Binary files a/interface/resources/avatar/animations/jump_standing_land.fbx and b/interface/resources/avatar/animations/jump_standing_land.fbx differ diff --git a/interface/resources/avatar/animations/jump_standing_land_settle.fbx b/interface/resources/avatar/animations/jump_standing_land_settle.fbx new file mode 100644 index 0000000000..1a11781e22 Binary files /dev/null and b/interface/resources/avatar/animations/jump_standing_land_settle.fbx differ diff --git a/interface/resources/avatar/animations/jump_standing_launch.fbx b/interface/resources/avatar/animations/jump_standing_launch.fbx new file mode 100644 index 0000000000..06479c8885 Binary files /dev/null and b/interface/resources/avatar/animations/jump_standing_launch.fbx differ diff --git a/interface/resources/avatar/animations/jump_takeoff.fbx b/interface/resources/avatar/animations/jump_takeoff.fbx index 4119b2417f..3976725676 100644 Binary files a/interface/resources/avatar/animations/jump_takeoff.fbx and b/interface/resources/avatar/animations/jump_takeoff.fbx differ diff --git a/interface/resources/avatar/animations/run_bwd.fbx b/interface/resources/avatar/animations/run_bwd.fbx new file mode 100644 index 0000000000..62f49c9729 Binary files /dev/null and b/interface/resources/avatar/animations/run_bwd.fbx differ diff --git a/interface/resources/avatar/animations/settle_to_idle.fbx b/interface/resources/avatar/animations/settle_to_idle.fbx index a5ccbfb490..fba4305e9a 100644 Binary files a/interface/resources/avatar/animations/settle_to_idle.fbx and b/interface/resources/avatar/animations/settle_to_idle.fbx differ diff --git a/interface/resources/avatar/animations/side_step_left.fbx b/interface/resources/avatar/animations/side_step_left.fbx index 4bface0c75..ef8cbe0a5c 100644 Binary files a/interface/resources/avatar/animations/side_step_left.fbx and b/interface/resources/avatar/animations/side_step_left.fbx differ diff --git a/interface/resources/avatar/animations/talk.fbx b/interface/resources/avatar/animations/talk.fbx index ba8f88589e..c29bf1e9bf 100644 Binary files a/interface/resources/avatar/animations/talk.fbx and b/interface/resources/avatar/animations/talk.fbx differ diff --git a/interface/resources/avatar/animations/walk_bwd_fast.fbx b/interface/resources/avatar/animations/walk_bwd_fast.fbx index f2007b03b1..f9a9ba0e26 100644 Binary files a/interface/resources/avatar/animations/walk_bwd_fast.fbx and b/interface/resources/avatar/animations/walk_bwd_fast.fbx differ diff --git a/interface/resources/avatar/animations/walk_fwd.fbx b/interface/resources/avatar/animations/walk_fwd.fbx index 7d8ab94494..8ad461f62e 100644 Binary files a/interface/resources/avatar/animations/walk_fwd.fbx and b/interface/resources/avatar/animations/walk_fwd.fbx differ diff --git a/interface/resources/avatar/animations/walk_fwd_fast.fbx b/interface/resources/avatar/animations/walk_fwd_fast.fbx index 1ba94a798f..db440fc9c4 100644 Binary files a/interface/resources/avatar/animations/walk_fwd_fast.fbx and b/interface/resources/avatar/animations/walk_fwd_fast.fbx differ diff --git a/interface/resources/avatar/animations/walk_short_bwd.fbx b/interface/resources/avatar/animations/walk_short_bwd.fbx index 89e940c888..d7e4bedf53 100644 Binary files a/interface/resources/avatar/animations/walk_short_bwd.fbx and b/interface/resources/avatar/animations/walk_short_bwd.fbx differ diff --git a/interface/resources/avatar/avatar-animation.json b/interface/resources/avatar/avatar-animation.json index 6ebbbf3000..50fe5019f9 100644 --- a/interface/resources/avatar/avatar-animation.json +++ b/interface/resources/avatar/avatar-animation.json @@ -585,149 +585,188 @@ "states": [ { "id": "idle", - "interpTarget": 0, - "interpDuration": 4, + "interpTarget": 20, + "interpDuration": 8, "interpType": "snapshotPrev", "transitions": [ - { "var": "isMovingForward", "state": "idleToWalkFwd" }, - { "var": "isMovingBackward", "state": "walkBwd" }, - { "var": "isMovingRight", "state": "strafeRight" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isMovingForward", "state": "WALKFWD" }, + { "var": "isMovingBackward", "state": "WALKBWD" }, + { "var": "isMovingRight", "state": "STRAFERIGHT" }, + { "var": "isMovingLeft", "state": "STRAFELEFT" }, { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isFlying", "state": "fly" }, { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isTakeoffRun", "state": "TAKEOFFRUN" }, { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" }, + { "var": "isInAirRun", "state": "INAIRRUN" }, { "var": "isMovingRightHmd", "state": "strafeRightHmd" }, { "var": "isMovingLeftHmd", "state": "strafeLeftHmd" } ] }, { "id": "idleToWalkFwd", - "interpTarget": 10, - "interpDuration": 4, - "interpType": "snapshotPrev", + "interpTarget": 12, + "interpDuration": 8, "transitions": [ - { "var": "idleToWalkFwdOnDone", "state": "walkFwd" }, + { "var": "idleToWalkFwdOnDone", "state": "WALKFWD" }, { "var": "isNotMoving", "state": "idle" }, - { "var": "isMovingBackward", "state": "walkBwd" }, - { "var": "isMovingRight", "state": "strafeRight" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isMovingBackward", "state": "WALKBWD" }, + { "var": "isMovingRight", "state": "STRAFERIGHT" }, + { "var": "isMovingLeft", "state": "STRAFELEFT" }, { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isFlying", "state": "fly" }, { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isTakeoffRun", "state": "TAKEOFFRUN" }, { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" }, + { "var": "isInAirRun", "state": "INAIRRUN" }, { "var": "isMovingRightHmd", "state": "strafeRightHmd" }, { "var": "isMovingLeftHmd", "state": "strafeLeftHmd" } ] }, { "id": "idleSettle", - "interpTarget": 10, - "interpDuration": 10, + "interpTarget": 15, + "interpDuration": 8, "interpType": "snapshotPrev", "transitions": [ {"var": "idleSettleOnDone", "state": "idle" }, - {"var": "isMovingForward", "state": "idleToWalkFwd" }, - { "var": "isMovingBackward", "state": "walkBwd" }, - { "var": "isMovingRight", "state": "strafeRight" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, + {"var": "isMovingForward", "state": "WALKFWD" }, + { "var": "isMovingBackward", "state": "WALKBWD" }, + { "var": "isMovingRight", "state": "STRAFERIGHT" }, + { "var": "isMovingLeft", "state": "STRAFELEFT" }, { "var": "isMovingRightHmd", "state": "strafeRightHmd" }, { "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }, { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isFlying", "state": "fly" }, { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isTakeoffRun", "state": "TAKEOFFRUN" }, { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" } + { "var": "isInAirRun", "state": "INAIRRUN" } ] }, { - "id": "walkFwd", - "interpTarget": 16, - "interpDuration": 6, + "id": "WALKFWD", + "interpTarget": 35, + "interpDuration": 10, "interpType": "snapshotPrev", "transitions": [ { "var": "isNotMoving", "state": "idleSettle" }, - { "var": "isMovingBackward", "state": "walkBwd" }, - { "var": "isMovingRight", "state": "strafeRight" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isMovingBackward", "state": "WALKBWD" }, + { "var": "isMovingRight", "state": "STRAFERIGHT" }, + { "var": "isMovingLeft", "state": "STRAFELEFT" }, { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isFlying", "state": "fly" }, { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isTakeoffRun", "state": "TAKEOFFRUN" }, { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" }, + { "var": "isInAirRun", "state": "INAIRRUN" }, { "var": "isMovingRightHmd", "state": "strafeRightHmd" }, { "var": "isMovingLeftHmd", "state": "strafeLeftHmd" } ] }, { - "id": "walkBwd", - "interpTarget": 8, - "interpDuration": 6, + "id": "WALKBWD", + "interpTarget": 35, + "interpDuration": 10, "interpType": "snapshotPrev", "transitions": [ { "var": "isNotMoving", "state": "idleSettle" }, - { "var": "isMovingForward", "state": "walkFwd" }, - { "var": "isMovingRight", "state": "strafeRight" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isMovingForward", "state": "WALKFWD" }, + { "var": "isMovingRight", "state": "STRAFERIGHT" }, + { "var": "isMovingLeft", "state": "STRAFELEFT" }, { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isFlying", "state": "fly" }, { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isTakeoffRun", "state": "TAKEOFFRUN" }, { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" }, + { "var": "isInAirRun", "state": "INAIRRUN" }, { "var": "isMovingRightHmd", "state": "strafeRightHmd" }, { "var": "isMovingLeftHmd", "state": "strafeLeftHmd" } ] }, { - "id": "strafeRight", - "interpTarget": 5, + "id": "STRAFERIGHT", + "interpTarget": 25, "interpDuration": 8, "interpType": "snapshotPrev", "transitions": [ { "var": "isNotMoving", "state": "idleSettle" }, - { "var": "isMovingForward", "state": "walkFwd" }, - { "var": "isMovingBackward", "state": "walkBwd" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isMovingForward", "state": "WALKFWD" }, + { "var": "isMovingBackward", "state": "WALKBWD" }, + { "var": "isMovingLeft", "state": "STRAFELEFT" }, { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isFlying", "state": "fly" }, { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isTakeoffRun", "state": "TAKEOFFRUN" }, { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" }, + { "var": "isInAirRun", "state": "INAIRRUN" }, { "var": "isMovingRightHmd", "state": "strafeRightHmd" }, { "var": "isMovingLeftHmd", "state": "strafeLeftHmd" } ] }, { - "id": "strafeLeft", - "interpTarget": 5, + "id": "STRAFELEFT", + "interpTarget": 25, "interpDuration": 8, "interpType": "snapshotPrev", "transitions": [ { "var": "isNotMoving", "state": "idleSettle" }, - { "var": "isMovingForward", "state": "walkFwd" }, - { "var": "isMovingBackward", "state": "walkBwd" }, - { "var": "isMovingRight", "state": "strafeRight" }, + { "var": "isMovingForward", "state": "WALKFWD" }, + { "var": "isMovingBackward", "state": "WALKBWD" }, + { "var": "isMovingRight", "state": "STRAFERIGHT" }, { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isFlying", "state": "fly" }, { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isTakeoffRun", "state": "TAKEOFFRUN" }, { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" }, + { "var": "isInAirRun", "state": "INAIRRUN" }, + { "var": "isMovingRightHmd", "state": "strafeRightHmd" }, + { "var": "isMovingLeftHmd", "state": "strafeLeftHmd" } + ] + }, + { + "id": "turnRight", + "interpTarget": 6, + "interpDuration": 8, + "transitions": [ + { "var": "isNotTurning", "state": "idle" }, + { "var": "isMovingForward", "state": "WALKFWD" }, + { "var": "isMovingBackward", "state": "WALKBWD" }, + { "var": "isMovingRight", "state": "STRAFERIGHT" }, + { "var": "isMovingLeft", "state": "STRAFELEFT" }, + { "var": "isTurningLeft", "state": "turnLeft" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "TAKEOFFRUN" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "INAIRRUN" }, + { "var": "isMovingRightHmd", "state": "strafeRightHmd" }, + { "var": "isMovingLeftHmd", "state": "strafeLeftHmd" } + ] + }, + { + "id": "turnLeft", + "interpTarget": 6, + "interpDuration": 8, + "transitions": [ + { "var": "isNotTurning", "state": "idle" }, + { "var": "isMovingForward", "state": "WALKFWD" }, + { "var": "isMovingBackward", "state": "WALKBWD" }, + { "var": "isMovingRight", "state": "STRAFERIGHT" }, + { "var": "isMovingLeft", "state": "STRAFELEFT" }, + { "var": "isTurningRight", "state": "turnRight" }, + { "var": "isFlying", "state": "fly" }, + { "var": "isTakeoffStand", "state": "takeoffStand" }, + { "var": "isTakeoffRun", "state": "TAKEOFFRUN" }, + { "var": "isInAirStand", "state": "inAirStand" }, + { "var": "isInAirRun", "state": "INAIRRUN" }, { "var": "isMovingRightHmd", "state": "strafeRightHmd" }, { "var": "isMovingLeftHmd", "state": "strafeLeftHmd" } ] @@ -739,18 +778,18 @@ "interpType": "snapshotPrev", "transitions": [ { "var": "isNotMoving", "state": "idleSettle" }, - { "var": "isMovingForward", "state": "walkFwd" }, - { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingForward", "state": "WALKFWD" }, + { "var": "isMovingBackward", "state": "WALKBWD" }, { "var": "isMovingLeftHmd", "state": "strafeLeftHmd" }, - { "var": "isMovingRight", "state": "strafeRight" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isMovingRight", "state": "STRAFERIGHT" }, + { "var": "isMovingLeft", "state": "STRAFELEFT" }, { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isFlying", "state": "fly" }, { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isTakeoffRun", "state": "TAKEOFFRUN" }, { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" } + { "var": "isInAirRun", "state": "INAIRRUN" } ] }, { @@ -760,60 +799,18 @@ "interpType": "snapshotPrev", "transitions": [ { "var": "isNotMoving", "state": "idleSettle" }, - { "var": "isMovingForward", "state": "walkFwd" }, - { "var": "isMovingBackward", "state": "walkBwd" }, + { "var": "isMovingForward", "state": "WALKFWD" }, + { "var": "isMovingBackward", "state": "WALKBWD" }, { "var": "isMovingRightHmd", "state": "strafeRightHmd" }, - { "var": "isMovingRight", "state": "strafeRight" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isMovingRight", "state": "STRAFERIGHT" }, + { "var": "isMovingLeft", "state": "STRAFELEFT" }, { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isFlying", "state": "fly" }, { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isTakeoffRun", "state": "TAKEOFFRUN" }, { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" } - ] - }, - { - "id": "turnRight", - "interpTarget": 6, - "interpDuration": 8, - "interpType": "snapshotPrev", - "transitions": [ - { "var": "isNotTurning", "state": "idle" }, - { "var": "isMovingForward", "state": "walkFwd" }, - { "var": "isMovingBackward", "state": "walkBwd" }, - { "var": "isMovingRight", "state": "strafeRight" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, - { "var": "isTurningLeft", "state": "turnLeft" }, - { "var": "isFlying", "state": "fly" }, - { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, - { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" }, - { "var": "isMovingRightHmd", "state": "strafeRightHmd" }, - { "var": "isMovingLeftHmd", "state": "strafeLeftHmd" } - ] - }, - { - "id": "turnLeft", - "interpTarget": 6, - "interpDuration": 8, - "interpType": "snapshotPrev", - "transitions": [ - { "var": "isNotTurning", "state": "idle" }, - { "var": "isMovingForward", "state": "walkFwd" }, - { "var": "isMovingBackward", "state": "walkBwd" }, - { "var": "isMovingRight", "state": "strafeRight" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, - { "var": "isTurningRight", "state": "turnRight" }, - { "var": "isFlying", "state": "fly" }, - { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, - { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" }, - { "var": "isMovingRightHmd", "state": "strafeRightHmd" }, - { "var": "isMovingLeftHmd", "state": "strafeLeftHmd" } + { "var": "isInAirRun", "state": "INAIRRUN" } ] }, { @@ -826,79 +823,79 @@ }, { "id": "takeoffStand", - "interpTarget": 0, - "interpDuration": 6, + "interpTarget": 2, + "interpDuration": 2, "transitions": [ { "var": "isNotTakeoff", "state": "inAirStand" } ] }, { - "id": "takeoffRun", - "interpTarget": 0, - "interpDuration": 6, + "id": "TAKEOFFRUN", + "interpTarget": 2, + "interpDuration": 2, "transitions": [ - { "var": "isNotTakeoff", "state": "inAirRun" } + { "var": "isNotTakeoff", "state": "INAIRRUN" } ] }, { "id": "inAirStand", - "interpTarget": 0, - "interpDuration": 6, + "interpTarget": 3, + "interpDuration": 3, "interpType": "snapshotPrev", "transitions": [ { "var": "isNotInAir", "state": "landStandImpact" } ] }, { - "id": "inAirRun", - "interpTarget": 0, - "interpDuration": 6, + "id": "INAIRRUN", + "interpTarget": 3, + "interpDuration": 3, "interpType": "snapshotPrev", "transitions": [ - { "var": "isNotInAir", "state": "landRun" } + { "var": "isNotInAir", "state": "WALKFWD" } ] }, { "id": "landStandImpact", - "interpTarget": 6, - "interpDuration": 4, + "interpTarget": 1, + "interpDuration": 1, "transitions": [ { "var": "isFlying", "state": "fly" }, { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isTakeoffRun", "state": "TAKEOFFRUN" }, { "var": "landStandImpactOnDone", "state": "landStand" } ] }, { "id": "landStand", - "interpTarget": 0, + "interpTarget": 1, "interpDuration": 1, "transitions": [ - { "var": "isMovingForward", "state": "idleToWalkFwd" }, - { "var": "isMovingBackward", "state": "walkBwd" }, - { "var": "isMovingRight", "state": "strafeRight" }, - { "var": "isMovingLeft", "state": "strafeLeft" }, + { "var": "isMovingForward", "state": "WALKFWD" }, + { "var": "isMovingBackward", "state": "WALKBWD" }, + { "var": "isMovingRight", "state": "STRAFERIGHT" }, + { "var": "isMovingLeft", "state": "STRAFELEFT" }, { "var": "isTurningRight", "state": "turnRight" }, { "var": "isTurningLeft", "state": "turnLeft" }, { "var": "isFlying", "state": "fly" }, { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, + { "var": "isTakeoffRun", "state": "TAKEOFFRUN" }, { "var": "isInAirStand", "state": "inAirStand" }, - { "var": "isInAirRun", "state": "inAirRun" }, + { "var": "isInAirRun", "state": "INAIRRUN" }, { "var": "landStandOnDone", "state": "idle" }, { "var": "isMovingRightHmd", "state": "strafeRightHmd" }, { "var": "isMovingLeftHmd", "state": "strafeLeftHmd" } ] }, { - "id": "landRun", - "interpTarget": 1, - "interpDuration": 7, + "id": "LANDRUN", + "interpTarget": 2, + "interpDuration": 2, "transitions": [ { "var": "isFlying", "state": "fly" }, { "var": "isTakeoffStand", "state": "takeoffStand" }, - { "var": "isTakeoffRun", "state": "takeoffRun" }, - { "var": "landRunOnDone", "state": "walkFwd" } + { "var": "isTakeoffRun", "state": "TAKEOFFRUN" }, + { "var": "landRunOnDone", "state": "WALKFWD" } ] } ] @@ -913,7 +910,7 @@ { "id": "idleStand", "interpTarget": 6, - "interpDuration": 6, + "interpDuration": 10, "transitions": [ { "var": "isTalking", "state": "idleTalk" } ] @@ -921,7 +918,7 @@ { "id": "idleTalk", "interpTarget": 6, - "interpDuration": 6, + "interpDuration": 10, "transitions": [ { "var": "notIsTalking", "state": "idleStand" } ] @@ -956,12 +953,12 @@ ] }, { - "id": "walkFwd", + "id": "WALKFWD", "type": "blendLinearMove", "data": { "alpha": 0.0, "desiredSpeed": 1.4, - "characteristicSpeeds": [0.5, 1.5, 2.5, 3.2, 4.5], + "characteristicSpeeds": [0.5, 1.8, 2.3, 3.2, 4.5], "alphaVar": "moveForwardAlpha", "desiredSpeedVar": "moveForwardSpeed" }, @@ -984,7 +981,7 @@ "data": { "url": "qrc:///avatar/animations/walk_fwd.fbx", "startFrame": 0.0, - "endFrame": 35.0, + "endFrame": 30.0, "timeScale": 1.0, "loopFlag": true }, @@ -1046,25 +1043,25 @@ "data": { "url": "qrc:///avatar/animations/settle_to_idle.fbx", "startFrame": 1.0, - "endFrame": 48.0, + "endFrame": 59.0, "timeScale": 1.0, "loopFlag": false }, "children": [] }, { - "id": "walkBwd", + "id": "WALKBWD", "type": "blendLinearMove", "data": { "alpha": 0.0, "desiredSpeed": 1.4, - "characteristicSpeeds": [0.6, 1.7], + "characteristicSpeeds": [0.6, 1.6, 2.3, 3.1], "alphaVar": "moveBackwardAlpha", "desiredSpeedVar": "moveBackwardSpeed" }, "children": [ { - "id": "walkBwdShort", + "id": "walkBwdShort_c", "type": "clip", "data": { "url": "qrc:///avatar/animations/walk_short_bwd.fbx", @@ -1076,7 +1073,7 @@ "children": [] }, { - "id": "walkBwdNormal", + "id": "walkBwdFast_c", "type": "clip", "data": { "url": "qrc:///avatar/animations/walk_bwd_fast.fbx", @@ -1086,6 +1083,30 @@ "loopFlag": true }, "children": [] + }, + { + "id": "jogBwd_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/jog_bwd.fbx", + "startFrame": 0.0, + "endFrame": 24.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] + }, + { + "id": "runBwd_c", + "type": "clip", + "data": { + "url": "qrc:///avatar/animations/run_bwd.fbx", + "startFrame": 0.0, + "endFrame": 16.0, + "timeScale": 1.0, + "loopFlag": true + }, + "children": [] } ] }, @@ -1115,18 +1136,18 @@ "children": [] }, { - "id": "strafeLeft", + "id": "STRAFELEFT", "type": "blendLinearMove", "data": { "alpha": 0.0, "desiredSpeed": 1.4, - "characteristicSpeeds": [0, 0.5, 1.5, 2.6, 3.0], + "characteristicSpeeds": [0.1, 0.5, 1.0, 2.6, 3.0], "alphaVar": "moveLateralAlpha", "desiredSpeedVar": "moveLateralSpeed" }, "children": [ { - "id": "strafeLeftShort_c", + "id": "strafeLeftShortStep_c", "type": "clip", "data": { "url": "qrc:///avatar/animations/side_step_short_left.fbx", @@ -1138,7 +1159,7 @@ "children": [] }, { - "id": "strafeLeft_c", + "id": "strafeLeftStep_c", "type": "clip", "data": { "url": "qrc:///avatar/animations/side_step_left.fbx", @@ -1150,19 +1171,19 @@ "children": [] }, { - "id": "strafeLeftAnim_c", + "id": "strafeLeftWalk_c", "type": "clip", "data": { "url": "qrc:///avatar/animations/walk_left.fbx", "startFrame": 0.0, - "endFrame": 33.0, + "endFrame": 35.0, "timeScale": 1.0, "loopFlag": true }, "children": [] }, { - "id": "strafeLeftFast_c", + "id": "strafeLeftWalkFast_c", "type": "clip", "data": { "url": "qrc:///avatar/animations/walk_left_fast.fbx", @@ -1188,17 +1209,17 @@ ] }, { - "id": "strafeRight", + "id": "STRAFERIGHT", "type": "blendLinearMove", "data": { "alpha": 0.0, "desiredSpeed": 1.4, - "characteristicSpeeds": [0, 0.5, 1.5, 2.6, 3.0], + "characteristicSpeeds": [0.1, 0.5, 1.0, 2.6, 3.0], "alphaVar": "moveLateralAlpha", "desiredSpeedVar": "moveLateralSpeed" }, "children": [ { - "id": "stepRightShort_c", + "id": "strafeRightShortStep_c", "type": "clip", "data": { "url": "qrc:///avatar/animations/side_step_short_left.fbx", @@ -1211,7 +1232,7 @@ "children": [] }, { - "id": "stepRight_c", + "id": "strafeRightStep_c", "type": "clip", "data": { "url": "qrc:///avatar/animations/side_step_left.fbx", @@ -1224,12 +1245,12 @@ "children": [] }, { - "id": "strafeRight_c", + "id": "strafeRightWalk_c", "type": "clip", "data": { "url": "qrc:///avatar/animations/walk_left.fbx", "startFrame": 0.0, - "endFrame": 33.0, + "endFrame": 35.0, "timeScale": 1.0, "loopFlag": true, "mirrorFlag": true @@ -1381,22 +1402,22 @@ "id": "takeoffStand", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_standing_takeoff.fbx", - "startFrame": 17.0, - "endFrame": 25.0, + "url": "qrc:///avatar/animations/jump_standing_launch.fbx", + "startFrame": 2.0, + "endFrame": 16.0, "timeScale": 1.0, "loopFlag": false }, "children": [] }, { - "id": "takeoffRun", + "id": "TAKEOFFRUN", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_takeoff.fbx", - "startFrame": 1.0, - "endFrame": 2.5, - "timeScale": 0.01, + "url": "qrc:///avatar/animations/jump_running_launch_land.fbx", + "startFrame": 4.0, + "endFrame": 15.0, + "timeScale": 1.0, "loopFlag": false }, "children": [] @@ -1416,7 +1437,7 @@ "url": "qrc:///avatar/animations/jump_standing_apex.fbx", "startFrame": 0.0, "endFrame": 0.0, - "timeScale": 0.0, + "timeScale": 1.0, "loopFlag": false }, "children": [] @@ -1448,7 +1469,7 @@ ] }, { - "id": "inAirRun", + "id": "INAIRRUN", "type": "blendLinear", "data": { "alpha": 0.0, @@ -1459,10 +1480,10 @@ "id": "inAirRunPreApex", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_in_air.fbx", - "startFrame": 0.0, - "endFrame": 0.0, - "timeScale": 0.0, + "url": "qrc:///avatar/animations/jump_running_launch_land.fbx", + "startFrame": 16.0, + "endFrame": 16.0, + "timeScale": 1.0, "loopFlag": false }, "children": [] @@ -1471,9 +1492,9 @@ "id": "inAirRunApex", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_in_air.fbx", - "startFrame": 6.0, - "endFrame": 6.0, + "url": "qrc:///avatar/animations/jump_running_launch_land.fbx", + "startFrame": 22.0, + "endFrame": 22.0, "timeScale": 1.0, "loopFlag": false }, @@ -1483,9 +1504,9 @@ "id": "inAirRunPostApex", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_in_air.fbx", - "startFrame": 11.0, - "endFrame": 11.0, + "url": "qrc:///avatar/animations/jump_running_launch_land.fbx", + "startFrame": 33.0, + "endFrame": 33.0, "timeScale": 1.0, "loopFlag": false }, @@ -1497,7 +1518,7 @@ "id": "landStandImpact", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_standing_land.fbx", + "url": "qrc:///avatar/animations/jump_standing_land_settle.fbx", "startFrame": 1.0, "endFrame": 6.0, "timeScale": 1.0, @@ -1509,22 +1530,22 @@ "id": "landStand", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_standing_land.fbx", + "url": "qrc:///avatar/animations/jump_standing_land_settle.fbx", "startFrame": 6.0, - "endFrame": 28.0, + "endFrame": 68.0, "timeScale": 1.0, "loopFlag": false }, "children": [] }, { - "id": "landRun", + "id": "LANDRUN", "type": "clip", "data": { - "url": "qrc:///avatar/animations/jump_land.fbx", - "startFrame": 1.0, - "endFrame": 6.0, - "timeScale": 0.65, + "url": "qrc:///avatar/animations/jump_running_launch_land.fbx", + "startFrame": 29.0, + "endFrame": 40.0, + "timeScale": 1.0, "loopFlag": false }, "children": [] diff --git a/interface/resources/qml/AnimStats.qml b/interface/resources/qml/AnimStats.qml new file mode 100644 index 0000000000..35ed3799a6 --- /dev/null +++ b/interface/resources/qml/AnimStats.qml @@ -0,0 +1,157 @@ +import Hifi 1.0 as Hifi +import QtQuick 2.3 +import '.' + +Item { + id: animStats + + anchors.leftMargin: 300 + objectName: "StatsItem" + property int modality: Qt.NonModal + implicitHeight: row.height + implicitWidth: row.width + + Component.onCompleted: { + animStats.parentChanged.connect(fill); + fill(); + } + Component.onDestruction: { + animStats.parentChanged.disconnect(fill); + } + + function fill() { + // This will cause a warning at shutdown, need to find another way to remove + // the warning other than filling the anchors to the parent + anchors.horizontalCenter = parent.horizontalCenter + } + + Hifi.AnimStats { + id: root + objectName: "AnimStats" + implicitHeight: row.height + implicitWidth: row.width + + anchors.horizontalCenter: parent.horizontalCenter + readonly property string bgColor: "#AA111111" + + Row { + id: row + spacing: 8 + + Rectangle { + width: firstCol.width + 8; + height: firstCol.height + 8; + color: root.bgColor; + + Column { + id: firstCol + spacing: 4; x: 4; y: 4; + + StatText { + text: "State Machines:---------------------------------------------------------------------------" + } + ListView { + width: firstCol.width + height: root.animStateMachines.length * 15 + visible: root.animStateMchines.length > 0; + model: root.animStateMachines + delegate: StatText { + text: { + return modelData; + } + } + } + } + } + + Rectangle { + width: secondCol.width + 8 + height: secondCol.height + 8 + color: root.bgColor; + + Column { + id: secondCol + spacing: 4; x: 4; y: 4; + + StatText { + text: "Anim Vars:--------------------------------------------------------------------------------" + } + + ListView { + width: secondCol.width + height: root.animVars.length * 15 + visible: root.animVars.length > 0; + model: root.animVars + delegate: StatText { + text: { + var actualText = modelData.split("|")[1]; + if (actualText) { + return actualText; + } else { + return modelData; + } + } + color: { + var grayScale = parseFloat(modelData.split("|")[0]); + return Qt.rgba(1.0, 1.0, 1.0, grayScale); + } + styleColor: { + var grayScale = parseFloat(modelData.split("|")[0]); + return Qt.rgba(0.0, 0.0, 0.0, grayScale); + } + } + } + } + } + + Rectangle { + width: thirdCol.width + 8 + height: thirdCol.height + 8 + color: root.bgColor; + + Column { + id: thirdCol + spacing: 4; x: 4; y: 4; + + StatText { + text: "Alpha Values:--------------------------------------------------------------------------" + } + + ListView { + width: thirdCol.width + height: root.animAlphaValues.length * 15 + visible: root.animAlphaValues.length > 0; + model: root.animAlphaValues + delegate: StatText { + text: { + var actualText = modelData.split("|")[1]; + if (actualText) { + return actualText; + } else { + return modelData; + } + } + color: { + var grayScale = parseFloat(modelData.split("|")[0]); + return Qt.rgba(1.0, 1.0, 1.0, grayScale); + } + styleColor: { + var grayScale = parseFloat(modelData.split("|")[0]); + return Qt.rgba(0.0, 0.0, 0.0, grayScale); + } + } + } + + } + } + } + + Connections { + target: root.parent + onWidthChanged: { + root.x = root.parent.width - root.width; + } + } + } + +} diff --git a/interface/resources/qml/InteractiveWindow.qml b/interface/resources/qml/InteractiveWindow.qml index 800026710d..e8ddbf823d 100644 --- a/interface/resources/qml/InteractiveWindow.qml +++ b/interface/resources/qml/InteractiveWindow.qml @@ -146,7 +146,8 @@ Windows.Window { Qt.WindowCloseButtonHint | Qt.WindowMaximizeButtonHint | Qt.WindowMinimizeButtonHint; - if ((flags & Desktop.ALWAYS_ON_TOP) === Desktop.ALWAYS_ON_TOP) { + // only use the always on top feature for non Windows OS + if (Qt.platform.os !== "windows" && (flags & Desktop.ALWAYS_ON_TOP)) { nativeWindowFlags |= Qt.WindowStaysOnTopHint; } nativeWindow.flags = nativeWindowFlags; diff --git a/interface/resources/qml/Stats.qml b/interface/resources/qml/Stats.qml index d5cfcff1e2..1a29ce87df 100644 --- a/interface/resources/qml/Stats.qml +++ b/interface/resources/qml/Stats.qml @@ -192,21 +192,6 @@ Item { StatText { text: "Yaw: " + root.yaw.toFixed(1) } - StatText { - visible: root.animStackNames.length > 0; - text: "Anim Stack Names:" - } - ListView { - width: geoCol.width - height: root.animStackNames.length * 15 - visible: root.animStackNames.length > 0; - model: root.animStackNames - delegate: StatText { - text: modelData.length > 30 - ? modelData.substring(0, 5) + "..." + modelData.substring(modelData.length - 22) - : modelData - } - } StatText { visible: root.expanded; text: "Avatar Mixer In: " + root.avatarMixerInKbps + " kbps, " + diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index abcceae295..dfa6555150 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -530,9 +530,7 @@ Item { maximumValue: 20.0 stepSize: 5 updateValueWhileDragging: true - Component.onCompleted: { - value = Users.getAvatarGain(uuid); - } + value: Users.getAvatarGain(uuid) onValueChanged: { updateGainFromQML(uuid, value, false); } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index cbab83ea28..35a0078d32 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -780,6 +780,12 @@ Rectangle { headerVisible: true; sortIndicatorColumn: settings.connectionsSortIndicatorColumn; sortIndicatorOrder: settings.connectionsSortIndicatorOrder; + onSortIndicatorColumnChanged: { + settings.connectionsSortIndicatorColumn = sortIndicatorColumn; + } + onSortIndicatorOrderChanged: { + settings.connectionsSortIndicatorOrder = sortIndicatorOrder; + } TableViewColumn { id: connectionsUserNameHeader; diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index cc1ba49984..f4a708567a 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -26,7 +26,7 @@ Rectangle { HifiConstants { id: hifi; } property var eventBridge; - property string title: "Audio Settings - " + AudioScriptingInterface.context; + property string title: "Audio Settings" signal sendToScript(var message); color: hifi.colors.baseGray; diff --git a/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml b/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml index 1ec7ea3e0e..afe06897df 100644 --- a/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml +++ b/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml @@ -18,6 +18,7 @@ import "../../windows" Rectangle { id: root objectName: "DCConectionTiming" + property string title: "Domain Connection Timing" signal sendToScript(var message); property bool isHMD: false @@ -33,7 +34,7 @@ Rectangle { Row { id: header anchors.top: parent.top - anchors.topMargin: hifi.dimensions.tabletMenuHeader + anchors.topMargin: hifi.dimensions.contentMargin.y anchors.leftMargin: 5 anchors.rightMargin: 5 anchors.left: parent.left diff --git a/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml b/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml index 7bce460283..24798af21a 100644 --- a/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml +++ b/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml @@ -18,6 +18,7 @@ import "../../windows" Rectangle { id: root objectName: "EntityStatistics" + property string title: "Entity Statistics" signal sendToScript(var message); property bool isHMD: false @@ -40,6 +41,7 @@ Rectangle { id: scrollView width: parent.width anchors.top: parent.top + anchors.topMargin: hifi.dimensions.contentMargin.y anchors.bottom: parent.bottom anchors.bottomMargin: hifi.dimensions.tabletMenuHeader contentWidth: column.implicitWidth @@ -48,10 +50,15 @@ Rectangle { Column { id: column - anchors.margins: 10 + anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - y: hifi.dimensions.tabletMenuHeader //-bgNavBar + anchors { + topMargin: 0 + leftMargin: 10 + rightMargin: 10 + bottomMargin: 0 + } spacing: 20 TabletEntityStatisticsItem { diff --git a/interface/resources/qml/hifi/tablet/ControllerSettings.qml b/interface/resources/qml/hifi/tablet/ControllerSettings.qml index 135c1379e2..6706830537 100644 --- a/interface/resources/qml/hifi/tablet/ControllerSettings.qml +++ b/interface/resources/qml/hifi/tablet/ControllerSettings.qml @@ -24,6 +24,8 @@ Item { height: parent.height width: parent.width + property string title: "Controls" + HifiConstants { id: hifi } TabBar { diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index c9d05aea51..802c00a97a 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -105,7 +105,6 @@ StackView { propagateComposedEvents: true onPressed: { parent.forceActiveFocus(); - addressBarDialog.keyboardEnabled = false; mouse.accepted = false; } } @@ -223,7 +222,6 @@ StackView { updateLocationText(text.length > 0); } onAccepted: { - addressBarDialog.keyboardEnabled = false; toggleOrGo(); } @@ -378,7 +376,7 @@ StackView { HifiControls.Keyboard { id: keyboard - raised: parent.keyboardEnabled + raised: parent.keyboardEnabled && parent.keyboardRaised numeric: parent.punctuationMode anchors { bottom: parent.bottom diff --git a/interface/resources/qml/hifi/tablet/TabletMenu.qml b/interface/resources/qml/hifi/tablet/TabletMenu.qml index 57c1163eb8..6540d53fca 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenu.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenu.qml @@ -23,6 +23,8 @@ FocusScope { property string subMenu: "" signal sendToScript(var message); + HifiConstants { id: hifi } + Rectangle { id: bgNavBar height: 90 @@ -45,24 +47,22 @@ FocusScope { anchors.topMargin: 0 anchors.top: parent.top - Image { + HiFiGlyphs { id: menuRootIcon - width: 40 - height: 40 - source: "../../../icons/tablet-icons/menu-i.svg" + text: breadcrumbText.text !== "Menu" ? hifi.glyphs.backward : "" + size: 72 anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left - anchors.leftMargin: 15 + width: breadcrumbText.text === "Menu" ? 32 : 50 + visible: breadcrumbText.text !== "Menu" MouseArea { anchors.fill: parent hoverEnabled: true onEntered: iconColorOverlay.color = "#1fc6a6"; onExited: iconColorOverlay.color = "#34a2c7"; - // navigate back to root level menu onClicked: { - buildMenu(); - breadcrumbText.text = "Menu"; + menuPopperUpper.closeLastMenu(); tabletRoot.playButtonClickSound(); } } @@ -79,23 +79,10 @@ FocusScope { id: breadcrumbText text: "Menu" size: 26 - color: "#34a2c7" + color: "#e3e3e3" anchors.verticalCenter: parent.verticalCenter anchors.left: menuRootIcon.right anchors.leftMargin: 15 - MouseArea { - anchors.fill: parent - hoverEnabled: true - onEntered: breadcrumbText.color = "#1fc6a6"; - onExited: breadcrumbText.color = "#34a2c7"; - // navigate back to parent level menu if there is one - onClicked: { - if (breadcrumbText.text !== "Menu") { - menuPopperUpper.closeLastMenu(); - } - tabletRoot.playButtonClickSound(); - } - } } } @@ -103,7 +90,6 @@ FocusScope { menuPopperUpper.closeLastMenu(); } - function setRootMenu(rootMenu, subMenu) { tabletMenu.subMenu = subMenu; tabletMenu.rootMenu = rootMenu; diff --git a/interface/resources/qml/hifi/tablet/TabletMenuStack.qml b/interface/resources/qml/hifi/tablet/TabletMenuStack.qml index 4d36a57793..fe636dafa5 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenuStack.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenuStack.qml @@ -1,5 +1,5 @@ // -// MessageDialog.qml +// TabletMenuStack.qml // // Created by Dante Ruiz on 13 Feb 2017 // Copyright 2016 High Fidelity, Inc. @@ -66,7 +66,7 @@ Item { function popSource() { console.log("trying to pop page"); - d.pop(); + closeLastMenu(); } function toModel(items, newMenu) { diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml b/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml index 05f45dc61e..5a0dc24dbc 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml @@ -41,7 +41,11 @@ Item { section.saveAll(); } - closeDialog(); + if (HMD.active) { + tablet.popFromStack(); + } else { + closeDialog(); + } } function restoreAll() { @@ -50,7 +54,11 @@ Item { section.restoreAll(); } - closeDialog(); + if (HMD.active) { + tablet.popFromStack(); + } else { + closeDialog(); + } } function closeDialog() { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2fe67ec5cb..e2cb9a1dfa 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -195,6 +195,7 @@ #include "ui/SnapshotAnimated.h" #include "ui/StandAloneJSConsole.h" #include "ui/Stats.h" +#include "ui/AnimStats.h" #include "ui/UpdateDialog.h" #include "ui/overlays/Overlays.h" #include "ui/DomainConnectionModel.h" @@ -2663,6 +2664,10 @@ Application::~Application() { void Application::initializeGL() { qCDebug(interfaceapp) << "Created Display Window."; +#ifdef DISABLE_QML + setAttribute(Qt::AA_DontCheckOpenGLContextThreadAffinity); +#endif + // initialize glut for shape drawing; Qt apparently initializes it on OS X if (_isGLInitialized) { return; @@ -3081,8 +3086,10 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { void Application::onDesktopRootItemCreated(QQuickItem* rootItem) { Stats::show(); + AnimStats::show(); auto surfaceContext = DependencyManager::get()->getSurfaceContext(); surfaceContext->setContextProperty("Stats", Stats::getInstance()); + surfaceContext->setContextProperty("AnimStats", AnimStats::getInstance()); #if !defined(Q_OS_ANDROID) auto offscreenUi = DependencyManager::get(); @@ -4618,6 +4625,7 @@ void Application::idle() { checkChangeCursor(); Stats::getInstance()->updateStats(); + AnimStats::getInstance()->updateStats(); // Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing // details if we're in ExtraDebugging mode. However, the ::update() and its subcomponents will show their timing @@ -5855,9 +5863,7 @@ void Application::update(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::update()"); -#if !defined(Q_OS_ANDROID) updateLOD(deltaTime); -#endif // TODO: break these out into distinct perfTimers when they prove interesting { @@ -6870,6 +6876,9 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) { shortName = shortName.mid(startIndex, endIndex - startIndex); } +#ifdef DISABLE_QML + DependencyManager::get()->loadScript(scriptFilenameOrURL); +#else QString message = "Would you like to run this script:\n" + shortName; ModalDialogListener* dlg = OffscreenUi::asyncQuestion(getWindow(), "Run Script", message, QMessageBox::Yes | QMessageBox::No); @@ -6884,7 +6893,7 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) { } QObject::disconnect(dlg, &ModalDialogListener::response, this, nullptr); }); - +#endif return true; } diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 1452c714e9..6206fd3539 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -19,8 +19,11 @@ #include #include - +#ifdef Q_OS_ANDROID +const float LOD_DEFAULT_QUALITY_LEVEL = 0.75f; // default quality level setting is High (lower framerate) +#else const float LOD_DEFAULT_QUALITY_LEVEL = 0.5f; // default quality level setting is Mid +#endif const float LOD_MAX_LIKELY_DESKTOP_FPS = 60.0f; // this is essentially, V-synch fps const float LOD_MAX_LIKELY_HMD_FPS = 90.0f; // this is essentially, V-synch fps const float LOD_OFFSET_FPS = 5.0f; // offset of FPS to add for computing the target framerate diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index a6ba983ab5..7a310e675f 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -255,7 +255,7 @@ Menu::Menu() { connect(action, &QAction::triggered, [] { auto tablet = DependencyManager::get()->getTablet("com.highfidelity.interface.tablet.system"); auto hmd = DependencyManager::get(); - tablet->loadQMLSource("hifi/tablet/ControllerSettings.qml"); + tablet->pushOntoStack("hifi/tablet/ControllerSettings.qml"); if (!hmd->getShouldShowTablet()) { hmd->toggleShouldShowTablet(); @@ -737,6 +737,7 @@ Menu::Menu() { // Developer > Stats addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::Stats); + addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::AnimStats); // Settings > Enable Speech Control API #if defined(Q_OS_MAC) || defined(Q_OS_WIN) diff --git a/interface/src/Menu.h b/interface/src/Menu.h index c4ea3734f5..031ee2561c 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -197,6 +197,7 @@ namespace MenuOption { const QString SMIEyeTracking = "SMI Eye Tracking"; const QString SparseTextureManagement = "Enable Sparse Texture Management"; const QString Stats = "Show Statistics"; + const QString AnimStats = "Show Animation Stats"; const QString StopAllScripts = "Stop All Scripts"; const QString SuppressShortTimings = "Suppress Timings Less than 10ms"; const QString ThirdPerson = "Third Person"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e4503b4e78..c8af792d8f 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -516,6 +516,10 @@ void MyAvatar::update(float deltaTime) { head->relax(deltaTime); updateFromTrackers(deltaTime); + if (getIsInWalkingState() && glm::length(getControllerPoseInAvatarFrame(controller::Action::HEAD).getVelocity()) < DEFAULT_AVATAR_WALK_SPEED_THRESHOLD) { + setIsInWalkingState(false); + } + // Get audio loudness data from audio input device // Also get the AudioClient so we can update the avatar bounding box data // on the AudioClient side. @@ -3678,10 +3682,10 @@ static bool headAngularVelocityBelowThreshold(const controller::Pose& head) { return isBelowThreshold; } -static bool isWithinThresholdHeightMode(const controller::Pose& head,const float& newMode) { +static bool isWithinThresholdHeightMode(const controller::Pose& head, const float& newMode, const float& scale) { bool isWithinThreshold = true; if (head.isValid()) { - isWithinThreshold = (head.getTranslation().y - newMode) > DEFAULT_AVATAR_MODE_HEIGHT_STEPPING_THRESHOLD; + isWithinThreshold = (head.getTranslation().y - newMode) > (DEFAULT_AVATAR_MODE_HEIGHT_STEPPING_THRESHOLD * scale); } return isWithinThreshold; } @@ -3802,6 +3806,10 @@ float MyAvatar::getUserEyeHeight() const { return userHeight - userHeight * ratio; } +bool MyAvatar::getIsInWalkingState() const { + return _isInWalkingState; +} + float MyAvatar::getWalkSpeed() const { return _walkSpeed.get() * _walkSpeedScalar; } @@ -3818,6 +3826,10 @@ void MyAvatar::setSprintMode(bool sprint) { _walkSpeedScalar = sprint ? _sprintSpeed.get() : AVATAR_WALK_SPEED_SCALAR; } +void MyAvatar::setIsInWalkingState(bool isWalking) { + _isInWalkingState = isWalking; +} + void MyAvatar::setWalkSpeed(float value) { _walkSpeed.set(value); } @@ -3912,7 +3924,6 @@ void MyAvatar::lateUpdatePalms() { Avatar::updatePalms(); } - static const float FOLLOW_TIME = 0.5f; MyAvatar::FollowHelper::FollowHelper() { @@ -4004,24 +4015,36 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons controller::Pose currentRightHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND); bool stepDetected = false; - if (!withinBaseOfSupport(currentHeadPose) && + float myScale = myAvatar.getAvatarScale(); + + if (myAvatar.getIsInWalkingState()) { + stepDetected = true; + } else { + if (!withinBaseOfSupport(currentHeadPose) && headAngularVelocityBelowThreshold(currentHeadPose) && - isWithinThresholdHeightMode(currentHeadPose, myAvatar.getCurrentStandingHeight()) && + isWithinThresholdHeightMode(currentHeadPose, myAvatar.getCurrentStandingHeight(), myScale) && handDirectionMatchesHeadDirection(currentLeftHandPose, currentRightHandPose, currentHeadPose) && handAngularVelocityBelowThreshold(currentLeftHandPose, currentRightHandPose) && headVelocityGreaterThanThreshold(currentHeadPose) && isHeadLevel(currentHeadPose, myAvatar.getAverageHeadRotation())) { - // a step is detected - stepDetected = true; - } else { - glm::vec3 defaultHipsPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); - glm::vec3 defaultHeadPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head")); - glm::vec3 currentHeadPosition = currentHeadPose.getTranslation(); - float anatomicalHeadToHipsDistance = glm::length(defaultHeadPosition - defaultHipsPosition); - if (!isActive(Horizontal) && - (glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance)))) { - myAvatar.setResetMode(true); + // a step is detected stepDetected = true; + if (glm::length(currentHeadPose.velocity) > DEFAULT_AVATAR_WALK_SPEED_THRESHOLD) { + myAvatar.setIsInWalkingState(true); + } + } else { + glm::vec3 defaultHipsPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); + glm::vec3 defaultHeadPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head")); + glm::vec3 currentHeadPosition = currentHeadPose.getTranslation(); + float anatomicalHeadToHipsDistance = glm::length(defaultHeadPosition - defaultHipsPosition); + if (!isActive(Horizontal) && + (glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance)))) { + myAvatar.setResetMode(true); + stepDetected = true; + if (glm::length(currentHeadPose.velocity) > DEFAULT_AVATAR_WALK_SPEED_THRESHOLD) { + myAvatar.setIsInWalkingState(true); + } + } } } return stepDetected; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 06267b3819..5008190c33 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1086,6 +1086,8 @@ public: const QUuid& getSelfID() const { return AVATAR_SELF_ID; } + void setIsInWalkingState(bool isWalking); + bool getIsInWalkingState() const; void setWalkSpeed(float value); float getWalkSpeed() const; void setWalkBackwardSpeed(float value); @@ -1788,6 +1790,7 @@ private: ThreadSafeValueCache _walkBackwardSpeed { DEFAULT_AVATAR_MAX_WALKING_BACKWARD_SPEED }; ThreadSafeValueCache _sprintSpeed { AVATAR_SPRINT_SPEED_SCALAR }; float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; + bool _isInWalkingState { false }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; diff --git a/interface/src/avatar/MyAvatarHeadTransformNode.cpp b/interface/src/avatar/MyAvatarHeadTransformNode.cpp index 9c202ba94a..1e83a17dd3 100644 --- a/interface/src/avatar/MyAvatarHeadTransformNode.cpp +++ b/interface/src/avatar/MyAvatarHeadTransformNode.cpp @@ -16,8 +16,9 @@ Transform MyAvatarHeadTransformNode::getTransform() { auto myAvatar = DependencyManager::get()->getMyAvatar(); glm::vec3 pos = myAvatar->getHeadPosition(); + glm::vec3 scale = glm::vec3(myAvatar->scaleForChildren()); glm::quat headOri = myAvatar->getHeadOrientation(); glm::quat ori = headOri * glm::angleAxis(-PI / 2.0f, Vectors::RIGHT); - return Transform(ori, glm::vec3(1.0f), pos); + return Transform(ori, scale, pos); } \ No newline at end of file diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 77d1a87195..3084542472 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -46,7 +46,7 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) { } glm::mat4 hipsMat; - if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying) { + if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState())) { // then we use center of gravity model hipsMat = myAvatar->deriveBodyUsingCgModel(); } else { diff --git a/interface/src/octree/SafeLanding.cpp b/interface/src/octree/SafeLanding.cpp index 60b660f66a..cfb0a2c753 100644 --- a/interface/src/octree/SafeLanding.cpp +++ b/interface/src/octree/SafeLanding.cpp @@ -75,7 +75,6 @@ void SafeLanding::addTrackedEntity(const EntityItemID& entityID) { if (hasAABox && downloadedCollisionTypes.count(modelEntity->getShapeType()) != 0) { // Only track entities with downloaded collision bodies. _trackedEntities.emplace(entityID, entity); - qCDebug(interfaceapp) << "Safe Landing: Tracking entity " << entity->getItemName(); } } } @@ -110,7 +109,6 @@ bool SafeLanding::isLoadSequenceComplete() { _initialEnd = INVALID_SEQUENCE; _entityTree = nullptr; EntityTreeRenderer::setEntityLoadingPriorityFunction(StandardPriority); - qCDebug(interfaceapp) << "Safe Landing: load sequence complete"; } return !_trackingEntities; diff --git a/interface/src/raypick/CollisionPick.cpp b/interface/src/raypick/CollisionPick.cpp index 7d0276875b..c21ee69b74 100644 --- a/interface/src/raypick/CollisionPick.cpp +++ b/interface/src/raypick/CollisionPick.cpp @@ -86,23 +86,23 @@ bool CollisionPick::isLoaded() const { return !_mathPick.shouldComputeShapeInfo() || (_cachedResource && _cachedResource->isLoaded()); } -bool CollisionPick::getShapeInfoReady() { +bool CollisionPick::getShapeInfoReady(const CollisionRegion& pick) { if (_mathPick.shouldComputeShapeInfo()) { if (_cachedResource && _cachedResource->isLoaded()) { - computeShapeInfo(_mathPick, *_mathPick.shapeInfo, _cachedResource); + computeShapeInfo(pick, *_mathPick.shapeInfo, _cachedResource); _mathPick.loaded = true; } else { _mathPick.loaded = false; } } else { - computeShapeInfoDimensionsOnly(_mathPick, *_mathPick.shapeInfo, _cachedResource); + computeShapeInfoDimensionsOnly(pick, *_mathPick.shapeInfo, _cachedResource); _mathPick.loaded = true; } return _mathPick.loaded; } -void CollisionPick::computeShapeInfoDimensionsOnly(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) { +void CollisionPick::computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) { ShapeType type = shapeInfo.getType(); glm::vec3 dimensions = pick.transform.getScale(); QString modelURL = (resource ? resource->getURL().toString() : ""); @@ -115,7 +115,7 @@ void CollisionPick::computeShapeInfoDimensionsOnly(CollisionRegion& pick, ShapeI } } -void CollisionPick::computeShapeInfo(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) { +void CollisionPick::computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource) { // This code was copied and modified from RenderableModelEntityItem::computeShapeInfo // TODO: Move to some shared code area (in entities-renderer? model-networking?) // after we verify this is working and do a diff comparison with RenderableModelEntityItem::computeShapeInfo @@ -357,12 +357,14 @@ CollisionPick::CollisionPick(const PickFilter& filter, float maxDistance, bool e CollisionRegion CollisionPick::getMathematicalPick() const { CollisionRegion mathPick = _mathPick; mathPick.loaded = isLoaded(); - if (!parentTransform) { - return mathPick; - } else { - mathPick.transform = parentTransform->getTransform().worldTransform(mathPick.transform); - return mathPick; + if (parentTransform) { + Transform parentTransformValue = parentTransform->getTransform(); + mathPick.transform = parentTransformValue.worldTransform(mathPick.transform); + glm::vec3 scale = parentTransformValue.getScale(); + float largestDimension = glm::max(glm::max(scale.x, scale.y), scale.z); + mathPick.threshold *= largestDimension; } + return mathPick; } void CollisionPick::filterIntersections(std::vector& intersections) const { @@ -393,9 +395,9 @@ PickResultPointer CollisionPick::getEntityIntersection(const CollisionRegion& pi // Cannot compute result return std::make_shared(pick.toVariantMap(), std::vector(), std::vector()); } - getShapeInfoReady(); + getShapeInfoReady(pick); - auto entityIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_ENTITIES, *pick.shapeInfo, pick.transform, USER_COLLISION_GROUP_DYNAMIC, pick.threshold); + auto entityIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_ENTITIES, *_mathPick.shapeInfo, pick.transform, USER_COLLISION_GROUP_DYNAMIC, pick.threshold); filterIntersections(entityIntersections); return std::make_shared(pick, entityIntersections, std::vector()); } @@ -409,9 +411,9 @@ PickResultPointer CollisionPick::getAvatarIntersection(const CollisionRegion& pi // Cannot compute result return std::make_shared(pick, std::vector(), std::vector()); } - getShapeInfoReady(); + getShapeInfoReady(pick); - auto avatarIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_AVATARS, *pick.shapeInfo, pick.transform, USER_COLLISION_GROUP_DYNAMIC, pick.threshold); + auto avatarIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_AVATARS, *_mathPick.shapeInfo, pick.transform, USER_COLLISION_GROUP_DYNAMIC, pick.threshold); filterIntersections(avatarIntersections); return std::make_shared(pick, std::vector(), avatarIntersections); } diff --git a/interface/src/raypick/CollisionPick.h b/interface/src/raypick/CollisionPick.h index ce8b3bd199..fe0e5a6337 100644 --- a/interface/src/raypick/CollisionPick.h +++ b/interface/src/raypick/CollisionPick.h @@ -62,9 +62,9 @@ protected: // Returns true if the resource for _mathPick.shapeInfo is loaded or if a resource is not needed. bool isLoaded() const; // Returns true if _mathPick.shapeInfo is valid. Otherwise, attempts to get the _mathPick ready for use. - bool getShapeInfoReady(); - void computeShapeInfo(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource); - void computeShapeInfoDimensionsOnly(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource); + bool getShapeInfoReady(const CollisionRegion& pick); + void computeShapeInfo(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource); + void computeShapeInfoDimensionsOnly(const CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer resource); void filterIntersections(std::vector& intersections) const; CollisionRegion _mathPick; diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index 6dedf3fca1..0273b084b2 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -24,11 +24,14 @@ #include "CollisionPick.h" #include "SpatialParentFinder.h" -#include "NestableTransformNode.h" #include "PickTransformNode.h" #include "MouseTransformNode.h" #include "avatar/MyAvatarHeadTransformNode.h" #include "avatar/AvatarManager.h" +#include "NestableTransformNode.h" +#include "avatars-renderer/AvatarTransformNode.h" +#include "ui/overlays/OverlayTransformNode.h" +#include "EntityTransformNode.h" #include @@ -260,9 +263,16 @@ unsigned int PickScriptingInterface::createParabolaPick(const QVariant& properti * A set of properties that can be passed to {@link Picks.createPick} to create a new Collision Pick. * @typedef {object} Picks.CollisionPickProperties -* @property {Shape} shape - The information about the collision region's size and shape. -* @property {Vec3} position - The position of the collision region. -* @property {Quat} orientation - The orientation of the collision region. +* @property {boolean} [enabled=false] If this Pick should start enabled or not. Disabled Picks do not updated their pick results. +* @property {number} [filter=Picks.PICK_NOTHING] The filter for this Pick to use, constructed using filter flags combined using bitwise OR. +* @property {Shape} shape - The information about the collision region's size and shape. Dimensions are in world space, but will scale with the parent if defined. +* @property {Vec3} position - The position of the collision region, relative to a parent if defined. +* @property {Quat} orientation - The orientation of the collision region, relative to a parent if defined. +* @property {float} threshold - The approximate minimum penetration depth for a test object to be considered in contact with the collision region. +* The depth is measured in world space, but will scale with the parent if defined. +* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or an overlay. +* @property {number} parentJointIndex - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint) +* @property {string} joint - If "Mouse," parents the pick to the mouse. If "Avatar," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar. */ unsigned int PickScriptingInterface::createCollisionPick(const QVariant& properties) { QVariantMap propMap = properties.toMap(); @@ -375,7 +385,16 @@ std::shared_ptr PickScriptingInterface::createTransformNode(const } auto sharedNestablePointer = nestablePointer.lock(); if (success && sharedNestablePointer) { - return std::make_shared(nestablePointer, parentJointIndex); + NestableType nestableType = sharedNestablePointer->getNestableType(); + if (nestableType == NestableType::Avatar) { + return std::make_shared(std::static_pointer_cast(sharedNestablePointer), parentJointIndex); + } else if (nestableType == NestableType::Overlay) { + return std::make_shared(std::static_pointer_cast(sharedNestablePointer), parentJointIndex); + } else if (nestableType == NestableType::Entity) { + return std::make_shared(std::static_pointer_cast(sharedNestablePointer), parentJointIndex); + } else { + return std::make_shared(nestablePointer, parentJointIndex); + } } } @@ -394,7 +413,7 @@ std::shared_ptr PickScriptingInterface::createTransformNode(const } else if (!joint.isNull()) { auto myAvatar = DependencyManager::get()->getMyAvatar(); int jointIndex = myAvatar->getJointIndex(joint); - return std::make_shared(myAvatar, jointIndex); + return std::make_shared(myAvatar, jointIndex); } } diff --git a/interface/src/ui/AnimStats.cpp b/interface/src/ui/AnimStats.cpp new file mode 100644 index 0000000000..7b4778e365 --- /dev/null +++ b/interface/src/ui/AnimStats.cpp @@ -0,0 +1,141 @@ +// +// Created by Anthony J. Thibault 2018/08/06 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "AnimStats.h" + +#include +#include +#include "Menu.h" + +HIFI_QML_DEF(AnimStats) + +static AnimStats* INSTANCE{ nullptr }; + +AnimStats* AnimStats::getInstance() { + Q_ASSERT(INSTANCE); + return INSTANCE; +} + +AnimStats::AnimStats(QQuickItem* parent) : QQuickItem(parent) { + INSTANCE = this; +} + +void AnimStats::updateStats(bool force) { + QQuickItem* parent = parentItem(); + if (!force) { + if (!Menu::getInstance()->isOptionChecked(MenuOption::AnimStats)) { + if (parent->isVisible()) { + parent->setVisible(false); + } + return; + } else if (!parent->isVisible()) { + parent->setVisible(true); + } + } + + auto avatarManager = DependencyManager::get(); + auto myAvatar = avatarManager->getMyAvatar(); + auto debugAlphaMap = myAvatar->getSkeletonModel()->getRig().getDebugAlphaMap(); + + // update animation debug alpha values + QStringList newAnimAlphaValues; + qint64 now = usecTimestampNow(); + for (auto& iter : debugAlphaMap) { + QString key = iter.first; + float alpha = std::get<0>(iter.second); + + auto prevIter = _prevDebugAlphaMap.find(key); + if (prevIter != _prevDebugAlphaMap.end()) { + float prevAlpha = std::get<0>(iter.second); + if (prevAlpha != alpha) { + // change detected: reset timer + _animAlphaValueChangedTimers[key] = now; + } + } else { + // new value: start timer + _animAlphaValueChangedTimers[key] = now; + } + + AnimNodeType type = std::get<1>(iter.second); + if (type == AnimNodeType::Clip) { + + // figure out the grayScale color of this line. + const float LIT_TIME = 2.0f; + const float FADE_OUT_TIME = 1.0f; + float grayScale = 0.0f; + float secondsElapsed = (float)(now - _animAlphaValueChangedTimers[key]) / (float)USECS_PER_SECOND; + if (secondsElapsed < LIT_TIME) { + grayScale = 1.0f; + } else if (secondsElapsed < LIT_TIME + FADE_OUT_TIME) { + grayScale = (FADE_OUT_TIME - (secondsElapsed - LIT_TIME)) / FADE_OUT_TIME; + } else { + grayScale = 0.0f; + } + + if (grayScale > 0.0f) { + // append grayScaleColor to start of debug string + newAnimAlphaValues << QString::number(grayScale, 'f', 2) + "|" + key + ": " + QString::number(alpha, 'f', 3); + } + } + } + + _animAlphaValues = newAnimAlphaValues; + _prevDebugAlphaMap = debugAlphaMap; + + emit animAlphaValuesChanged(); + + // update animation anim vars + _animVarsList.clear(); + auto animVars = myAvatar->getSkeletonModel()->getRig().getAnimVars().toDebugMap(); + for (auto& iter : animVars) { + QString key = iter.first; + QString value = iter.second; + + auto prevIter = _prevAnimVars.find(key); + if (prevIter != _prevAnimVars.end()) { + QString prevValue = prevIter->second; + if (value != prevValue) { + // change detected: reset timer + _animVarChangedTimers[key] = now; + } + } else { + // new value: start timer + _animVarChangedTimers[key] = now; + } + + // figure out the grayScale color of this line. + const float LIT_TIME = 2.0f; + const float FADE_OUT_TIME = 0.5f; + float grayScale = 0.0f; + float secondsElapsed = (float)(now - _animVarChangedTimers[key]) / (float)USECS_PER_SECOND; + if (secondsElapsed < LIT_TIME) { + grayScale = 1.0f; + } else if (secondsElapsed < LIT_TIME + FADE_OUT_TIME) { + grayScale = (FADE_OUT_TIME - (secondsElapsed - LIT_TIME)) / FADE_OUT_TIME; + } else { + grayScale = 0.0f; + } + + if (grayScale > 0.0f) { + // append grayScaleColor to start of debug string + _animVarsList << QString::number(grayScale, 'f', 2) + "|" + key + ": " + value; + } + } + _prevAnimVars = animVars; + emit animVarsChanged(); + + // animation state machines + _animStateMachines.clear(); + auto stateMachineMap = myAvatar->getSkeletonModel()->getRig().getStateMachineMap(); + for (auto& iter : stateMachineMap) { + _animStateMachines << iter.second; + } + emit animStateMachinesChanged(); +} + + diff --git a/interface/src/ui/AnimStats.h b/interface/src/ui/AnimStats.h new file mode 100644 index 0000000000..1a6795b498 --- /dev/null +++ b/interface/src/ui/AnimStats.h @@ -0,0 +1,55 @@ +// +// Created by Anthony J. Thibault 2018/08/06 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AnimStats_h +#define hifi_AnimStats_h + +#include +#include + +class AnimStats : public QQuickItem { + Q_OBJECT + HIFI_QML_DECL + + Q_PROPERTY(QStringList animAlphaValues READ animAlphaValues NOTIFY animAlphaValuesChanged) + Q_PROPERTY(QStringList animVars READ animVars NOTIFY animVarsChanged) + Q_PROPERTY(QStringList animStateMachines READ animStateMachines NOTIFY animStateMachinesChanged) + +public: + static AnimStats* getInstance(); + + AnimStats(QQuickItem* parent = nullptr); + + void updateStats(bool force = false); + + QStringList animAlphaValues() { return _animAlphaValues; } + QStringList animVars() { return _animVarsList; } + QStringList animStateMachines() { return _animStateMachines; } + +public slots: + void forceUpdateStats() { updateStats(true); } + +signals: + + void animAlphaValuesChanged(); + void animVarsChanged(); + void animStateMachinesChanged(); + +private: + QStringList _animAlphaValues; + AnimContext::DebugAlphaMap _prevDebugAlphaMap; // alpha values from previous frame + std::map _animAlphaValueChangedTimers; // last time alpha value has changed + + QStringList _animVarsList; + std::map _prevAnimVars; // anim vars from previous frame + std::map _animVarChangedTimers; // last time animVar value has changed. + + QStringList _animStateMachines; +}; + +#endif // hifi_AnimStats_h diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 1b26c9b621..d51b90f15d 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -207,14 +207,6 @@ void Stats::updateStats(bool force) { // Third column, avatar stats auto myAvatar = avatarManager->getMyAvatar(); - auto animStack = myAvatar->getSkeletonModel()->getRig().getAnimStack(); - - _animStackNames.clear(); - for (auto animStackIterator = animStack.begin(); animStackIterator != animStack.end(); ++animStackIterator) { - _animStackNames << animStackIterator->first + ": " + QString::number(animStackIterator->second,'f',3); - } - emit animStackNamesChanged(); - glm::vec3 avatarPos = myAvatar->getWorldPosition(); STAT_UPDATE(position, QVector3D(avatarPos.x, avatarPos.y, avatarPos.z)); STAT_UPDATE_FLOAT(speed, glm::length(myAvatar->getWorldVelocity()), 0.01f); diff --git a/interface/src/ui/Stats.h b/interface/src/ui/Stats.h index a0453a09c5..ae608cfddb 100644 --- a/interface/src/ui/Stats.h +++ b/interface/src/ui/Stats.h @@ -134,7 +134,6 @@ private: \ * @property {number} batchFrameTime - Read-only. * @property {number} engineFrameTime - Read-only. * @property {number} avatarSimulationTime - Read-only. - * @property {string[]} animStackNames - Read-only. * * * @property {number} x @@ -292,7 +291,6 @@ class Stats : public QQuickItem { STATS_PROPERTY(float, batchFrameTime, 0) STATS_PROPERTY(float, engineFrameTime, 0) STATS_PROPERTY(float, avatarSimulationTime, 0) - Q_PROPERTY(QStringList animStackNames READ animStackNames NOTIFY animStackNamesChanged) STATS_PROPERTY(int, stylusPicksCount, 0) STATS_PROPERTY(int, rayPicksCount, 0) @@ -326,7 +324,6 @@ public: } QStringList downloadUrls () { return _downloadUrls; } - QStringList animStackNames() { return _animStackNames; } public slots: void forceUpdateStats() { updateStats(true); } @@ -1028,13 +1025,6 @@ signals: */ void avatarSimulationTimeChanged(); - /**jsdoc - * Triggered when the value of the animStackNames property changes. - * @function Stats.animStackNamesChanged - * @returns {Signal} - */ - void animStackNamesChanged(); - /**jsdoc * Triggered when the value of the rectifiedTextureCount property changes. * @function Stats.rectifiedTextureCountChanged @@ -1049,7 +1039,6 @@ signals: */ void decimatedTextureCountChanged(); - // QQuickItem signals. /**jsdoc @@ -1336,7 +1325,6 @@ private: QString _monospaceFont; const AudioIOStats* _audioStats; QStringList _downloadUrls = QStringList(); - QStringList _animStackNames = QStringList(); }; #endif // hifi_Stats_h diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index 6bce9d9283..1d8db69e26 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -238,7 +238,9 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) { */ QVariant Base3DOverlay::getProperty(const QString& property) { if (property == "name") { - return _name; + return _nameLock.resultWithReadLock([&] { + return _name; + }); } if (property == "position" || property == "start" || property == "p1" || property == "point") { return vec3toVariant(getWorldPosition()); @@ -346,6 +348,20 @@ void Base3DOverlay::setVisible(bool visible) { notifyRenderVariableChange(); } +QString Base3DOverlay::getName() const { + return _nameLock.resultWithReadLock([&] { + return QString("Overlay:") + _name; + }); +} + +void Base3DOverlay::setName(QString name) { + _nameLock.withWriteLock([&] { + _name = name; + }); +} + + + render::ItemKey Base3DOverlay::getKey() { auto builder = render::ItemKey::Builder(Overlay::getKey()); @@ -364,4 +380,4 @@ render::ItemKey Base3DOverlay::getKey() { } return builder.build(); -} \ No newline at end of file +} diff --git a/interface/src/ui/overlays/Base3DOverlay.h b/interface/src/ui/overlays/Base3DOverlay.h index d44c193055..6f6092a42e 100644 --- a/interface/src/ui/overlays/Base3DOverlay.h +++ b/interface/src/ui/overlays/Base3DOverlay.h @@ -29,8 +29,8 @@ public: virtual OverlayID getOverlayID() const override { return OverlayID(getID().toString()); } void setOverlayID(OverlayID overlayID) override { setID(overlayID); } - virtual QString getName() const override { return QString("Overlay:") + _name; } - void setName(QString name) { _name = name; } + virtual QString getName() const override; + void setName(QString name); // getters virtual bool is3D() const override { return true; } @@ -107,6 +107,7 @@ protected: mutable bool _renderVariableDirty { true }; QString _name; + mutable ReadWriteLockable _nameLock; }; #endif // hifi_Base3DOverlay_h diff --git a/interface/src/ui/overlays/OverlayTransformNode.cpp b/interface/src/ui/overlays/OverlayTransformNode.cpp new file mode 100644 index 0000000000..817b6af305 --- /dev/null +++ b/interface/src/ui/overlays/OverlayTransformNode.cpp @@ -0,0 +1,13 @@ +// +// Created by Sabrina Shanman 9/5/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "OverlayTransformNode.h" + +template<> +glm::vec3 BaseNestableTransformNode::getActualScale(const std::shared_ptr& nestablePointer) const { + return nestablePointer->getBounds().getScale(); +} \ No newline at end of file diff --git a/interface/src/ui/overlays/OverlayTransformNode.h b/interface/src/ui/overlays/OverlayTransformNode.h new file mode 100644 index 0000000000..11c3415828 --- /dev/null +++ b/interface/src/ui/overlays/OverlayTransformNode.h @@ -0,0 +1,21 @@ +// +// Created by Sabrina Shanman 9/5/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_OverlayTransformNode_h +#define hifi_OverlayTransformNode_h + +#include "NestableTransformNode.h" + +#include "Base3DOverlay.h" + +// For 3D overlays only +class OverlayTransformNode : public BaseNestableTransformNode { +public: + OverlayTransformNode(std::weak_ptr spatiallyNestable, int jointIndex) : BaseNestableTransformNode(spatiallyNestable, jointIndex) {}; +}; + +#endif // hifi_OverlayTransformNode_h \ No newline at end of file diff --git a/libraries/animation/src/AnimBlendLinear.cpp b/libraries/animation/src/AnimBlendLinear.cpp index e2d79f864d..17ca88123f 100644 --- a/libraries/animation/src/AnimBlendLinear.cpp +++ b/libraries/animation/src/AnimBlendLinear.cpp @@ -27,7 +27,7 @@ AnimBlendLinear::~AnimBlendLinear() { const AnimPoseVec& AnimBlendLinear::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) { _alpha = animVars.lookup(_alphaVar, _alpha); - float parentAlpha = _animStack[_id]; + float parentDebugAlpha = context.getDebugAlpha(_id); if (_children.size() == 0) { for (auto&& pose : _poses) { @@ -35,7 +35,7 @@ const AnimPoseVec& AnimBlendLinear::evaluate(const AnimVariantMap& animVars, con } } else if (_children.size() == 1) { _poses = _children[0]->evaluate(animVars, context, dt, triggersOut); - _animStack[_children[0]->getID()] = parentAlpha; + context.setDebugAlpha(_children[0]->getID(), parentDebugAlpha, _children[0]->getType()); } else { float clampedAlpha = glm::clamp(_alpha, 0.0f, (float)(_children.size() - 1)); size_t prevPoseIndex = glm::floor(clampedAlpha); @@ -48,12 +48,12 @@ const AnimPoseVec& AnimBlendLinear::evaluate(const AnimVariantMap& animVars, con float weight2 = 0.0f; if (prevPoseIndex == nextPoseIndex) { weight2 = 1.0f; - _animStack[_children[nextPoseIndex]->getID()] = weight2 * parentAlpha; + context.setDebugAlpha(_children[nextPoseIndex]->getID(), weight2 * parentDebugAlpha, _children[nextPoseIndex]->getType()); } else { weight2 = alpha; weight1 = 1.0f - weight2; - _animStack[_children[prevPoseIndex]->getID()] = weight1 * parentAlpha; - _animStack[_children[nextPoseIndex]->getID()] = weight2 * parentAlpha; + context.setDebugAlpha(_children[prevPoseIndex]->getID(), weight1 * parentDebugAlpha, _children[prevPoseIndex]->getType()); + context.setDebugAlpha(_children[nextPoseIndex]->getID(), weight2 * parentDebugAlpha, _children[nextPoseIndex]->getType()); } } processOutputJoints(triggersOut); diff --git a/libraries/animation/src/AnimBlendLinearMove.cpp b/libraries/animation/src/AnimBlendLinearMove.cpp index 42098eb072..07e1c17f77 100644 --- a/libraries/animation/src/AnimBlendLinearMove.cpp +++ b/libraries/animation/src/AnimBlendLinearMove.cpp @@ -62,9 +62,7 @@ const AnimPoseVec& AnimBlendLinearMove::evaluate(const AnimVariantMap& animVars, speed = animVars.lookup("moveForwardSpeed", speed); } _alpha = calculateAlpha(speed, _characteristicSpeeds); - float parentAlpha = _animStack[_id]; - - _animStack["speed"] = speed; + float parentDebugAlpha = context.getDebugAlpha(_id); if (_children.size() == 0) { for (auto&& pose : _poses) { @@ -77,7 +75,7 @@ const AnimPoseVec& AnimBlendLinearMove::evaluate(const AnimVariantMap& animVars, float prevDeltaTime, nextDeltaTime; setFrameAndPhase(dt, alpha, prevPoseIndex, nextPoseIndex, &prevDeltaTime, &nextDeltaTime, triggersOut); evaluateAndBlendChildren(animVars, context, triggersOut, alpha, prevPoseIndex, nextPoseIndex, prevDeltaTime, nextDeltaTime); - _animStack[_children[0]->getID()] = parentAlpha; + context.setDebugAlpha(_children[0]->getID(), parentDebugAlpha, _children[0]->getType()); } else { auto clampedAlpha = glm::clamp(_alpha, 0.0f, (float)(_children.size() - 1)); auto prevPoseIndex = glm::floor(clampedAlpha); @@ -87,17 +85,11 @@ const AnimPoseVec& AnimBlendLinearMove::evaluate(const AnimVariantMap& animVars, setFrameAndPhase(dt, alpha, prevPoseIndex, nextPoseIndex, &prevDeltaTime, &nextDeltaTime, triggersOut); evaluateAndBlendChildren(animVars, context, triggersOut, alpha, prevPoseIndex, nextPoseIndex, prevDeltaTime, nextDeltaTime); - // weights are for animation stack debug purposes only. - float weight1 = 0.0f; - float weight2 = 0.0f; if (prevPoseIndex == nextPoseIndex) { - weight2 = 1.0f; - _animStack[_children[nextPoseIndex]->getID()] = weight2 * parentAlpha; + context.setDebugAlpha(_children[nextPoseIndex]->getID(), parentDebugAlpha, _children[nextPoseIndex]->getType()); } else { - weight2 = alpha; - weight1 = 1.0f - weight2; - _animStack[_children[prevPoseIndex]->getID()] = weight1 * parentAlpha; - _animStack[_children[nextPoseIndex]->getID()] = weight2 * parentAlpha; + context.setDebugAlpha(_children[prevPoseIndex]->getID(), (1.0f - alpha) * parentDebugAlpha, _children[prevPoseIndex]->getType()); + context.setDebugAlpha(_children[nextPoseIndex]->getID(), alpha * parentDebugAlpha, _children[nextPoseIndex]->getType()); } } diff --git a/libraries/animation/src/AnimContext.h b/libraries/animation/src/AnimContext.h index e8bf5c34eb..c455dd9c8f 100644 --- a/libraries/animation/src/AnimContext.h +++ b/libraries/animation/src/AnimContext.h @@ -14,8 +14,27 @@ #include #include +#include +#include +#include + +enum class AnimNodeType { + Clip = 0, + BlendLinear, + BlendLinearMove, + Overlay, + StateMachine, + Manipulator, + InverseKinematics, + DefaultPose, + TwoBoneIK, + PoleVectorConstraint, + NumTypes +}; + class AnimContext { public: + AnimContext() {} AnimContext(bool enableDebugDrawIKTargets, bool enableDebugDrawIKConstraints, bool enableDebugDrawIKChains, const glm::mat4& geometryToRigMatrix, const glm::mat4& rigToWorldMatrix); @@ -25,6 +44,39 @@ public: const glm::mat4& getGeometryToRigMatrix() const { return _geometryToRigMatrix; } const glm::mat4& getRigToWorldMatrix() const { return _rigToWorldMatrix; } + float getDebugAlpha(const QString& key) const { + auto it = _debugAlphaMap.find(key); + if (it != _debugAlphaMap.end()) { + return std::get<0>(it->second); + } else { + return 1.0f; + } + } + + using DebugAlphaMapValue = std::tuple; + using DebugAlphaMap = std::map; + + void setDebugAlpha(const QString& key, float alpha, AnimNodeType type) const { + _debugAlphaMap[key] = DebugAlphaMapValue(alpha, type); + } + + const DebugAlphaMap& getDebugAlphaMap() const { + return _debugAlphaMap; + } + + using DebugStateMachineMapValue = QString; + using DebugStateMachineMap = std::map; + + void addStateMachineInfo(const QString& stateMachineName, const QString& currentState, const QString& previousState, bool duringInterp, float alpha) const { + if (duringInterp) { + _stateMachineMap[stateMachineName] = QString("%1: %2 -> %3 (%4)").arg(stateMachineName).arg(previousState).arg(currentState).arg(QString::number(alpha, 'f', 2)); + } else { + _stateMachineMap[stateMachineName] = QString("%1: %2").arg(stateMachineName).arg(currentState); + } + } + + const DebugStateMachineMap& getStateMachineMap() const { return _stateMachineMap; } + protected: bool _enableDebugDrawIKTargets { false }; @@ -32,6 +84,10 @@ protected: bool _enableDebugDrawIKChains { false }; glm::mat4 _geometryToRigMatrix; glm::mat4 _rigToWorldMatrix; + + // used for debugging internal state of animation system. + mutable DebugAlphaMap _debugAlphaMap; + mutable DebugStateMachineMap _stateMachineMap; }; #endif // hifi_AnimContext_h diff --git a/libraries/animation/src/AnimNode.cpp b/libraries/animation/src/AnimNode.cpp index a8e76617ae..f055e6b473 100644 --- a/libraries/animation/src/AnimNode.cpp +++ b/libraries/animation/src/AnimNode.cpp @@ -12,10 +12,6 @@ #include -std::map AnimNode::_animStack = { - {"none", 0.0f} -}; - AnimNode::Pointer AnimNode::getParent() { return _parent.lock(); } diff --git a/libraries/animation/src/AnimNode.h b/libraries/animation/src/AnimNode.h index 1f14889ce4..1a12bb8ddb 100644 --- a/libraries/animation/src/AnimNode.h +++ b/libraries/animation/src/AnimNode.h @@ -36,19 +36,7 @@ class QJsonObject; class AnimNode : public std::enable_shared_from_this { public: - enum class Type { - Clip = 0, - BlendLinear, - BlendLinearMove, - Overlay, - StateMachine, - Manipulator, - InverseKinematics, - DefaultPose, - TwoBoneIK, - PoleVectorConstraint, - NumTypes - }; + using Type = AnimNodeType; using Pointer = std::shared_ptr; using ConstPointer = std::shared_ptr; @@ -84,7 +72,6 @@ public: } void setCurrentFrame(float frame); - const std::map getAnimStack() { return _animStack; } template bool traverse(F func) { @@ -127,9 +114,6 @@ protected: std::weak_ptr _parent; std::vector _outputJointNames; - // global available to Stats.h - static std::map _animStack; - // no copies AnimNode(const AnimNode&) = delete; AnimNode& operator=(const AnimNode&) = delete; diff --git a/libraries/animation/src/AnimStateMachine.cpp b/libraries/animation/src/AnimStateMachine.cpp index 90fd425ae5..7f46cd614a 100644 --- a/libraries/animation/src/AnimStateMachine.cpp +++ b/libraries/animation/src/AnimStateMachine.cpp @@ -23,9 +23,7 @@ AnimStateMachine::~AnimStateMachine() { const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, const AnimContext& context, float dt, AnimVariantMap& triggersOut) { - if (_id.contains("userAnimStateMachine")) { - _animStack.clear(); - } + float parentDebugAlpha = context.getDebugAlpha(_id); QString desiredStateID = animVars.lookup(_currentStateVar, _currentState->getID()); if (_currentState->getID() != desiredStateID) { @@ -33,8 +31,6 @@ const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, co bool foundState = false; for (auto& state : _states) { if (state->getID() == desiredStateID) { - // parenthesis means previous state, which is a snapshot. - _previousStateID = "(" + _currentState->getID() + ")"; switchState(animVars, context, state); foundState = true; break; @@ -48,8 +44,6 @@ const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, co // evaluate currentState transitions auto desiredState = evaluateTransitions(animVars); if (desiredState != _currentState) { - // parenthesis means previous state, which is a snapshot. - _previousStateID = "(" + _currentState->getID() + ")"; switchState(animVars, context, desiredState); } @@ -57,17 +51,8 @@ const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, co auto currentStateNode = _children[_currentState->getChildIndex()]; assert(currentStateNode); - if (!_previousStateID.contains("none")) { - _animStack[_previousStateID] = 1.0f - _alpha; - } - if (_duringInterp) { _alpha += _alphaVel * dt; - if (_alpha > 1.0f) { - _animStack[_currentState->getID()] = 1.0f; - } else { - _animStack[_currentState->getID()] = _alpha; - } if (_alpha < 1.0f) { AnimPoseVec* nextPoses = nullptr; AnimPoseVec* prevPoses = nullptr; @@ -88,26 +73,27 @@ const AnimPoseVec& AnimStateMachine::evaluate(const AnimVariantMap& animVars, co if (_poses.size() > 0 && nextPoses && prevPoses && nextPoses->size() > 0 && prevPoses->size() > 0) { ::blend(_poses.size(), &(prevPoses->at(0)), &(nextPoses->at(0)), _alpha, &_poses[0]); } + context.setDebugAlpha(_currentState->getID(), _alpha * parentDebugAlpha, _children[_currentState->getChildIndex()]->getType()); } else { _duringInterp = false; - if (_animStack.count(_previousStateID) > 0) { - _animStack.erase(_previousStateID); - } - _previousStateID = "none"; _prevPoses.clear(); _nextPoses.clear(); } } + if (!_duringInterp) { - _animStack[_currentState->getID()] = 1.0f; + context.setDebugAlpha(_currentState->getID(), parentDebugAlpha, _children[_currentState->getChildIndex()]->getType()); _poses = currentStateNode->evaluate(animVars, context, dt, triggersOut); } processOutputJoints(triggersOut); + context.addStateMachineInfo(_id, _currentState->getID(), _previousState->getID(), _duringInterp, _alpha); + return _poses; } void AnimStateMachine::setCurrentState(State::Pointer state) { + _previousState = _currentState ? _currentState : state; _currentState = state; } @@ -152,7 +138,7 @@ void AnimStateMachine::switchState(const AnimVariantMap& animVars, const AnimCon qCDebug(animation) << "AnimStateMachine::switchState:" << _currentState->getID() << "->" << desiredState->getID() << "duration =" << duration << "targetFrame =" << desiredState->_interpTarget << "interpType = " << (int)_interpType; #endif - _currentState = desiredState; + setCurrentState(desiredState); } AnimStateMachine::State::Pointer AnimStateMachine::evaluateTransitions(const AnimVariantMap& animVars) const { diff --git a/libraries/animation/src/AnimStateMachine.h b/libraries/animation/src/AnimStateMachine.h index b20e5203a1..713c659a1d 100644 --- a/libraries/animation/src/AnimStateMachine.h +++ b/libraries/animation/src/AnimStateMachine.h @@ -138,9 +138,9 @@ protected: float _alpha = 0.0f; AnimPoseVec _prevPoses; AnimPoseVec _nextPoses; - QString _previousStateID { "none" }; State::Pointer _currentState; + State::Pointer _previousState; std::vector _states; QString _currentStateVar; diff --git a/libraries/animation/src/AnimVariant.cpp b/libraries/animation/src/AnimVariant.cpp index 483a7999c9..509462984a 100644 --- a/libraries/animation/src/AnimVariant.cpp +++ b/libraries/animation/src/AnimVariant.cpp @@ -67,6 +67,7 @@ QScriptValue AnimVariantMap::animVariantMapToScriptValue(QScriptEngine* engine, } return target; } + void AnimVariantMap::copyVariantsFrom(const AnimVariantMap& other) { for (auto& pair : other._map) { _map[pair.first] = pair.second; @@ -124,3 +125,43 @@ void AnimVariantMap::animVariantMapFromScriptValue(const QScriptValue& source) { } } } + +std::map AnimVariantMap::toDebugMap() const { + std::map result; + for (auto& pair : _map) { + switch (pair.second.getType()) { + case AnimVariant::Type::Bool: + result[pair.first] = QString("%1").arg(pair.second.getBool()); + break; + case AnimVariant::Type::Int: + result[pair.first] = QString("%1").arg(pair.second.getInt()); + break; + case AnimVariant::Type::Float: + result[pair.first] = QString::number(pair.second.getFloat(), 'f', 3); + break; + case AnimVariant::Type::Vec3: { + glm::vec3 value = pair.second.getVec3(); + result[pair.first] = QString("(%1, %2, %3)"). + arg(QString::number(value.x, 'f', 3)). + arg(QString::number(value.y, 'f', 3)). + arg(QString::number(value.z, 'f', 3)); + break; + } + case AnimVariant::Type::Quat: { + glm::quat value = pair.second.getQuat(); + result[pair.first] = QString("(%1, %2, %3, %4)"). + arg(QString::number(value.x, 'f', 3)). + arg(QString::number(value.y, 'f', 3)). + arg(QString::number(value.z, 'f', 3)). + arg(QString::number(value.w, 'f', 3)); + break; + } + case AnimVariant::Type::String: + result[pair.first] = pair.second.getString(); + break; + default: + assert(("invalid AnimVariant::Type", false)); + } + } + return result; +} diff --git a/libraries/animation/src/AnimVariant.h b/libraries/animation/src/AnimVariant.h index d383b5abb8..0f921984b1 100644 --- a/libraries/animation/src/AnimVariant.h +++ b/libraries/animation/src/AnimVariant.h @@ -235,6 +235,9 @@ public: void animVariantMapFromScriptValue(const QScriptValue& object); void copyVariantsFrom(const AnimVariantMap& other); + // For stat debugging. + std::map toDebugMap() const; + #ifdef NDEBUG void dump() const { qCDebug(animation) << "AnimVariantMap ="; diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 13cf165dac..91d4e0f9d3 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1061,8 +1061,10 @@ void Rig::updateAnimations(float deltaTime, const glm::mat4& rootTransform, cons // animations haven't fully loaded yet. _internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses(); } + _lastAnimVars = _animVars; _animVars.clearTriggers(); _animVars = triggersOut; + _lastContext = context; } applyOverridePoses(); buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index accbcccbbc..48f00d4e5d 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -222,7 +222,10 @@ public: // input assumed to be in rig space void computeHeadFromHMD(const AnimPose& hmdPose, glm::vec3& headPositionOut, glm::quat& headOrientationOut) const; - const std::map getAnimStack() { return _animNode->getAnimStack(); } + // used to debug animation playback + const AnimContext::DebugAlphaMap& getDebugAlphaMap() const { return _lastContext.getDebugAlphaMap(); } + const AnimVariantMap& getAnimVars() const { return _lastAnimVars; } + const AnimContext::DebugStateMachineMap& getStateMachineMap() const { return _lastContext.getStateMachineMap(); } void toggleSmoothPoleVectors() { _smoothPoleVectors = !_smoothPoleVectors; }; signals: @@ -388,6 +391,9 @@ protected: int _rigId; bool _headEnabled { false }; + + AnimContext _lastContext; + AnimVariantMap _lastAnimVars; }; #endif /* defined(__hifi__Rig__) */ diff --git a/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp b/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp new file mode 100644 index 0000000000..ca3d4a6062 --- /dev/null +++ b/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.cpp @@ -0,0 +1,13 @@ +// +// Created by Sabrina Shanman 9/5/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "AvatarTransformNode.h" + +template<> +glm::vec3 BaseNestableTransformNode::getActualScale(const std::shared_ptr& nestablePointer) const { + return nestablePointer->scaleForChildren(); +} \ No newline at end of file diff --git a/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.h b/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.h new file mode 100644 index 0000000000..183e4ab05c --- /dev/null +++ b/libraries/avatars-renderer/src/avatars-renderer/AvatarTransformNode.h @@ -0,0 +1,20 @@ +// +// Created by Sabrina Shanman 9/5/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_AvatarTransformNode_h +#define hifi_AvatarTransformNode_h + +#include "NestableTransformNode.h" + +#include "Avatar.h" + +class AvatarTransformNode : public BaseNestableTransformNode { +public: + AvatarTransformNode(std::weak_ptr spatiallyNestable, int jointIndex) : BaseNestableTransformNode(spatiallyNestable, jointIndex) {}; +}; + +#endif // hifi_AvatarTransformNode_h \ No newline at end of file diff --git a/libraries/avatars-renderer/src/avatars-renderer/Head.cpp b/libraries/avatars-renderer/src/avatars-renderer/Head.cpp index bdee6d9147..9cf034863e 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Head.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Head.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include #include diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index c1246866dc..1383939b8b 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -21,6 +21,7 @@ #include "AvatarLogging.h" #include "AvatarTraits.h" +#include "Profile.h" void AvatarReplicas::addReplica(const QUuid& parentID, AvatarSharedPointer replica) { if (parentID == QUuid()) { @@ -214,6 +215,7 @@ AvatarSharedPointer AvatarHashMap::findAvatar(const QUuid& sessionUUID) const { } void AvatarHashMap::processAvatarDataPacket(QSharedPointer message, SharedNodePointer sendingNode) { + DETAILED_PROFILE_RANGE(network, __FUNCTION__); PerformanceTimer perfTimer("receiveAvatar"); // enumerate over all of the avatars in this packet // only add them if mixerWeakPointer points to something (meaning that mixer is still around) diff --git a/libraries/display-plugins/src/display-plugins/InterleavedSrgbToLinear.slf b/libraries/display-plugins/src/display-plugins/InterleavedSrgbToLinear.slf index 5f7b3f3411..17dedce7f9 100644 --- a/libraries/display-plugins/src/display-plugins/InterleavedSrgbToLinear.slf +++ b/libraries/display-plugins/src/display-plugins/InterleavedSrgbToLinear.slf @@ -11,7 +11,7 @@ layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; void main(void) { - ivec2 texCoord = ivec2(floor(varTexCoord0 * textureData.textureSize)); + ivec2 texCoord = ivec2(floor(varTexCoord0 * vec2(textureData.textureSize))); texCoord.x /= 2; int row = int(floor(gl_FragCoord.y)); if (row % 2 > 0) { diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 2da5c30dc0..a4a5a34683 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1609,6 +1609,7 @@ PolyVoxEntityRenderer::PolyVoxEntityRenderer(const EntityItemPointer& entity) : _vertexFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); _vertexFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 12); }); + _params = std::make_shared(sizeof(glm::vec4), nullptr); } ShapeKey PolyVoxEntityRenderer::getShapeKey() { @@ -1671,9 +1672,12 @@ void PolyVoxEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& s void PolyVoxEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) { _lastVoxelToWorldMatrix = entity->voxelToWorldMatrix(); + _lastVoxelVolumeSize = entity->getVoxelVolumeSize(); + _params->setSubData(0, vec4(_lastVoxelVolumeSize, 0.0)); graphics::MeshPointer newMesh; entity->withReadLock([&] { newMesh = entity->_mesh; + }); if (newMesh && newMesh->getIndexBuffer()._buffer) { @@ -1686,6 +1690,7 @@ void PolyVoxEntityRenderer::doRender(RenderArgs* args) { return; } + PerformanceTimer perfTimer("RenderablePolyVoxEntityItem::render"); gpu::Batch& batch = *args->_batch; @@ -1695,6 +1700,7 @@ void PolyVoxEntityRenderer::doRender(RenderArgs* args) { batch.setInputBuffer(gpu::Stream::POSITION, _mesh->getVertexBuffer()._buffer, 0, sizeof(PolyVox::PositionMaterialNormal)); + // TODO -- should we be setting this? // batch.setInputBuffer(gpu::Stream::NORMAL, mesh->getVertexBuffer()._buffer, // 12, @@ -1710,7 +1716,7 @@ void PolyVoxEntityRenderer::doRender(RenderArgs* args) { } } - batch._glUniform3f(entities_renderer::slot::uniform::PolyvoxVoxelSize, _lastVoxelVolumeSize.x, _lastVoxelVolumeSize.y, _lastVoxelVolumeSize.z); + batch.setUniformBuffer(0, _params); batch.drawIndexed(gpu::TRIANGLES, (gpu::uint32)_mesh->getNumIndices(), 0); } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index 7afb9b41b4..366a3fdc70 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -187,6 +187,7 @@ private: #endif graphics::MeshPointer _mesh; + gpu::BufferPointer _params; std::array _xyzTextures; glm::vec3 _lastVoxelVolumeSize; glm::mat4 _lastVoxelToWorldMatrix; diff --git a/libraries/entities-renderer/src/entities-renderer/ShaderConstants.h b/libraries/entities-renderer/src/entities-renderer/ShaderConstants.h index 58b0bf5688..d01075846a 100644 --- a/libraries/entities-renderer/src/entities-renderer/ShaderConstants.h +++ b/libraries/entities-renderer/src/entities-renderer/ShaderConstants.h @@ -15,7 +15,6 @@ #define ENTITIES_SHADER_CONSTANTS_H // Polyvox -#define ENTITIES_UNIFORM_POLYVOX_VOXEL_SIZE 0 #define ENTITIES_TEXTURE_POLYVOX_XMAP 0 #define ENTITIES_TEXTURE_POLYVOX_YMAP 1 #define ENTITIES_TEXTURE_POLYVOX_ZMAP 2 @@ -26,17 +25,6 @@ namespace entities_renderer { namespace slot { -namespace uniform { -enum Uniform { - PolyvoxVoxelSize = ENTITIES_UNIFORM_POLYVOX_VOXEL_SIZE, -}; -} - -namespace buffer { -enum Buffer { -}; -} // namespace buffer - namespace texture { enum Texture { PolyvoxXMap = ENTITIES_TEXTURE_POLYVOX_XMAP, diff --git a/libraries/entities-renderer/src/paintStroke_fade.slf b/libraries/entities-renderer/src/paintStroke_fade.slf index 8739c9bb9b..e5f70c8038 100644 --- a/libraries/entities-renderer/src/paintStroke_fade.slf +++ b/libraries/entities-renderer/src/paintStroke_fade.slf @@ -45,7 +45,7 @@ void main(void) { int frontCondition = 1 -int(gl_FrontFacing) * 2; vec3 color = varColor.rgb; packDeferredFragmentTranslucent( - interpolatedNormal * frontCondition, + interpolatedNormal * float(frontCondition), texel.a * varColor.a, polyline.color * texel.rgb + fadeEmissive, vec3(0.01, 0.01, 0.01), diff --git a/libraries/entities-renderer/src/polyvox.slf b/libraries/entities-renderer/src/polyvox.slf index ba2fd7031b..441dfc11e5 100644 --- a/libraries/entities-renderer/src/polyvox.slf +++ b/libraries/entities-renderer/src/polyvox.slf @@ -23,15 +23,22 @@ layout(location=RENDER_UTILS_ATTR_POSITION_WS) in vec4 _worldPosition; layout(binding=ENTITIES_TEXTURE_POLYVOX_XMAP) uniform sampler2D xMap; layout(binding=ENTITIES_TEXTURE_POLYVOX_YMAP) uniform sampler2D yMap; layout(binding=ENTITIES_TEXTURE_POLYVOX_ZMAP) uniform sampler2D zMap; -layout(location=ENTITIES_UNIFORM_POLYVOX_VOXEL_SIZE) uniform vec3 voxelVolumeSize; + +struct PolyvoxParams { + vec4 voxelVolumeSize; +}; + +layout(binding=0) uniform polyvoxParamsBuffer { + PolyvoxParams params; +}; void main(void) { vec3 worldNormal = cross(dFdy(_worldPosition.xyz), dFdx(_worldPosition.xyz)); worldNormal = normalize(worldNormal); - float inPositionX = (_worldPosition.x - 0.5) / voxelVolumeSize.x; - float inPositionY = (_worldPosition.y - 0.5) / voxelVolumeSize.y; - float inPositionZ = (_worldPosition.z - 0.5) / voxelVolumeSize.z; + float inPositionX = (_worldPosition.x - 0.5) / params.voxelVolumeSize.x; + float inPositionY = (_worldPosition.y - 0.5) / params.voxelVolumeSize.y; + float inPositionZ = (_worldPosition.z - 0.5) / params.voxelVolumeSize.z; vec4 xyDiffuse = texture(xMap, vec2(-inPositionX, -inPositionY)); vec4 xzDiffuse = texture(yMap, vec2(-inPositionX, inPositionZ)); diff --git a/libraries/entities-renderer/src/polyvox_fade.slf b/libraries/entities-renderer/src/polyvox_fade.slf index 2247e472ea..6e236193aa 100644 --- a/libraries/entities-renderer/src/polyvox_fade.slf +++ b/libraries/entities-renderer/src/polyvox_fade.slf @@ -27,7 +27,13 @@ layout(binding=ENTITIES_TEXTURE_POLYVOX_XMAP) uniform sampler2D xMap; layout(binding=ENTITIES_TEXTURE_POLYVOX_YMAP) uniform sampler2D yMap; layout(binding=ENTITIES_TEXTURE_POLYVOX_ZMAP) uniform sampler2D zMap; -layout(location=ENTITIES_UNIFORM_POLYVOX_VOXEL_SIZE) uniform vec3 voxelVolumeSize; +struct PolyvoxParams { + vec4 voxelVolumeSize; +}; + +layout(binding=0) uniform polyvoxParamsBuffer { + PolyvoxParams params; +}; // Declare after all samplers to prevent sampler location mix up with voxel shading (sampler locations are hardcoded in RenderablePolyVoxEntityItem) <$declareFadeFragment()$> @@ -42,9 +48,9 @@ void main(void) { vec3 worldNormal = cross(dFdy(_worldPosition.xyz), dFdx(_worldPosition.xyz)); worldNormal = normalize(worldNormal); - float inPositionX = (_worldPosition.x - 0.5) / voxelVolumeSize.x; - float inPositionY = (_worldPosition.y - 0.5) / voxelVolumeSize.y; - float inPositionZ = (_worldPosition.z - 0.5) / voxelVolumeSize.z; + float inPositionX = (_worldPosition.x - 0.5) / params.voxelVolumeSize.x; + float inPositionY = (_worldPosition.y - 0.5) / params.voxelVolumeSize.y; + float inPositionZ = (_worldPosition.z - 0.5) / params.voxelVolumeSize.z; vec4 xyDiffuse = texture(xMap, vec2(-inPositionX, -inPositionY)); vec4 xzDiffuse = texture(yMap, vec2(-inPositionX, inPositionZ)); diff --git a/libraries/entities/src/EntityTransformNode.cpp b/libraries/entities/src/EntityTransformNode.cpp new file mode 100644 index 0000000000..438ece3840 --- /dev/null +++ b/libraries/entities/src/EntityTransformNode.cpp @@ -0,0 +1,13 @@ +// +// Created by Sabrina Shanman 9/5/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "EntityTransformNode.h" + +template<> +glm::vec3 BaseNestableTransformNode::getActualScale(const std::shared_ptr& nestablePointer) const { + return nestablePointer->getScaledDimensions(); +} \ No newline at end of file diff --git a/libraries/entities/src/EntityTransformNode.h b/libraries/entities/src/EntityTransformNode.h new file mode 100644 index 0000000000..07818f99f3 --- /dev/null +++ b/libraries/entities/src/EntityTransformNode.h @@ -0,0 +1,20 @@ +// +// Created by Sabrina Shanman 9/5/2018 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_EntityTransformNode_h +#define hifi_EntityTransformNode_h + +#include "NestableTransformNode.h" + +#include "EntityItem.h" + +class EntityTransformNode : public BaseNestableTransformNode { +public: + EntityTransformNode(std::weak_ptr spatiallyNestable, int jointIndex) : BaseNestableTransformNode(spatiallyNestable, jointIndex) {}; +}; + +#endif // hifi_EntityTransformNode_h \ No newline at end of file diff --git a/libraries/fbx/src/FBXReader_Mesh.cpp b/libraries/fbx/src/FBXReader_Mesh.cpp index 801edddb06..e8b5abcc9c 100644 --- a/libraries/fbx/src/FBXReader_Mesh.cpp +++ b/libraries/fbx/src/FBXReader_Mesh.cpp @@ -585,13 +585,8 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { FBXMesh& fbxMesh = extractedMesh; graphics::MeshPointer mesh(new graphics::Mesh()); - - // Grab the vertices in a buffer - auto vb = std::make_shared(); - vb->setData(extractedMesh.vertices.size() * sizeof(glm::vec3), - (const gpu::Byte*) extractedMesh.vertices.data()); - gpu::BufferView vbv(vb, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ)); - mesh->setVertexBuffer(vbv); + bool hasBlendShapes = !fbxMesh.blendshapes.empty(); + int numVerts = extractedMesh.vertices.size(); if (!fbxMesh.normals.empty() && fbxMesh.tangents.empty()) { // Fill with a dummy value to force tangents to be present if there are normals @@ -607,43 +602,61 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { } } - // evaluate all attribute channels sizes - const int normalsSize = fbxMesh.normals.size() * sizeof(NormalType); - const int tangentsSize = fbxMesh.tangents.size() * sizeof(NormalType); + // evaluate all attribute elements and data sizes + + // Position is a vec3 + const auto positionElement = gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ); + const int positionsSize = numVerts * positionElement.getSize(); + + // Normal and tangent are always there together packed in normalized xyz32bits word (times 2) + const auto normalElement = FBX_NORMAL_ELEMENT; + const int normalsSize = fbxMesh.normals.size() * normalElement.getSize(); + const int tangentsSize = fbxMesh.tangents.size() * normalElement.getSize(); // If there are normals then there should be tangents - assert(normalsSize <= tangentsSize); if (tangentsSize > normalsSize) { qWarning() << "Unexpected tangents in " << url; } const auto normalsAndTangentsSize = normalsSize + tangentsSize; - const int normalsAndTangentsStride = 2 * sizeof(NormalType); - const int colorsSize = fbxMesh.colors.size() * sizeof(ColorType); + const int normalsAndTangentsStride = 2 * normalElement.getSize(); + + // Color attrib + const auto colorElement = FBX_COLOR_ELEMENT; + const int colorsSize = fbxMesh.colors.size() * colorElement.getSize(); + // Texture coordinates are stored in 2 half floats - const int texCoordsSize = fbxMesh.texCoords.size() * sizeof(vec2h); - const int texCoords1Size = fbxMesh.texCoords1.size() * sizeof(vec2h); + const auto texCoordsElement = gpu::Element(gpu::VEC2, gpu::HALF, gpu::UV); + const int texCoordsSize = fbxMesh.texCoords.size() * texCoordsElement.getSize(); + const int texCoords1Size = fbxMesh.texCoords1.size() * texCoordsElement.getSize(); - int clusterIndicesSize = fbxMesh.clusterIndices.size() * sizeof(uint8_t); - if (fbxMesh.clusters.size() > UINT8_MAX) { - // we need 16 bits instead of just 8 for clusterIndices - clusterIndicesSize *= 2; - } + // Support for 4 skinning clusters: + // 4 Indices are uint8 ideally, uint16 if more than 256. + const auto clusterIndiceElement = (fbxMesh.clusters.size() < UINT8_MAX ? gpu::Element(gpu::VEC4, gpu::UINT8, gpu::XYZW) : gpu::Element(gpu::VEC4, gpu::UINT16, gpu::XYZW)); + // 4 Weights are normalized 16bits + const auto clusterWeightElement = gpu::Element(gpu::VEC4, gpu::NUINT16, gpu::XYZW); - const int clusterWeightsSize = fbxMesh.clusterWeights.size() * sizeof(uint16_t); + // Cluster indices and weights must be the same sizes + const int NUM_CLUSTERS_PER_VERT = 4; + const int numVertClusters = (fbxMesh.clusterIndices.size() == fbxMesh.clusterWeights.size() ? fbxMesh.clusterIndices.size() / NUM_CLUSTERS_PER_VERT : 0); + const int clusterIndicesSize = numVertClusters * clusterIndiceElement.getSize(); + const int clusterWeightsSize = numVertClusters * clusterWeightElement.getSize(); - // Normals and tangents are interleaved - const int normalsOffset = 0; - const int tangentsOffset = normalsOffset + sizeof(NormalType); - const int colorsOffset = normalsOffset + normalsSize + tangentsSize; + // Decide on where to put what seequencially in a big buffer: + const int positionsOffset = 0; + const int normalsAndTangentsOffset = positionsOffset + positionsSize; + const int colorsOffset = normalsAndTangentsOffset + normalsAndTangentsSize; const int texCoordsOffset = colorsOffset + colorsSize; const int texCoords1Offset = texCoordsOffset + texCoordsSize; const int clusterIndicesOffset = texCoords1Offset + texCoords1Size; const int clusterWeightsOffset = clusterIndicesOffset + clusterIndicesSize; - const int totalAttributeSize = clusterWeightsOffset + clusterWeightsSize; + const int totalVertsSize = clusterWeightsOffset + clusterWeightsSize; - // Copy all attribute data in a single attribute buffer - auto attribBuffer = std::make_shared(); - attribBuffer->resize(totalAttributeSize); + // Copy all vertex data in a single buffer + auto vertBuffer = std::make_shared(); + vertBuffer->resize(totalVertsSize); + + // First positions + vertBuffer->setSubData(positionsOffset, positionsSize, (const gpu::Byte*) extractedMesh.vertices.data()); // Interleave normals and tangents if (normalsSize > 0) { @@ -651,8 +664,8 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { normalsAndTangents.reserve(fbxMesh.normals.size() + fbxMesh.tangents.size()); for (auto normalIt = fbxMesh.normals.constBegin(), tangentIt = fbxMesh.tangents.constBegin(); - normalIt != fbxMesh.normals.constEnd(); - ++normalIt, ++tangentIt) { + normalIt != fbxMesh.normals.constEnd(); + ++normalIt, ++tangentIt) { #if FBX_PACK_NORMALS const auto normal = normalizeDirForPacking(*normalIt); const auto tangent = normalizeDirForPacking(*tangentIt); @@ -665,9 +678,10 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { normalsAndTangents.push_back(packedNormal); normalsAndTangents.push_back(packedTangent); } - attribBuffer->setSubData(normalsOffset, normalsAndTangentsSize, (const gpu::Byte*) normalsAndTangents.data()); + vertBuffer->setSubData(normalsAndTangentsOffset, normalsAndTangentsSize, (const gpu::Byte*) normalsAndTangents.data()); } + // Pack colors if (colorsSize > 0) { #if FBX_PACK_COLORS std::vector colors; @@ -676,12 +690,13 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { for (const auto& color : fbxMesh.colors) { colors.push_back(glm::packUnorm4x8(glm::vec4(color, 1.0f))); } - attribBuffer->setSubData(colorsOffset, colorsSize, (const gpu::Byte*) colors.data()); + vertBuffer->setSubData(colorsOffset, colorsSize, (const gpu::Byte*) colors.data()); #else - attribBuffer->setSubData(colorsOffset, colorsSize, (const gpu::Byte*) fbxMesh.colors.constData()); + vertBuffer->setSubData(colorsOffset, colorsSize, (const gpu::Byte*) fbxMesh.colors.constData()); #endif } + // Pack Texcoords 0 and 1 (if exists) if (texCoordsSize > 0) { QVector texCoordData; texCoordData.reserve(fbxMesh.texCoords.size()); @@ -692,9 +707,8 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { texCoordVec2h.y = glm::detail::toFloat16(texCoordVec2f.y); texCoordData.push_back(texCoordVec2h); } - attribBuffer->setSubData(texCoordsOffset, texCoordsSize, (const gpu::Byte*) texCoordData.constData()); + vertBuffer->setSubData(texCoordsOffset, texCoordsSize, (const gpu::Byte*) texCoordData.constData()); } - if (texCoords1Size > 0) { QVector texCoordData; texCoordData.reserve(fbxMesh.texCoords1.size()); @@ -705,69 +719,170 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { texCoordVec2h.y = glm::detail::toFloat16(texCoordVec2f.y); texCoordData.push_back(texCoordVec2h); } - attribBuffer->setSubData(texCoords1Offset, texCoords1Size, (const gpu::Byte*) texCoordData.constData()); + vertBuffer->setSubData(texCoords1Offset, texCoords1Size, (const gpu::Byte*) texCoordData.constData()); } - if (fbxMesh.clusters.size() < UINT8_MAX) { - // yay! we can fit the clusterIndices within 8-bits - int32_t numIndices = fbxMesh.clusterIndices.size(); - QVector clusterIndices; - clusterIndices.resize(numIndices); - for (int32_t i = 0; i < numIndices; ++i) { - assert(fbxMesh.clusterIndices[i] <= UINT8_MAX); - clusterIndices[i] = (uint8_t)(fbxMesh.clusterIndices[i]); + // Clusters data + if (clusterIndicesSize > 0) { + if (fbxMesh.clusters.size() < UINT8_MAX) { + // yay! we can fit the clusterIndices within 8-bits + int32_t numIndices = fbxMesh.clusterIndices.size(); + QVector clusterIndices; + clusterIndices.resize(numIndices); + for (int32_t i = 0; i < numIndices; ++i) { + assert(fbxMesh.clusterIndices[i] <= UINT8_MAX); + clusterIndices[i] = (uint8_t)(fbxMesh.clusterIndices[i]); + } + vertBuffer->setSubData(clusterIndicesOffset, clusterIndicesSize, (const gpu::Byte*) clusterIndices.constData()); + } else { + vertBuffer->setSubData(clusterIndicesOffset, clusterIndicesSize, (const gpu::Byte*) fbxMesh.clusterIndices.constData()); } - attribBuffer->setSubData(clusterIndicesOffset, clusterIndicesSize, (const gpu::Byte*) clusterIndices.constData()); - } else { - attribBuffer->setSubData(clusterIndicesOffset, clusterIndicesSize, (const gpu::Byte*) fbxMesh.clusterIndices.constData()); } - attribBuffer->setSubData(clusterWeightsOffset, clusterWeightsSize, (const gpu::Byte*) fbxMesh.clusterWeights.constData()); + if (clusterWeightsSize > 0) { + vertBuffer->setSubData(clusterWeightsOffset, clusterWeightsSize, (const gpu::Byte*) fbxMesh.clusterWeights.constData()); + } - if (normalsSize) { - mesh->addAttribute(gpu::Stream::NORMAL, - graphics::BufferView(attribBuffer, normalsOffset, normalsAndTangentsSize, - normalsAndTangentsStride, FBX_NORMAL_ELEMENT)); - mesh->addAttribute(gpu::Stream::TANGENT, - graphics::BufferView(attribBuffer, tangentsOffset, normalsAndTangentsSize, - normalsAndTangentsStride, FBX_NORMAL_ELEMENT)); + + // Now we decide on how to interleave the attributes and provide the vertices among bufers: + // Aka the Vertex format and the vertexBufferStream + auto vertexFormat = std::make_shared(); + auto vertexBufferStream = std::make_shared(); + + // Decision time: + // if blendshapes then keep position and normals/tangents as separated channel buffers from interleaved attributes + // else everything is interleaved in one buffer + + // Default case is no blend shapes + gpu::BufferPointer attribBuffer; + int totalAttribBufferSize = totalVertsSize; + gpu::uint8 posChannel = 0; + gpu::uint8 tangentChannel = posChannel; + gpu::uint8 attribChannel = posChannel; + bool interleavePositions = true; + bool interleaveNormalsTangents = true; + + // TODO: We are using the same vertex format layout for all meshes because this is more efficient + // This work is going into rc73 release which is meant to be used for the SPot500 event and we are picking the format + // that works best for blendshaped and skinned meshes aka the avatars. + // We will improve this technique in a hot fix to 73. + hasBlendShapes = true; + + // If has blend shapes allocate and assign buffers for pos and tangents now + if (hasBlendShapes) { + auto posBuffer = std::make_shared(); + posBuffer->setData(positionsSize, (const gpu::Byte*) vertBuffer->getData() + positionsOffset); + vertexBufferStream->addBuffer(posBuffer, 0, positionElement.getSize()); + + auto normalsAndTangentsBuffer = std::make_shared(); + normalsAndTangentsBuffer->setData(normalsAndTangentsSize, (const gpu::Byte*) vertBuffer->getData() + normalsAndTangentsOffset); + vertexBufferStream->addBuffer(normalsAndTangentsBuffer, 0, normalsAndTangentsStride); + + // update channels and attribBuffer size accordingly + interleavePositions = false; + interleaveNormalsTangents = false; + + tangentChannel = 1; + attribChannel = 2; + + totalAttribBufferSize = totalVertsSize - positionsSize - normalsAndTangentsSize; } + + // Define the vertex format, compute the offset for each attributes as we append them to the vertex format + gpu::Offset bufOffset = 0; + if (positionsSize) { + vertexFormat->setAttribute(gpu::Stream::POSITION, posChannel, positionElement, bufOffset); + bufOffset += positionElement.getSize(); + if (!interleavePositions) { + bufOffset = 0; + } + } + if (normalsSize) { + vertexFormat->setAttribute(gpu::Stream::NORMAL, tangentChannel, normalElement, bufOffset); + bufOffset += normalElement.getSize(); + vertexFormat->setAttribute(gpu::Stream::TANGENT, tangentChannel, normalElement, bufOffset); + bufOffset += normalElement.getSize(); + if (!interleaveNormalsTangents) { + bufOffset = 0; + } + } + + // Pack normal and Tangent with the rest of atributes if no blend shapes if (colorsSize) { - mesh->addAttribute(gpu::Stream::COLOR, - graphics::BufferView(attribBuffer, colorsOffset, colorsSize, FBX_COLOR_ELEMENT)); + vertexFormat->setAttribute(gpu::Stream::COLOR, attribChannel, colorElement, bufOffset); + bufOffset += colorElement.getSize(); } if (texCoordsSize) { - mesh->addAttribute(gpu::Stream::TEXCOORD, - graphics::BufferView( attribBuffer, texCoordsOffset, texCoordsSize, - gpu::Element(gpu::VEC2, gpu::HALF, gpu::UV))); + vertexFormat->setAttribute(gpu::Stream::TEXCOORD, attribChannel, texCoordsElement, bufOffset); + bufOffset += texCoordsElement.getSize(); } if (texCoords1Size) { - mesh->addAttribute( gpu::Stream::TEXCOORD1, - graphics::BufferView(attribBuffer, texCoords1Offset, texCoords1Size, - gpu::Element(gpu::VEC2, gpu::HALF, gpu::UV))); + vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, attribChannel, texCoordsElement, bufOffset); + bufOffset += texCoordsElement.getSize(); } else if (texCoordsSize) { - mesh->addAttribute(gpu::Stream::TEXCOORD1, - graphics::BufferView(attribBuffer, texCoordsOffset, texCoordsSize, - gpu::Element(gpu::VEC2, gpu::HALF, gpu::UV))); + vertexFormat->setAttribute(gpu::Stream::TEXCOORD1, attribChannel, texCoordsElement, bufOffset - texCoordsElement.getSize()); } - if (clusterIndicesSize) { - if (fbxMesh.clusters.size() < UINT8_MAX) { - mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, - graphics::BufferView(attribBuffer, clusterIndicesOffset, clusterIndicesSize, - gpu::Element(gpu::VEC4, gpu::UINT8, gpu::XYZW))); - } else { - mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, - graphics::BufferView(attribBuffer, clusterIndicesOffset, clusterIndicesSize, - gpu::Element(gpu::VEC4, gpu::UINT16, gpu::XYZW))); - } + vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, attribChannel, clusterIndiceElement, bufOffset); + bufOffset += clusterIndiceElement.getSize(); } if (clusterWeightsSize) { - mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, - graphics::BufferView(attribBuffer, clusterWeightsOffset, clusterWeightsSize, - gpu::Element(gpu::VEC4, gpu::NUINT16, gpu::XYZW))); + vertexFormat->setAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, attribChannel, clusterWeightElement, bufOffset); + bufOffset += clusterWeightElement.getSize(); } + // Finally, allocate and fill the attribBuffer interleaving the attributes as needed: + { + auto vPositionOffset = 0; + auto vPositionSize = (interleavePositions ? positionsSize / numVerts : 0); + auto vNormalsAndTangentsOffset = vPositionOffset + vPositionSize; + auto vNormalsAndTangentsSize = (interleaveNormalsTangents ? normalsAndTangentsSize / numVerts : 0); + + auto vColorOffset = vNormalsAndTangentsOffset + vNormalsAndTangentsSize; + auto vColorSize = colorsSize / numVerts; + + auto vTexcoord0Offset = vColorOffset + vColorSize; + auto vTexcoord0Size = texCoordsSize / numVerts; + + auto vTexcoord1Offset = vTexcoord0Offset + vTexcoord0Size; + auto vTexcoord1Size = texCoords1Size / numVerts; + + auto vClusterIndiceOffset = vTexcoord1Offset + vTexcoord1Size; + auto vClusterIndiceSize = clusterIndicesSize / numVerts; + + auto vClusterWeightOffset = vClusterIndiceOffset + vClusterIndiceSize; + auto vClusterWeightSize = clusterWeightsSize / numVerts; + + auto vStride = vClusterWeightOffset + vClusterWeightSize; + + std::vector dest; + dest.resize(totalAttribBufferSize); + auto vDest = dest.data(); + + auto source = vertBuffer->getData(); + + for (int i = 0; i < numVerts; i++) { + + if (vPositionSize) memcpy(vDest + vPositionOffset, source + positionsOffset + i * vPositionSize, vPositionSize); + if (vNormalsAndTangentsSize) memcpy(vDest + vNormalsAndTangentsOffset, source + normalsAndTangentsOffset + i * vNormalsAndTangentsSize, vNormalsAndTangentsSize); + if (vColorSize) memcpy(vDest + vColorOffset, source + colorsOffset + i * vColorSize, vColorSize); + if (vTexcoord0Size) memcpy(vDest + vTexcoord0Offset, source + texCoordsOffset + i * vTexcoord0Size, vTexcoord0Size); + if (vTexcoord1Size) memcpy(vDest + vTexcoord1Offset, source + texCoords1Offset + i * vTexcoord1Size, vTexcoord1Size); + if (vClusterIndiceSize) memcpy(vDest + vClusterIndiceOffset, source + clusterIndicesOffset + i * vClusterIndiceSize, vClusterIndiceSize); + if (vClusterWeightSize) memcpy(vDest + vClusterWeightOffset, source + clusterWeightsOffset + i * vClusterWeightSize, vClusterWeightSize); + + vDest += vStride; + } + + auto attribBuffer = std::make_shared(); + attribBuffer->setData(totalAttribBufferSize, dest.data()); + vertexBufferStream->addBuffer(attribBuffer, 0, vStride); + } + + // Mesh vertex format and vertex stream is ready + mesh->setVertexFormatAndStream(vertexFormat, vertexBufferStream); + + // Index and Part Buffers unsigned int totalIndices = 0; foreach(const FBXMeshPart& part, extractedMesh.parts) { totalIndices += (part.quadTrianglesIndices.size() + part.triangleIndices.size()); diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index aeef3b1ad7..28b5550553 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -240,6 +240,7 @@ public: virtual GLuint getFramebufferID(const FramebufferPointer& framebuffer) = 0; virtual GLuint getTextureID(const TexturePointer& texture) final; virtual GLuint getBufferID(const Buffer& buffer) = 0; + virtual GLuint getBufferIDUnsynced(const Buffer& buffer) = 0; virtual GLuint getQueryID(const QueryPointer& query) = 0; virtual GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) = 0; diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendInput.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendInput.cpp index 77e1f90f66..8d46b4c6e3 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendInput.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendInput.cpp @@ -11,6 +11,7 @@ #include "GLBackend.h" #include "GLShared.h" #include "GLInputFormat.h" +#include "GLBuffer.h" using namespace gpu; using namespace gpu::gl; @@ -43,13 +44,7 @@ void GLBackend::do_setInputBuffer(const Batch& batch, size_t paramOffset) { bool isModified = false; if (_input._buffers[channel] != buffer) { _input._buffers[channel] = buffer; - - GLuint vbo = 0; - if (buffer) { - vbo = getBufferID((*buffer)); - } - _input._bufferVBOs[channel] = vbo; - + _input._bufferVBOs[channel] = getBufferIDUnsynced((*buffer)); isModified = true; } @@ -128,7 +123,7 @@ void GLBackend::do_setIndexBuffer(const Batch& batch, size_t paramOffset) { if (indexBuffer != _input._indexBuffer) { _input._indexBuffer = indexBuffer; if (indexBuffer) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferID(*indexBuffer)); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, getBufferIDUnsynced(*indexBuffer)); } else { // FIXME do we really need this? Is there ever a draw call where we care that the element buffer is null? glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); @@ -145,7 +140,7 @@ void GLBackend::do_setIndirectBuffer(const Batch& batch, size_t paramOffset) { if (buffer != _input._indirectBuffer) { _input._indirectBuffer = buffer; if (buffer) { - glBindBuffer(GL_DRAW_INDIRECT_BUFFER, getBufferID(*buffer)); + glBindBuffer(GL_DRAW_INDIRECT_BUFFER, getBufferIDUnsynced(*buffer)); } else { // FIXME do we really need this? Is there ever a draw call where we care that the element buffer is null? glBindBuffer(GL_DRAW_INDIRECT_BUFFER, 0); @@ -261,9 +256,17 @@ void GLBackend::updateInput() { auto offset = _input._bufferOffsets.data(); auto stride = _input._bufferStrides.data(); + // Profile the count of buffers to update and use it to short cut the for loop + int numInvalids = (int) _input._invalidBuffers.count(); + _stats._ISNumInputBufferChanges += numInvalids; + for (GLuint buffer = 0; buffer < _input._buffers.size(); buffer++, vbo++, offset++, stride++) { if (_input._invalidBuffers.test(buffer)) { glBindVertexBuffer(buffer, (*vbo), (*offset), (GLsizei)(*stride)); + numInvalids--; + if (numInvalids <= 0) { + break; + } } } diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp index d3d2bc0938..05ded3eece 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp @@ -85,6 +85,8 @@ void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) { auto& cameraCorrectionBuffer = _transform._viewCorrectionEnabled ? _pipeline._cameraCorrectionBuffer._buffer : _pipeline._cameraCorrectionBufferIdentity._buffer; + // Because we don't sync Buffers in the bindUniformBuffer, let s force this buffer synced + getBufferID(*cameraCorrectionBuffer); bindUniformBuffer(gpu::slot::buffer::CameraCorrection, cameraCorrectionBuffer, 0, sizeof(CameraCorrection)); } (void)CHECK_GL_ERROR(); @@ -170,11 +172,10 @@ void GLBackend::bindUniformBuffer(uint32_t slot, const BufferPointer& buffer, GL return; } - // Sync BufferObject - auto* object = syncGPUObject(*bufferState.buffer); - if (object) { - glBindBufferRange(GL_UNIFORM_BUFFER, slot, object->_buffer, bufferState.offset, bufferState.size); - + // Grab the true gl Buffer object + auto glBO = getBufferIDUnsynced(*buffer); + if (glBO) { + glBindBufferRange(GL_UNIFORM_BUFFER, slot, glBO, bufferState.offset, bufferState.size); _uniform._buffers[slot] = bufferState; (void)CHECK_GL_ERROR(); } else { diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBuffer.h b/libraries/gpu-gl-common/src/gpu/gl/GLBuffer.h index 182014e764..6b7d3405f0 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBuffer.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBuffer.h @@ -49,6 +49,16 @@ public: } } + template + static GLuint getIdUnsynced(GLBackend& backend, const Buffer& buffer) { + GLBufferType* object = Backend::getGPUObject(buffer); + if (object) { + return object->_buffer; + } else { + return 0; + } + } + const GLuint& _buffer { _id }; const GLuint _size; const Stamp _stamp; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index d277e9c026..c5c69259f0 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -137,6 +137,7 @@ protected: GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override; GLuint getBufferID(const Buffer& buffer) override; + GLuint getBufferIDUnsynced(const Buffer& buffer) override; GLuint getResourceBufferID(const Buffer& buffer); GLBuffer* syncGPUObject(const Buffer& buffer) override; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendBuffer.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendBuffer.cpp index 62ade673b4..ac5d5ee0c9 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendBuffer.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendBuffer.cpp @@ -83,6 +83,10 @@ GLuint GL41Backend::getBufferID(const Buffer& buffer) { return GL41Buffer::getId(*this, buffer); } +GLuint GL41Backend::getBufferIDUnsynced(const Buffer& buffer) { + return GL41Buffer::getIdUnsynced(*this, buffer); +} + GLuint GL41Backend::getResourceBufferID(const Buffer& buffer) { auto* object = GL41Buffer::sync(*this, buffer); if (object) { diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp index 9dcb08f0b7..c61ffb09e5 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp @@ -78,8 +78,9 @@ void GL41Backend::updateInput() { const Stream::Format::AttributeMap& attributes = _input._format->getAttributes(); auto& inputChannels = _input._format->getChannels(); - _stats._ISNumInputBufferChanges++; - + int numInvalids = (int)_input._invalidBuffers.count(); + _stats._ISNumInputBufferChanges += numInvalids; + GLuint boundVBO = 0; for (auto& channelIt : inputChannels) { const Stream::Format::ChannelMap::value_type::second_type& channel = (channelIt).second; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 1932be356f..54a659ebba 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -236,6 +236,7 @@ protected: GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override; GLuint getBufferID(const Buffer& buffer) override; + GLuint getBufferIDUnsynced(const Buffer& buffer) override; GLBuffer* syncGPUObject(const Buffer& buffer) override; GLTexture* syncGPUObject(const TexturePointer& texture) override; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendBuffer.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendBuffer.cpp index 2afbea3876..6d17923ebd 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendBuffer.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendBuffer.cpp @@ -51,6 +51,10 @@ GLuint GL45Backend::getBufferID(const Buffer& buffer) { return GL45Buffer::getId(*this, buffer); } +GLuint GL45Backend::getBufferIDUnsynced(const Buffer& buffer) { + return GL45Buffer::getIdUnsynced(*this, buffer); +} + GLBuffer* GL45Backend::syncGPUObject(const Buffer& buffer) { return GL45Buffer::sync(*this, buffer); } diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp index cc3e609bda..7cd8756ead 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp @@ -132,9 +132,18 @@ void GL45Backend::updateInput() { auto offset = _input._bufferOffsets.data(); auto stride = _input._bufferStrides.data(); - for (GLuint buffer = 0; buffer < _input._buffers.size(); buffer++, vbo++, offset++, stride++) { + // Profile the count of buffers to update and use it to short cut the for loop + int numInvalids = (int) _input._invalidBuffers.count(); + _stats._ISNumInputBufferChanges += numInvalids; + + auto numBuffers = _input._buffers.size(); + for (GLuint buffer = 0; buffer < numBuffers; buffer++, vbo++, offset++, stride++) { if (_input._invalidBuffers.test(buffer)) { glBindVertexBuffer(buffer, (*vbo), (*offset), (GLsizei)(*stride)); + numInvalids--; + if (numInvalids <= 0) { + break; + } } } diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackend.h b/libraries/gpu-gles/src/gpu/gles/GLESBackend.h index 785f4c3ef9..c757de0a72 100644 --- a/libraries/gpu-gles/src/gpu/gles/GLESBackend.h +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackend.h @@ -130,6 +130,7 @@ protected: GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override; GLuint getBufferID(const Buffer& buffer) override; + GLuint getBufferIDUnsynced(const Buffer& buffer) override; GLuint getResourceBufferID(const Buffer& buffer); GLBuffer* syncGPUObject(const Buffer& buffer) override; diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackendBuffer.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackendBuffer.cpp index 17fdad8377..7dd08df409 100644 --- a/libraries/gpu-gles/src/gpu/gles/GLESBackendBuffer.cpp +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackendBuffer.cpp @@ -64,6 +64,10 @@ GLuint GLESBackend::getBufferID(const Buffer& buffer) { return GLESBuffer::getId(*this, buffer); } +GLuint GLESBackend::getBufferIDUnsynced(const Buffer& buffer) { + return GLESBuffer::getIdUnsynced(*this, buffer); +} + GLBuffer* GLESBackend::syncGPUObject(const Buffer& buffer) { return GLESBuffer::sync(*this, buffer); } diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index b2d978c0d7..66365c8518 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -420,10 +420,7 @@ public: } const Data& get(uint32 offset) const { - if (offset >= _items.size()) { - static const Data EMPTY; - return EMPTY; - } + assert((offset < _items.size())); return (_items.data() + offset)->_data; } diff --git a/libraries/gpu/src/gpu/Color.slh b/libraries/gpu/src/gpu/Color.slh index 384b8bd329..16eb7487ed 100644 --- a/libraries/gpu/src/gpu/Color.slh +++ b/libraries/gpu/src/gpu/Color.slh @@ -31,29 +31,29 @@ vec4 color_sRGBAToLinear(vec4 srgba) { } vec3 color_LinearToYCoCg(vec3 rgb) { - // Y = R/4 + G/2 + B/4 - // Co = R/2 - B/2 - // Cg = -R/4 + G/2 - B/4 - return vec3( - rgb.x/4.0 + rgb.y/2.0 + rgb.z/4.0, - rgb.x/2.0 - rgb.z/2.0, - -rgb.x/4.0 + rgb.y/2.0 - rgb.z/4.0 - ); + // Y = R/4 + G/2 + B/4 + // Co = R/2 - B/2 + // Cg = -R/4 + G/2 - B/4 + return vec3( + rgb.x/4.0 + rgb.y/2.0 + rgb.z/4.0, + rgb.x/2.0 - rgb.z/2.0, + -rgb.x/4.0 + rgb.y/2.0 - rgb.z/4.0 + ); } vec3 color_YCoCgToUnclampedLinear(vec3 ycocg) { - // R = Y + Co - Cg - // G = Y + Cg - // B = Y - Co - Cg - return vec3( - ycocg.x + ycocg.y - ycocg.z, - ycocg.x + ycocg.z, - ycocg.x - ycocg.y - ycocg.z - ); + // R = Y + Co - Cg + // G = Y + Cg + // B = Y - Co - Cg + return vec3( + ycocg.x + ycocg.y - ycocg.z, + ycocg.x + ycocg.z, + ycocg.x - ycocg.y - ycocg.z + ); } vec3 color_YCoCgToLinear(vec3 ycocg) { - return clamp(color_YCoCgToUnclampedLinear(ycocg), vec3(0.0), vec3(1.0)); + return clamp(color_YCoCgToUnclampedLinear(ycocg), vec3(0.0), vec3(1.0)); } <@func declareColorWheel()@> diff --git a/libraries/gpu/src/gpu/DrawColor.slf b/libraries/gpu/src/gpu/DrawColor.slf index 2540d56d69..fdea26fa68 100644 --- a/libraries/gpu/src/gpu/DrawColor.slf +++ b/libraries/gpu/src/gpu/DrawColor.slf @@ -13,12 +13,16 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include gpu/ShaderConstants.h@> +struct DrawColorParams { + vec4 color; +}; -layout(location=GPU_UNIFORM_COLOR) uniform vec4 color; +layout(binding=0) uniform drawColorParamsBuffer { + DrawColorParams params; +}; layout(location=0) out vec4 outFragColor; void main(void) { - outFragColor = color; + outFragColor = params.color; } diff --git a/libraries/gpu/src/gpu/DrawColoredTexture.slf b/libraries/gpu/src/gpu/DrawColoredTexture.slf index 632bf18391..0fe3707b1c 100755 --- a/libraries/gpu/src/gpu/DrawColoredTexture.slf +++ b/libraries/gpu/src/gpu/DrawColoredTexture.slf @@ -13,14 +13,19 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include gpu/ShaderConstants.h@> - layout(binding=0) uniform sampler2D colorMap; -layout(location=GPU_UNIFORM_COLOR) uniform vec4 color; + +struct DrawColorParams { + vec4 color; +}; + +layout(binding=0) uniform drawColorParams { + DrawColorParams params; +}; layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; void main(void) { - outFragColor = texture(colorMap, varTexCoord0) * color; + outFragColor = texture(colorMap, varTexCoord0) * params.color; } diff --git a/libraries/gpu/src/gpu/DrawTexcoordRectTransformUnitQuad.slv b/libraries/gpu/src/gpu/DrawTexcoordRectTransformUnitQuad.slv index d401fc40c2..8849cb494a 100755 --- a/libraries/gpu/src/gpu/DrawTexcoordRectTransformUnitQuad.slv +++ b/libraries/gpu/src/gpu/DrawTexcoordRectTransformUnitQuad.slv @@ -21,7 +21,13 @@ <$declareStandardTransform()$> -layout(location=GPU_UNIFORM_TEXCOORD_RECT) uniform vec4 texcoordRect; +struct TexCoordRectParams { + vec4 texcoordRect; +}; + +layout(binding=0) uniform texcoordRectBuffer { + TexCoordRectParams params; +}; layout(location=0) out vec2 varTexCoord0; @@ -39,5 +45,5 @@ void main(void) { TransformObject obj = getTransformObject(); <$transformModelToClipPos(cam, obj, pos, gl_Position)$> - varTexCoord0 = ((pos.xy + 1.0) * 0.5) * texcoordRect.zw + texcoordRect.xy; + varTexCoord0 = ((pos.xy + 1.0) * 0.5) * params.texcoordRect.zw + params.texcoordRect.xy; } diff --git a/libraries/gpu/src/gpu/Noise.slh b/libraries/gpu/src/gpu/Noise.slh index b390945957..d300e71ba9 100644 --- a/libraries/gpu/src/gpu/Noise.slh +++ b/libraries/gpu/src/gpu/Noise.slh @@ -284,14 +284,14 @@ float hifi_noise(in vec2 x) { // https://www.shadertoy.com/view/MdX3Rr // https://en.wikipedia.org/wiki/Fractional_Brownian_motion float hifi_fbm(in vec2 p) { - const mat2 m2 = mat2(0.8, -0.6, 0.6, 0.8); - float f = 0.0; - f += 0.5000 * hifi_noise(p); p = m2 * p * 2.02; - f += 0.2500 * hifi_noise(p); p = m2 * p * 2.03; - f += 0.1250 * hifi_noise(p); p = m2 * p * 2.01; - f += 0.0625 * hifi_noise(p); + const mat2 m2 = mat2(0.8, -0.6, 0.6, 0.8); + float f = 0.0; + f += 0.5000 * hifi_noise(p); p = m2 * p * 2.02; + f += 0.2500 * hifi_noise(p); p = m2 * p * 2.03; + f += 0.1250 * hifi_noise(p); p = m2 * p * 2.01; + f += 0.0625 * hifi_noise(p); - return f / 0.9375; + return f / 0.9375; } <@endif@> \ No newline at end of file diff --git a/libraries/gpu/src/gpu/Paint.slh b/libraries/gpu/src/gpu/Paint.slh index 5f49b20b30..54a1214e12 100644 --- a/libraries/gpu/src/gpu/Paint.slh +++ b/libraries/gpu/src/gpu/Paint.slh @@ -17,7 +17,7 @@ float paintStripe(float value, float offset, float scale, float edge) { float width = fwidth(value); float normalizedWidth = width * scale; - float x0 = (value + offset) * scale - normalizedWidth / 2; + float x0 = (value + offset) * scale - normalizedWidth / 2.0; float x1 = x0 + normalizedWidth; float balance = 1.0 - edge; diff --git a/libraries/gpu/src/gpu/ShaderConstants.h b/libraries/gpu/src/gpu/ShaderConstants.h index d33383cc80..302c9f4994 100644 --- a/libraries/gpu/src/gpu/ShaderConstants.h +++ b/libraries/gpu/src/gpu/ShaderConstants.h @@ -43,8 +43,6 @@ // OSX seems to have an issue using 14 as an attribute location for passing from the vertex to the fragment shader #define GPU_ATTR_V2F_STEREO_SIDE 8 -#define GPU_UNIFORM_COLOR 101 -#define GPU_UNIFORM_TEXCOORD_RECT 102 #define GPU_UNIFORM_EXTRA0 110 #define GPU_UNIFORM_EXTRA1 111 #define GPU_UNIFORM_EXTRA2 112 @@ -102,8 +100,6 @@ enum Attribute { namespace uniform { enum Uniform { - Color = GPU_UNIFORM_COLOR, - TexCoordRect = GPU_UNIFORM_TEXCOORD_RECT, Extra0 = GPU_UNIFORM_EXTRA0, Extra1 = GPU_UNIFORM_EXTRA1, Extra2 = GPU_UNIFORM_EXTRA2, diff --git a/libraries/gpu/src/gpu/Stream.h b/libraries/gpu/src/gpu/Stream.h index 0def1ab201..2e1ed1d83c 100644 --- a/libraries/gpu/src/gpu/Stream.h +++ b/libraries/gpu/src/gpu/Stream.h @@ -152,6 +152,8 @@ public: BufferStream makeRangedStream(uint32 offset, uint32 count = -1) const; + BufferStream& operator = (const BufferStream& src) = default; + protected: Buffers _buffers; Offsets _offsets; diff --git a/libraries/gpu/src/gpu/TransformCamera_shared.slh b/libraries/gpu/src/gpu/TransformCamera_shared.slh index 37521d8201..e4a0f8c2cc 100644 --- a/libraries/gpu/src/gpu/TransformCamera_shared.slh +++ b/libraries/gpu/src/gpu/TransformCamera_shared.slh @@ -2,11 +2,11 @@ #ifdef __cplusplus # define _MAT4 Mat4 # define _VEC4 Vec4 -# define _MUTABLE mutable +# define _MUTABLE mutable #else # define _MAT4 mat4 # define _VEC4 vec4 -# define _MUTABLE +# define _MUTABLE #endif struct _TransformCamera { diff --git a/libraries/graphics/src/graphics/Geometry.cpp b/libraries/graphics/src/graphics/Geometry.cpp index d43c773249..a983ba07b4 100755 --- a/libraries/graphics/src/graphics/Geometry.cpp +++ b/libraries/graphics/src/graphics/Geometry.cpp @@ -32,6 +32,15 @@ Mesh::Mesh(const Mesh& mesh) : Mesh::~Mesh() { } +void Mesh::setVertexFormatAndStream(const gpu::Stream::FormatPointer& vf, const gpu::BufferStreamPointer& vbs) { + _vertexFormat = vf; + _vertexStream = (*vbs); + + auto attrib = _vertexFormat->getAttribute(gpu::Stream::POSITION); + _vertexBuffer = BufferView(vbs->getBuffers()[attrib._channel], vbs->getOffsets()[attrib._channel], vbs->getBuffers()[attrib._channel]->getSize(), + (gpu::uint16) vbs->getStrides()[attrib._channel], attrib._element); +} + void Mesh::setVertexBuffer(const BufferView& buffer) { _vertexBuffer = buffer; evalVertexFormat(); @@ -107,11 +116,10 @@ Box Mesh::evalPartBound(int partNum) const { index += part._startIndex; auto endIndex = index; endIndex += part._numIndices; - auto vertices = &_vertexBuffer.get(part._baseVertex); for (;index != endIndex; index++) { // skip primitive restart indices if ((*index) != PRIMITIVE_RESTART_INDEX) { - box += vertices[(*index)]; + box += _vertexBuffer.get(part._baseVertex + (*index)); } } } @@ -128,11 +136,10 @@ Box Mesh::evalPartsBound(int partStart, int partEnd) const { Box partBound; auto index = _indexBuffer.cbegin() + (*part)._startIndex; auto endIndex = index + (*part)._numIndices; - auto vertices = &_vertexBuffer.get((*part)._baseVertex); for (;index != endIndex; index++) { // skip primitive restart indices if ((*index) != (uint) PRIMITIVE_RESTART_INDEX) { - partBound += vertices[(*index)]; + partBound += _vertexBuffer.get((*part)._baseVertex + (*index)); } } diff --git a/libraries/graphics/src/graphics/Geometry.h b/libraries/graphics/src/graphics/Geometry.h index eddfdbd1b6..20018ba71b 100755 --- a/libraries/graphics/src/graphics/Geometry.h +++ b/libraries/graphics/src/graphics/Geometry.h @@ -59,6 +59,9 @@ public: void removeAttribute(Slot slot); const BufferView getAttributeBuffer(int attrib) const; + // Force vertex stream and Vertex format + void setVertexFormatAndStream(const gpu::Stream::FormatPointer& vf, const gpu::BufferStreamPointer& vbs); + // Stream format const gpu::Stream::FormatPointer getVertexFormat() const { return _vertexFormat; } diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index b6b2369703..db6ed15792 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -56,13 +56,20 @@ LimitedNodeList::LimitedNodeList(int socketListenPort, int dtlsListenPort) : qRegisterMetaType("ConnectionStep"); auto port = (socketListenPort != INVALID_PORT) ? socketListenPort : LIMITED_NODELIST_LOCAL_PORT.get(); _nodeSocket.bind(QHostAddress::AnyIPv4, port); - qCDebug(networking) << "NodeList socket is listening on" << _nodeSocket.localPort(); + quint16 assignedPort = _nodeSocket.localPort(); + if (socketListenPort != INVALID_PORT && socketListenPort != 0 && socketListenPort != assignedPort) { + qCCritical(networking) << "NodeList is unable to assign requested port of" << socketListenPort; + } + qCDebug(networking) << "NodeList socket is listening on" << assignedPort; if (dtlsListenPort != INVALID_PORT) { // only create the DTLS socket during constructor if a custom port is passed _dtlsSocket = new QUdpSocket(this); _dtlsSocket->bind(QHostAddress::AnyIPv4, dtlsListenPort); + if (dtlsListenPort != 0 && _dtlsSocket->localPort() != dtlsListenPort) { + qCDebug(networking) << "NodeList is unable to assign requested DTLS port of" << dtlsListenPort; + } qCDebug(networking) << "NodeList DTLS socket is listening on" << _dtlsSocket->localPort(); } diff --git a/libraries/procedural/src/procedural/ShaderConstants.h b/libraries/procedural/src/procedural/ShaderConstants.h index 1995996c97..bfbf2a2691 100644 --- a/libraries/procedural/src/procedural/ShaderConstants.h +++ b/libraries/procedural/src/procedural/ShaderConstants.h @@ -14,7 +14,6 @@ #ifndef PROCEDURAL_SHADER_CONSTANTS_H #define PROCEDURAL_SHADER_CONSTANTS_H -// Polyvox #define PROCEDURAL_UNIFORM_TIME 200 #define PROCEDURAL_UNIFORM_DATE 201 #define PROCEDURAL_UNIFORM_FRAME_COUNT 202 diff --git a/libraries/render-utils/src/AntialiasingEffect.cpp b/libraries/render-utils/src/AntialiasingEffect.cpp index 2b17ba3c01..17c13df19a 100644 --- a/libraries/render-utils/src/AntialiasingEffect.cpp +++ b/libraries/render-utils/src/AntialiasingEffect.cpp @@ -29,7 +29,6 @@ namespace ru { - using render_utils::slot::uniform::Uniform; using render_utils::slot::texture::Texture; using render_utils::slot::buffer::Buffer; } @@ -39,13 +38,7 @@ namespace gr { using graphics::slot::buffer::Buffer; } -#define ANTIALIASING_USE_TAA 1 - #if !ANTIALIASING_USE_TAA -#include "fxaa_vert.h" -#include "fxaa_frag.h" -#include "fxaa_blend_frag.h" - Antialiasing::Antialiasing() { _geometryId = DependencyManager::get()->allocateID(); @@ -58,30 +51,9 @@ Antialiasing::~Antialiasing() { } } -const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline(RenderArgs* args) { - int width = args->_viewport.z; - int height = args->_viewport.w; - - if (_antialiasingBuffer && _antialiasingBuffer->getSize() != uvec2(width, height)) { - _antialiasingBuffer.reset(); - } - - if (!_antialiasingBuffer) { - // Link the antialiasing FBO to texture - _antialiasingBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("antialiasing")); - auto format = gpu::Element::COLOR_SRGBA_32; - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); - _antialiasingTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, defaultSampler); - _antialiasingBuffer->setRenderBuffer(0, _antialiasingTexture); - } - +const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline() { if (!_antialiasingPipeline) { - auto vs = fxaa_vert::getShader(); - auto ps = fxaa_frag::getShader(); - gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - - _texcoordOffsetLoc = program->getUniforms().findLocation("texcoordOffset"); - + gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::fxaa); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setDepthTest(false, false, gpu::LESS_EQUAL); @@ -96,9 +68,7 @@ const gpu::PipelinePointer& Antialiasing::getAntialiasingPipeline(RenderArgs* ar const gpu::PipelinePointer& Antialiasing::getBlendPipeline() { if (!_blendPipeline) { - auto vs = fxaa_vert::getShader(); - auto ps = fxaa_blend_frag::getShader(); - gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); + gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::fxaa_blend); gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setDepthTest(false, false, gpu::LESS_EQUAL); PrepareStencil::testNoAA(*state); @@ -119,13 +89,30 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const batch.enableStereo(false); batch.setViewportTransform(args->_viewport); - // FIXME: NEED to simplify that code to avoid all the GeometryCahce call, this is purely pixel manipulation - float fbWidth = renderContext->args->_viewport.z; - float fbHeight = renderContext->args->_viewport.w; - // float sMin = args->_viewport.x / fbWidth; - // float sWidth = args->_viewport.z / fbWidth; - // float tMin = args->_viewport.y / fbHeight; - // float tHeight = args->_viewport.w / fbHeight; + if (!_paramsBuffer) { + _paramsBuffer = std::make_shared(sizeof(glm::vec4), nullptr); + } + + { + int width = args->_viewport.z; + int height = args->_viewport.w; + if (_antialiasingBuffer && _antialiasingBuffer->getSize() != uvec2(width, height)) { + _antialiasingBuffer.reset(); + } + + if (!_antialiasingBuffer) { + // Link the antialiasing FBO to texture + _antialiasingBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("antialiasing")); + auto format = gpu::Element::COLOR_SRGBA_32; + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); + _antialiasingTexture = gpu::Texture::createRenderBuffer(format, width, height, gpu::Texture::SINGLE_MIP, defaultSampler); + _antialiasingBuffer->setRenderBuffer(0, _antialiasingTexture); + glm::vec2 fbExtent { args->_viewport.z, args->_viewport.w }; + glm::vec2 inverseFbExtent = 1.0f / fbExtent; + _paramsBuffer->setSubData(0, glm::vec4(inverseFbExtent, 0.0, 0.0)); + } + } + glm::mat4 projMat; Transform viewMat; @@ -136,40 +123,18 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const batch.setModelTransform(Transform()); // FXAA step - auto pipeline = getAntialiasingPipeline(renderContext->args); + auto pipeline = getAntialiasingPipeline(); batch.setResourceTexture(0, sourceBuffer->getRenderBuffer(0)); batch.setFramebuffer(_antialiasingBuffer); batch.setPipeline(pipeline); - - // initialize the view-space unpacking uniforms using frustum data - float left, right, bottom, top, nearVal, farVal; - glm::vec4 nearClipPlane, farClipPlane; - - args->getViewFrustum().computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); - - // float depthScale = (farVal - nearVal) / farVal; - // float nearScale = -1.0f / nearVal; - // float depthTexCoordScaleS = (right - left) * nearScale / sWidth; - // float depthTexCoordScaleT = (top - bottom) * nearScale / tHeight; - // float depthTexCoordOffsetS = left * nearScale - sMin * depthTexCoordScaleS; - // float depthTexCoordOffsetT = bottom * nearScale - tMin * depthTexCoordScaleT; - - batch._glUniform2f(_texcoordOffsetLoc, 1.0f / fbWidth, 1.0f / fbHeight); - - glm::vec4 color(0.0f, 0.0f, 0.0f, 1.0f); - glm::vec2 bottomLeft(-1.0f, -1.0f); - glm::vec2 topRight(1.0f, 1.0f); - glm::vec2 texCoordTopLeft(0.0f, 0.0f); - glm::vec2 texCoordBottomRight(1.0f, 1.0f); - DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color, _geometryId); - + batch.setUniformBuffer(0, _paramsBuffer); + batch.draw(gpu::TRIANGLE_STRIP, 4); // Blend step batch.setResourceTexture(0, _antialiasingTexture); batch.setFramebuffer(sourceBuffer); batch.setPipeline(getBlendPipeline()); - - DependencyManager::get()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color, _geometryId); + batch.draw(gpu::TRIANGLE_STRIP, 4); }); } #else @@ -314,7 +279,11 @@ void Antialiasing::run(const render::RenderContextPointer& renderContext, const // Must match the bindg point in the fxaa_blend.slf shader batch.setResourceFramebufferSwapChainTexture(0, _antialiasingBuffers, 1); // Disable sharpen if FXAA - batch._glUniform1f(ru::Uniform::TaaSharpenIntensity, _sharpen * _params.get().regionInfo.z); + if (!_blendParamsBuffer) { + _blendParamsBuffer = std::make_shared(sizeof(glm::vec4), nullptr); + } + _blendParamsBuffer->setSubData(0, _sharpen * _params.get().regionInfo.z); + batch.setUniformBuffer(0, _blendParamsBuffer); } batch.draw(gpu::TRIANGLE_STRIP, 4); batch.advance(_antialiasingBuffers); diff --git a/libraries/render-utils/src/AntialiasingEffect.h b/libraries/render-utils/src/AntialiasingEffect.h index 61da352154..936ade043d 100644 --- a/libraries/render-utils/src/AntialiasingEffect.h +++ b/libraries/render-utils/src/AntialiasingEffect.h @@ -134,6 +134,10 @@ signals: #define SET_BIT(bitfield, bitIndex, value) bitfield = ((bitfield) & ~(1 << (bitIndex))) | ((value) << (bitIndex)) #define GET_BIT(bitfield, bitIndex) ((bitfield) & (1 << (bitIndex))) +#define ANTIALIASING_USE_TAA 1 + +#if ANTIALIASING_USE_TAA + struct TAAParams { float nope{ 0.0f }; float blend{ 0.15f }; @@ -186,7 +190,7 @@ private: gpu::FramebufferSwapChainPointer _antialiasingBuffers; gpu::TexturePointer _antialiasingTextures[2]; - + gpu::BufferPointer _blendParamsBuffer; gpu::PipelinePointer _antialiasingPipeline; gpu::PipelinePointer _blendPipeline; gpu::PipelinePointer _debugBlendPipeline; @@ -197,7 +201,7 @@ private: }; -/* +#else class AntiAliasingConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(bool enabled MEMBER enabled) @@ -219,18 +223,15 @@ public: const gpu::PipelinePointer& getBlendPipeline(); private: - - // Uniforms for AA - gpu::int32 _texcoordOffsetLoc; - gpu::FramebufferPointer _antialiasingBuffer; gpu::TexturePointer _antialiasingTexture; + gpu::BufferPointer _paramsBuffer; gpu::PipelinePointer _antialiasingPipeline; gpu::PipelinePointer _blendPipeline; int _geometryId { 0 }; }; -*/ +#endif #endif // hifi_AntialiasingEffect_h diff --git a/libraries/render-utils/src/BloomEffect.cpp b/libraries/render-utils/src/BloomEffect.cpp index 3a35e736a9..e6217eb825 100644 --- a/libraries/render-utils/src/BloomEffect.cpp +++ b/libraries/render-utils/src/BloomEffect.cpp @@ -184,6 +184,7 @@ void BloomDraw::run(const render::RenderContextPointer& renderContext, const Inp } DebugBloom::DebugBloom() { + _params = std::make_shared(sizeof(glm::vec4), nullptr); } void DebugBloom::configure(const Config& config) { @@ -227,7 +228,8 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In Transform modelTransform; if (_mode == DebugBloomConfig::MODE_ALL_LEVELS) { - batch._glUniform4f(gpu::slot::uniform::TexCoordRect, 0.0f, 0.0f, 1.f, 1.f); + _params->setSubData(0, vec4(0.0f, 0.0f, 1.f, 1.f)); + batch.setUniformBuffer(0, _params); modelTransform = gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, args->_viewport / 2); modelTransform.postTranslate(glm::vec3(-1.0f, 1.0f, 0.0f)); @@ -255,7 +257,8 @@ void DebugBloom::run(const render::RenderContextPointer& renderContext, const In viewport.z /= 2; - batch._glUniform4f(gpu::slot::uniform::TexCoordRect, 0.5f, 0.0f, 0.5f, 1.f); + _params->setSubData(0, vec4(0.5f, 0.0f, 0.5f, 1.f)); + batch.setUniformBuffer(0, _params); modelTransform = gpu::Framebuffer::evalSubregionTexcoordTransform(framebufferSize, viewport); modelTransform.postTranslate(glm::vec3(-1.0f, 0.0f, 0.0f)); diff --git a/libraries/render-utils/src/BloomEffect.h b/libraries/render-utils/src/BloomEffect.h index 7789c70190..12c94bb929 100644 --- a/libraries/render-utils/src/BloomEffect.h +++ b/libraries/render-utils/src/BloomEffect.h @@ -121,6 +121,7 @@ public: private: gpu::PipelinePointer _pipeline; + gpu::BufferPointer _params; DebugBloomConfig::Mode _mode; }; diff --git a/libraries/render-utils/src/BloomThreshold.shared.slh b/libraries/render-utils/src/BloomThreshold.shared.slh index 8aaf8ec311..5ad490a1ca 100644 --- a/libraries/render-utils/src/BloomThreshold.shared.slh +++ b/libraries/render-utils/src/BloomThreshold.shared.slh @@ -8,7 +8,7 @@ struct Parameters { BT_VEC2 _deltaUV; - float _threshold; + float _threshold; int _sampleCount; }; diff --git a/libraries/render-utils/src/BloomThreshold.slf b/libraries/render-utils/src/BloomThreshold.slf index 621aa31622..47a1fb0d9f 100644 --- a/libraries/render-utils/src/BloomThreshold.slf +++ b/libraries/render-utils/src/BloomThreshold.slf @@ -30,7 +30,7 @@ void main(void) { for (int x=0 ; x(); - if (triggerBlendshapes && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { + if (_blendedVertexBuffersInitialized && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { _blendedBlendshapeCoefficients = _blendshapeCoefficients; modelBlender->noteRequiresBlend(getThisPointer()); } diff --git a/libraries/render-utils/src/CauterizedModel.h b/libraries/render-utils/src/CauterizedModel.h index 12cf921e5b..36a96fb006 100644 --- a/libraries/render-utils/src/CauterizedModel.h +++ b/libraries/render-utils/src/CauterizedModel.h @@ -33,7 +33,7 @@ public: void createRenderItemSet() override; - virtual void updateClusterMatrices(bool triggerBlendshapes = true) override; + virtual void updateClusterMatrices() override; void updateRenderItems() override; const Model::MeshState& getCauterizeMeshState(int index) const; diff --git a/libraries/render-utils/src/DeferredBufferRead.slh b/libraries/render-utils/src/DeferredBufferRead.slh index 8c6c76b24a..e5a7c39d54 100644 --- a/libraries/render-utils/src/DeferredBufferRead.slh +++ b/libraries/render-utils/src/DeferredBufferRead.slh @@ -137,7 +137,7 @@ vec4 unpackDeferredPosition(float depthValue, vec2 texcoord) { // This method to unpack position is fastesst vec4 unpackDeferredPositionFromZdb(vec2 texcoord) { float Zdb = texture(depthMap, texcoord).x; - return unpackDeferredPosition(Zdb, texcoord); + return unpackDeferredPosition(Zdb, texcoord); } vec4 unpackDeferredPositionFromZeye(vec2 texcoord) { diff --git a/libraries/render-utils/src/DeferredFramebuffer.cpp b/libraries/render-utils/src/DeferredFramebuffer.cpp index 2df89b8808..1906375654 100644 --- a/libraries/render-utils/src/DeferredFramebuffer.cpp +++ b/libraries/render-utils/src/DeferredFramebuffer.cpp @@ -73,7 +73,7 @@ void DeferredFramebuffer::allocate() { _deferredFramebufferDepthColor->setDepthStencilBuffer(_primaryDepthTexture, depthFormat); - auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT); + auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR_MIP_POINT, gpu::Sampler::WRAP_CLAMP); _lightingTexture = gpu::Texture::createRenderBuffer(gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::R11G11B10), width, height, gpu::Texture::SINGLE_MIP, smoothSampler); _lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("lighting")); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index af5a3f3e63..3b23711a64 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -32,7 +32,6 @@ namespace ru { using render_utils::slot::texture::Texture; using render_utils::slot::buffer::Buffer; - using render_utils::slot::uniform::Uniform; } namespace gr { diff --git a/libraries/render-utils/src/DeferredTransform.slh b/libraries/render-utils/src/DeferredTransform.slh index 6dd92c651b..19986805f6 100644 --- a/libraries/render-utils/src/DeferredTransform.slh +++ b/libraries/render-utils/src/DeferredTransform.slh @@ -38,8 +38,8 @@ struct DeferredFrameTransform { mat4 _projectionMono; mat4 _viewInverse; mat4 _view; - mat4 _projectionUnJittered[2]; - mat4 _invProjectionUnJittered[2]; + mat4 _projectionUnJittered[2]; + mat4 _invProjectionUnJittered[2]; }; layout(binding=RENDER_UTILS_BUFFER_DEFERRED_FRAME_TRANSFORM) uniform deferredFrameTransformBuffer { @@ -68,10 +68,10 @@ mat4 getProjectionMono() { return frameTransform._projectionMono; } mat4 getUnjitteredProjection(int side) { - return frameTransform._projectionUnJittered[side]; + return frameTransform._projectionUnJittered[side]; } mat4 getUnjitteredInvProjection(int side) { - return frameTransform._invProjectionUnJittered[side]; + return frameTransform._invProjectionUnJittered[side]; } // positive near distance of the projection @@ -158,7 +158,7 @@ vec3 evalUnjitteredEyePositionFromZdb(int side, float Zdb, vec2 texcoord) { } vec3 evalEyePositionFromZeye(int side, float Zeye, vec2 texcoord) { - float Zdb = evalZdbFromZeye(Zeye); + float Zdb = evalZdbFromZeye(Zeye); return evalEyePositionFromZdb(side, Zdb, texcoord); } diff --git a/libraries/render-utils/src/Fade_shared.slh b/libraries/render-utils/src/Fade_shared.slh index 7d1c0fb8bc..7ede92b807 100644 --- a/libraries/render-utils/src/Fade_shared.slh +++ b/libraries/render-utils/src/Fade_shared.slh @@ -13,12 +13,12 @@ struct FadeParameters { - VEC4 _noiseInvSizeAndLevel; - VEC4 _innerEdgeColor; - VEC4 _outerEdgeColor; - VEC2 _edgeWidthInvWidth; - FLOAT32 _baseLevel; - INT32 _isInverted; + VEC4 _noiseInvSizeAndLevel; + VEC4 _innerEdgeColor; + VEC4 _outerEdgeColor; + VEC2 _edgeWidthInvWidth; + FLOAT32 _baseLevel; + INT32 _isInverted; }; // <@if 1@> diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index cbc9b40129..2fe811c97b 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -2104,9 +2104,7 @@ void GeometryCache::useSimpleDrawPipeline(gpu::Batch& batch, bool noBlend) { auto stateNoBlend = std::make_shared(); PrepareStencil::testMaskDrawShape(*stateNoBlend); - auto noBlendPS = gpu::Shader::createVertex(shader::gpu::fragment::DrawTextureOpaque); auto programNoBlend = gpu::Shader::createProgram(shader::render_utils::program::standardDrawTextureNoBlend); - _standardDrawPipelineNoBlend = gpu::Pipeline::create(programNoBlend, stateNoBlend); }); diff --git a/libraries/render-utils/src/Highlight.slh b/libraries/render-utils/src/Highlight.slh index 56a999f508..fe77c38fd5 100644 --- a/libraries/render-utils/src/Highlight.slh +++ b/libraries/render-utils/src/Highlight.slh @@ -22,8 +22,8 @@ layout(binding=RENDER_UTILS_BUFFER_HIGHLIGHT_PARAMS) uniform highlightParamsBuff layout(binding=RENDER_UTILS_TEXTURE_HIGHLIGHT_SCENE_DEPTH) uniform sampler2D sceneDepthMap; layout(binding=RENDER_UTILS_TEXTURE_HIGHLIGHT_DEPTH) uniform sampler2D highlightedDepthMap; -in vec2 varTexCoord0; -out vec4 outFragColor; +layout(location=0) in vec2 varTexCoord0; +layout(location=0) out vec4 outFragColor; const float FAR_Z = 1.0; const float LINEAR_DEPTH_BIAS = 5e-3; @@ -55,10 +55,10 @@ void main(void) { discard; <@endif@> } else { - vec2 halfTexel = getInvWidthHeight() / 2; + vec2 halfTexel = getInvWidthHeight() / 2.0; vec2 texCoord0 = varTexCoord0+halfTexel; float weight = 0.0; - vec2 deltaUv = params._size / params._blurKernelSize; + vec2 deltaUv = params._size / float(params._blurKernelSize); vec2 lineStartUv = texCoord0 - params._size / 2.0; vec2 uv; int x; @@ -87,7 +87,7 @@ void main(void) { } } - if (intensity > 0) { + if (intensity > 0.0) { // sumOutlineDepth /= intensity; } else { sumOutlineDepth = FAR_Z; diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp index 7e2e55c768..11326b1120 100644 --- a/libraries/render-utils/src/HighlightEffect.cpp +++ b/libraries/render-utils/src/HighlightEffect.cpp @@ -28,7 +28,6 @@ using namespace render; namespace ru { using render_utils::slot::texture::Texture; using render_utils::slot::buffer::Buffer; - using render_utils::slot::uniform::Uniform; } namespace gr { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 8287b9cca6..ba2bd28852 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -976,7 +976,7 @@ bool Model::addToScene(const render::ScenePointer& scene, render::Transaction& transaction, render::Item::Status::Getters& statusGetters) { if (!_addedToScene && isLoaded()) { - updateClusterMatrices(false); + updateClusterMatrices(); if (_modelMeshRenderItems.empty()) { createRenderItemSet(); } @@ -1307,6 +1307,7 @@ void Blender::run() { if (mesh.blendshapes.isEmpty()) { continue; } + vertices += mesh.vertices; normalsAndTangents += mesh.normalsAndTangents; glm::vec3* meshVertices = vertices.data() + offset; @@ -1486,7 +1487,7 @@ void Model::computeMeshPartLocalBounds() { } // virtual -void Model::updateClusterMatrices(bool triggerBlendshapes) { +void Model::updateClusterMatrices() { DETAILED_PERFORMANCE_TIMER("Model::updateClusterMatrices"); if (!_needsUpdateClusterMatrices || !isLoaded()) { @@ -1515,7 +1516,7 @@ void Model::updateClusterMatrices(bool triggerBlendshapes) { // post the blender if we're not currently waiting for one to finish auto modelBlender = DependencyManager::get(); - if (triggerBlendshapes && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { + if (_blendedVertexBuffersInitialized && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { _blendedBlendshapeCoefficients = _blendshapeCoefficients; modelBlender->noteRequiresBlend(getThisPointer()); } @@ -1552,7 +1553,7 @@ void Model::setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geo const auto vertexCount = mesh.vertices.size(); const auto verticesSize = vertexCount * sizeof(glm::vec3); const auto& buffer = _blendedVertexBuffers[i]; - assert(buffer); + assert(buffer && _blendedVertexBuffersInitialized); buffer->resize(mesh.vertices.size() * sizeof(glm::vec3) + mesh.normalsAndTangents.size() * sizeof(NormalType)); buffer->setSubData(0, verticesSize, (gpu::Byte*) vertices.constData() + index * sizeof(glm::vec3)); buffer->setSubData(verticesSize, mesh.normalsAndTangents.size() * sizeof(NormalType), (const gpu::Byte*) normalsAndTangents.data() + normalAndTangentIndex * sizeof(NormalType)); @@ -1565,6 +1566,7 @@ void Model::setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geo void Model::deleteGeometry() { _deleteGeometryCounter++; _blendedVertexBuffers.clear(); + _blendedVertexBuffersInitialized = false; _meshStates.clear(); _rig.destroyAnimGraph(); _blendedBlendshapeCoefficients.clear(); @@ -1630,6 +1632,7 @@ void Model::initializeBlendshapes(const FBXMesh& mesh, int index) { _blendedVertexBuffers[index]->setSubData(0, verticesSize, (const gpu::Byte*) mesh.vertices.constData()); _blendedVertexBuffers[index]->setSubData(verticesSize, normalsAndTangents.size() * sizeof(NormalType), (const gpu::Byte*) normalsAndTangents.data()); mesh.normalsAndTangents = normalsAndTangents; + _blendedVertexBuffersInitialized = true; } void Model::createRenderItemSet() { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 5ab50da162..e7534f5b89 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -159,7 +159,7 @@ public: bool getSnapModelToRegistrationPoint() { return _snapModelToRegistrationPoint; } virtual void simulate(float deltaTime, bool fullUpdate = true); - virtual void updateClusterMatrices(bool triggerBlendshapes = true); + virtual void updateClusterMatrices(); /// Returns a reference to the shared geometry. const Geometry::Pointer& getGeometry() const { return _renderGeometry; } @@ -345,6 +345,8 @@ public: void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName); void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName); + bool areBlendedVertexBuffersInitialized(int index) { return _blendedVertexBuffersInitialized; } + public slots: void loadURLFinished(bool success); @@ -424,8 +426,9 @@ protected: QUrl _url; std::unordered_map _blendedVertexBuffers; + bool _blendedVertexBuffersInitialized { false }; - QVector > > _dilatedTextures; + QVector>> _dilatedTextures; QVector _blendedBlendshapeCoefficients; int _blendNumber; diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh index 85a30d5889..5115a876fe 100644 --- a/libraries/render-utils/src/Shadow.slh +++ b/libraries/render-utils/src/Shadow.slh @@ -45,7 +45,7 @@ struct ShadowSampleOffsets { }; ShadowSampleOffsets evalShadowFilterOffsets(vec4 position) { - float shadowScale = getShadowScale(); + float shadowScale = getShadowScale(); ShadowSampleOffsets offsets; #if SHADOW_SCREEN_SPACE_DITHER @@ -67,10 +67,10 @@ ShadowSampleOffsets evalShadowFilterOffsets(vec4 position) { ivec2 offset = coords & ivec2(1,1); offset.y = (offset.x+offset.y) & 1; - offsets.points[0] = shadowScale * vec3(offset + PCFkernel[0], 0.0); - offsets.points[1] = shadowScale * vec3(offset + PCFkernel[1], 0.0); - offsets.points[2] = shadowScale * vec3(offset + PCFkernel[2], 0.0); - offsets.points[3] = shadowScale * vec3(offset + PCFkernel[3], 0.0); + offsets.points[0] = shadowScale * vec3(vec2(offset) + PCFkernel[0], 0.0); + offsets.points[1] = shadowScale * vec3(vec2(offset) + PCFkernel[1], 0.0); + offsets.points[2] = shadowScale * vec3(vec2(offset) + PCFkernel[2], 0.0); + offsets.points[3] = shadowScale * vec3(vec2(offset) + PCFkernel[3], 0.0); return offsets; } @@ -104,7 +104,7 @@ float evalShadowAttenuation(vec3 worldLightDir, vec4 worldPosition, float viewDe vec3 cascadeMix; bvec4 isPixelOnCascade; int cascadeIndex; - float oneMinusNdotL = 1.0 - clamp(dot(worldLightDir, worldNormal), 0, 1); + float oneMinusNdotL = 1.0 - clamp(dot(worldLightDir, worldNormal), 0.0, 1.0); for (cascadeIndex=0 ; cascadeIndex layout(std140, binding=RENDER_UTILS_BUFFER_SHADOW_PARAMS) uniform shadowTransformBuffer { - ShadowParameters shadow; + ShadowParameters shadow; }; int getShadowCascadeCount() { @@ -30,26 +30,26 @@ float evalShadowFalloff(float depth) { } mat4 getShadowReprojection(int cascadeIndex) { - return shadow.cascades[cascadeIndex].reprojection; + return shadow.cascades[cascadeIndex].reprojection; } float getShadowScale() { - return shadow.invMapSize; + return shadow.invMapSize; } float getShadowFixedBias(int cascadeIndex) { - return shadow.cascades[cascadeIndex].fixedBias; + return shadow.cascades[cascadeIndex].fixedBias; } float getShadowSlopeBias(int cascadeIndex) { - return shadow.cascades[cascadeIndex].slopeBias; + return shadow.cascades[cascadeIndex].slopeBias; } // Compute the texture coordinates from world coordinates vec4 evalShadowTexcoord(int cascadeIndex, vec4 position) { - vec4 shadowCoord = getShadowReprojection(cascadeIndex) * position; - return vec4(shadowCoord.xyz, 1.0); + vec4 shadowCoord = getShadowReprojection(cascadeIndex) * position; + return vec4(shadowCoord.xyz, 1.0); } bool isShadowCascadeProjectedOnPixel(vec4 cascadeTexCoords) { diff --git a/libraries/render-utils/src/Shadows_shared.slh b/libraries/render-utils/src/Shadows_shared.slh index bc8063e018..9cb46587a2 100644 --- a/libraries/render-utils/src/Shadows_shared.slh +++ b/libraries/render-utils/src/Shadows_shared.slh @@ -8,8 +8,8 @@ #define SHADOW_CASCADE_MAX_COUNT 4 struct ShadowTransform { - MAT4 reprojection; - float fixedBias; + MAT4 reprojection; + float fixedBias; float slopeBias; float _padding1; float _padding2; diff --git a/libraries/render-utils/src/SoftAttachmentModel.cpp b/libraries/render-utils/src/SoftAttachmentModel.cpp index 93ce8f595a..b9a6581f1d 100644 --- a/libraries/render-utils/src/SoftAttachmentModel.cpp +++ b/libraries/render-utils/src/SoftAttachmentModel.cpp @@ -31,7 +31,7 @@ int SoftAttachmentModel::getJointIndexOverride(int i) const { // virtual // use the _rigOverride matrices instead of the Model::_rig -void SoftAttachmentModel::updateClusterMatrices(bool triggerBlendshapes) { +void SoftAttachmentModel::updateClusterMatrices() { if (!_needsUpdateClusterMatrices) { return; } @@ -78,7 +78,7 @@ void SoftAttachmentModel::updateClusterMatrices(bool triggerBlendshapes) { // post the blender if we're not currently waiting for one to finish auto modelBlender = DependencyManager::get(); - if (triggerBlendshapes && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { + if (_blendedVertexBuffersInitialized && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { _blendedBlendshapeCoefficients = _blendshapeCoefficients; modelBlender->noteRequiresBlend(getThisPointer()); } diff --git a/libraries/render-utils/src/SoftAttachmentModel.h b/libraries/render-utils/src/SoftAttachmentModel.h index 03038c35f3..4335c1634e 100644 --- a/libraries/render-utils/src/SoftAttachmentModel.h +++ b/libraries/render-utils/src/SoftAttachmentModel.h @@ -27,7 +27,7 @@ public: ~SoftAttachmentModel(); void updateRig(float deltaTime, glm::mat4 parentTransform) override; - void updateClusterMatrices(bool triggerBlendshapes = true) override; + void updateClusterMatrices() override; protected: int getJointIndexOverride(int i) const; diff --git a/libraries/render-utils/src/TextRenderer3D.cpp b/libraries/render-utils/src/TextRenderer3D.cpp index dd9167d248..8ef0dc0d73 100644 --- a/libraries/render-utils/src/TextRenderer3D.cpp +++ b/libraries/render-utils/src/TextRenderer3D.cpp @@ -70,9 +70,8 @@ void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const QString& st const glm::vec2& bounds, bool layered) { // The font does all the OpenGL work if (_font) { - // Cache color so that the pointer stays valid. _color = color; - _font->drawString(batch, x, y, str, &_color, _effectType, bounds, layered); + _font->drawString(batch, _drawInfo, str, _color, _effectType, { x, y }, bounds, layered); } } diff --git a/libraries/render-utils/src/TextRenderer3D.h b/libraries/render-utils/src/TextRenderer3D.h index 175802ef6e..6c91411e1d 100644 --- a/libraries/render-utils/src/TextRenderer3D.h +++ b/libraries/render-utils/src/TextRenderer3D.h @@ -15,12 +15,14 @@ #include #include #include +#include namespace gpu { class Batch; } class Font; +#include "text/Font.h" #include "text/EffectType.h" #include "text/FontFamilies.h" @@ -51,7 +53,7 @@ private: // text color glm::vec4 _color; - + Font::DrawInfo _drawInfo; std::shared_ptr _font; }; diff --git a/libraries/render-utils/src/debug_deferred_buffer_shared.slh b/libraries/render-utils/src/debug_deferred_buffer_shared.slh index 2d11a66d61..f5d6797c50 100644 --- a/libraries/render-utils/src/debug_deferred_buffer_shared.slh +++ b/libraries/render-utils/src/debug_deferred_buffer_shared.slh @@ -7,7 +7,7 @@ struct DebugParameters { - INT32 _shadowCascadeIndex; + INT32 _shadowCascadeIndex; }; // <@if 1@> diff --git a/libraries/render-utils/src/deferred_light_limited.slv b/libraries/render-utils/src/deferred_light_limited.slv index fb59b8e78f..1c835aacf7 100644 --- a/libraries/render-utils/src/deferred_light_limited.slv +++ b/libraries/render-utils/src/deferred_light_limited.slv @@ -18,7 +18,8 @@ <$declareStandardTransform()$> -uniform vec4 sphereParam; +// FIXME make into a uniform buffer or push constant if this shader ever comes into use +vec4 sphereParam = vec4(0.0); layout(location=RENDER_UTILS_ATTR_TEXCOORD01) out vec4 _texCoord01; @@ -41,7 +42,7 @@ void main(void) { } #endif #endif - _texCoord01.xy = vec4(projected.xy, 0.0, 1.0) * gl_Position.w; + _texCoord01 = vec4(projected.xy, 0.0, 1.0) * gl_Position.w; } else { const float depth = -1.0; //Draw at near plane const vec4 UNIT_QUAD[4] = vec4[4]( @@ -60,7 +61,7 @@ void main(void) { #endif #endif - _texCoord01.xy = vec4((pos.xy + 1.0) * 0.5, 0.0, 1.0); + _texCoord01 = vec4((pos.xy + 1.0) * 0.5, 0.0, 1.0); #ifdef GPU_TRANSFORM_IS_STEREO #ifdef GPU_TRANSFORM_STEREO_SPLIT_SCREEN diff --git a/libraries/render-utils/src/drawWorkloadProxy.slf b/libraries/render-utils/src/drawWorkloadProxy.slf index 32dceab00a..f0bd9d474c 100644 --- a/libraries/render-utils/src/drawWorkloadProxy.slf +++ b/libraries/render-utils/src/drawWorkloadProxy.slf @@ -13,9 +13,9 @@ <@include DeferredBufferWrite.slh@> <@include gpu/Paint.slh@> -in vec4 varColor; -in vec3 varTexcoord; -in vec3 varEyePos; +layout(location=0) in vec4 varColor; +layout(location=1) in vec3 varTexcoord; +layout(location=2) in vec3 varEyePos; void main(void) { if (varColor.w > 0.0) { diff --git a/libraries/render-utils/src/drawWorkloadProxy.slv b/libraries/render-utils/src/drawWorkloadProxy.slv index 28a62070f9..7a01702107 100644 --- a/libraries/render-utils/src/drawWorkloadProxy.slv +++ b/libraries/render-utils/src/drawWorkloadProxy.slv @@ -19,9 +19,9 @@ <$declareWorkloadProxies()$> -out vec4 varColor; -out vec3 varTexcoord; -out vec3 varEyePos; +layout(location=0) out vec4 varColor; +layout(location=1) out vec3 varTexcoord; +layout(location=2) out vec3 varEyePos; void main(void) { const vec4 UNIT_SPRITE[3] = vec4[3]( diff --git a/libraries/render-utils/src/drawWorkloadView.slf b/libraries/render-utils/src/drawWorkloadView.slf index c44dae4a24..b638824204 100644 --- a/libraries/render-utils/src/drawWorkloadView.slf +++ b/libraries/render-utils/src/drawWorkloadView.slf @@ -14,9 +14,9 @@ <@include DeferredBufferWrite.slh@> <@include gpu/Paint.slh@> -in vec4 varColor; -in vec3 varTexcoord; -in vec3 varEyePos; +layout(location=0) in vec4 varColor; +layout(location=1) in vec3 varTexcoord; +layout(location=2) in vec3 varEyePos; void main(void) { if (varColor.w > 0.0) { diff --git a/libraries/render-utils/src/drawWorkloadView.slv b/libraries/render-utils/src/drawWorkloadView.slv index 291a8c86cd..db4a33c450 100644 --- a/libraries/render-utils/src/drawWorkloadView.slv +++ b/libraries/render-utils/src/drawWorkloadView.slv @@ -18,9 +18,9 @@ <@include WorkloadResource.slh@> <$declareWorkloadViews()$> -out vec4 varColor; -out vec3 varTexcoord; -out vec3 varEyePos; +layout(location=0) out vec4 varColor; +layout(location=1) out vec3 varTexcoord; +layout(location=2) out vec3 varEyePos; const int NUM_VERTICES_PER_SEGMENT = 2; const int NUM_SEGMENT_PER_VIEW_REGION = 65; @@ -79,7 +79,7 @@ void main(void) { <$transformModelToEyeDir(cam, obj, originSpaceTan, tanEye)$> lateralDir = normalize(cross(vec3(0.0, 0.0, 1.0), normalize(tanEye))); - posEye.xyz += (0.005 * abs(posEye.z) * (regionID + 1)) * (-1.0 + 2.0 * float(segmentVertexID)) * lateralDir; + posEye.xyz += (0.005 * abs(posEye.z) * float(regionID + 1)) * (-1.0 + 2.0 * float(segmentVertexID)) * lateralDir; varEyePos = posEye.xyz; <$transformEyeToClipPos(cam, posEye, gl_Position)$> diff --git a/libraries/render-utils/src/fxaa.slf b/libraries/render-utils/src/fxaa.slf index 2dddcc795b..f1096a3054 100644 --- a/libraries/render-utils/src/fxaa.slf +++ b/libraries/render-utils/src/fxaa.slf @@ -24,7 +24,9 @@ precision mediump int; layout(binding=0) uniform sampler2D colorTexture; //uniform sampler2D historyTexture; -layout(location=0) uniform vec2 texcoordOffset; + +// FIXME make into a uniform buffer or push constant if this shader ever comes into use +vec2 texcoordOffset = vec2(0.0); layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; @@ -66,7 +68,7 @@ void main() { outFragColor.w = 1.0; }*/ - if (gl_FragCoord.x > 800) { + if (gl_FragCoord.x > 800.0) { /* // filter width limit for dependent "two-tap" texture samples float FXAA_SPAN_MAX = 8.0; diff --git a/libraries/render-utils/src/fxaa_blend.slf b/libraries/render-utils/src/fxaa_blend.slf index aca050f047..c051801659 100644 --- a/libraries/render-utils/src/fxaa_blend.slf +++ b/libraries/render-utils/src/fxaa_blend.slf @@ -18,7 +18,14 @@ layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; layout(binding=0) uniform sampler2D colorTexture; -layout(location=GPU_UNIFORM_EXTRA0) uniform float sharpenIntensity; + +struct FxaaBlendParams { + vec4 sharpenIntensity; +}; + +layout(binding=0) uniform fxaaBlendParamsBuffer { + FxaaBlendParams params; +}; void main(void) { vec4 pixels[9]; @@ -37,7 +44,7 @@ void main(void) { sharpenedPixel = pixels[4]*6.8 - (pixels[1]+pixels[3]+pixels[5]+pixels[7]) - (pixels[0]+pixels[2]+pixels[6]+pixels[8])*0.7; - vec4 minColor = max(vec4(0), pixels[4]-vec4(0.5)); - vec4 maxColor = pixels[4]+vec4(0.5); - outFragColor = clamp(pixels[4] + sharpenedPixel * sharpenIntensity, minColor, maxColor); + vec4 minColor = max(vec4(0), pixels[4]-vec4(0.5)); + vec4 maxColor = pixels[4]+vec4(0.5); + outFragColor = clamp(pixels[4] + sharpenedPixel * params.sharpenIntensity.x, minColor, maxColor); } diff --git a/libraries/render-utils/src/glowLine.slf b/libraries/render-utils/src/glowLine.slf index 4e80b3358a..c65d8d6488 100644 --- a/libraries/render-utils/src/glowLine.slf +++ b/libraries/render-utils/src/glowLine.slf @@ -22,9 +22,9 @@ void main(void) { float alpha = 1.0 - abs(distanceFromCenter); // Convert from a linear alpha curve to a sharp peaked one - alpha = _color.a * pow(alpha, 10.0); - - // Drop everything where the curve falls off to nearly nothing + alpha = _color.a * pow(alpha, 10.0); + + // Drop everything where the curve falls off to nearly nothing if (alpha <= 0.05) { discard; } diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slf b/libraries/render-utils/src/lightClusters_drawClusterContent.slf index 65ae8f423e..27cb838566 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterContent.slf +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slf @@ -42,7 +42,7 @@ void main(void) { ivec3 cluster = clusterGrid_getCluster(clusterIndex); int numLights = cluster.x + cluster.y; - float numLightsScale = clamp(numLights * 0.05, 0.01, 1.0); + float numLightsScale = clamp(float(numLights) * 0.05, 0.01, 1.0); int clusterOffset = cluster.z; @@ -90,6 +90,6 @@ void main(void) { numLightTouching++; } - _fragColor = vec4(colorRamp(1.0 - (numLightTouching / 12.0f)), (numLightTouching > 0 ? 0.5 + 0.5 * numLightsScale : 0.0)); + _fragColor = vec4(colorRamp(1.0 - (float(numLightTouching) / 12.0f)), (numLightTouching > 0 ? 0.5 + 0.5 * numLightsScale : 0.0)); } diff --git a/libraries/render-utils/src/lightClusters_drawClusterContent.slv b/libraries/render-utils/src/lightClusters_drawClusterContent.slv index d7e4a66a6a..1303cf3926 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterContent.slv +++ b/libraries/render-utils/src/lightClusters_drawClusterContent.slv @@ -56,7 +56,7 @@ void main(void) { ivec3 cluster = clusterGrid_getCluster(gpu_InstanceID()); int numLights = cluster.x + cluster.y; - float numLightsScale = clamp(numLights * 0.1, 0.0, 1.0); + float numLightsScale = clamp(float(numLights) * 0.1, 0.0, 1.0); ivec3 clusterPos = frustumGrid_indexToCluster(gpu_InstanceID()); diff --git a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf index 4efb60a259..abbd86dd70 100644 --- a/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf +++ b/libraries/render-utils/src/lightClusters_drawClusterFromDepth.slf @@ -39,7 +39,7 @@ void main(void) { ivec3 cluster = clusterGrid_getCluster(frustumGrid_clusterToIndex(clusterPos)); int numLights = cluster.x + cluster.y; - float numLightsScale = clamp(numLights * 0.05, 0.01, 1.0); + float numLightsScale = clamp(float(numLights) * 0.05, 0.01, 1.0); ivec3 dims = frustumGrid.dims.xyz; diff --git a/libraries/render-utils/src/model_translucent_normal_map.slf b/libraries/render-utils/src/model_translucent_normal_map.slf index 45eee9d160..7ac6982cfa 100644 --- a/libraries/render-utils/src/model_translucent_normal_map.slf +++ b/libraries/render-utils/src/model_translucent_normal_map.slf @@ -87,7 +87,7 @@ void main(void) { 1.0, occlusionTex, fragPositionES, - fragPositionWS, + fragPositionWS, albedo, fresnel, metallic, diff --git a/libraries/render-utils/src/model_translucent_normal_map_fade.slf b/libraries/render-utils/src/model_translucent_normal_map_fade.slf index 2ede2bfbaa..2c182aeb19 100644 --- a/libraries/render-utils/src/model_translucent_normal_map_fade.slf +++ b/libraries/render-utils/src/model_translucent_normal_map_fade.slf @@ -97,7 +97,7 @@ void main(void) { 1.0, occlusionTex, fragPositionES, - fragPositionWS, + fragPositionWS, albedo, fresnel, metallic, diff --git a/libraries/render-utils/src/render-utils/ShaderConstants.h b/libraries/render-utils/src/render-utils/ShaderConstants.h index 7f5867c800..330df6a2af 100644 --- a/libraries/render-utils/src/render-utils/ShaderConstants.h +++ b/libraries/render-utils/src/render-utils/ShaderConstants.h @@ -43,9 +43,6 @@ #define RENDER_UTILS_BUFFER_AMBIENT_LIGHT 6 #define RENDER_UTILS_BUFFER_LIGHT_INDEX 7 -#define RENDER_UTILS_UNIFORM_LIGHT_RADIUS 0 -#define RENDER_UTILS_UNIFORM_LIGHT_TEXCOORD_TRANSFORM 1 - // Deferred lighting resolution #define RENDER_UTILS_TEXTURE_DEFERRRED_COLOR 0 #define RENDER_UTILS_TEXTURE_DEFERRRED_NORMAL 1 @@ -139,8 +136,6 @@ enum Uniform { TextOutline = RENDER_UTILS_UNIFORM_TEXT_OUTLINE, TaaSharpenIntensity = GPU_UNIFORM_EXTRA0, HighlightOutlineWidth = GPU_UNIFORM_EXTRA0, - LightRadius = RENDER_UTILS_UNIFORM_LIGHT_RADIUS, - TexcoordTransform = RENDER_UTILS_UNIFORM_LIGHT_TEXCOORD_TRANSFORM, }; } diff --git a/libraries/render-utils/src/render-utils/fxaa.slp b/libraries/render-utils/src/render-utils/fxaa.slp new file mode 100644 index 0000000000..c2c4bfbebd --- /dev/null +++ b/libraries/render-utils/src/render-utils/fxaa.slp @@ -0,0 +1 @@ +VERTEX gpu::vertex::DrawUnitQuadTexcoord diff --git a/libraries/render-utils/src/sdf_text3D.slf b/libraries/render-utils/src/sdf_text3D.slf index 2fbaa03900..d35396e469 100644 --- a/libraries/render-utils/src/sdf_text3D.slf +++ b/libraries/render-utils/src/sdf_text3D.slf @@ -14,8 +14,15 @@ <@include render-utils/ShaderConstants.h@> layout(binding=0) uniform sampler2D Font; -layout(location=RENDER_UTILS_UNIFORM_TEXT_OUTLINE) uniform bool Outline; -layout(location=RENDER_UTILS_UNIFORM_TEXT_COLOR) uniform vec4 Color; + +struct TextParams { + vec4 color; + vec4 outline; +}; + +layout(binding=0) uniform textParamsBuffer { + TextParams params; +}; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; @@ -32,7 +39,7 @@ const float taaBias = pow(2.0, TAA_TEXTURE_LOD_BIAS); float evalSDF(vec2 texCoord) { // retrieve signed distance float sdf = textureLod(Font, texCoord, TAA_TEXTURE_LOD_BIAS).g; - if (Outline) { + if (params.outline.x > 0.0) { if (sdf > interiorCutoff) { sdf = 1.0 - sdf; } else { @@ -47,12 +54,12 @@ void main() { vec2 dxTexCoord = dFdx(_texCoord0) * 0.5 * taaBias; vec2 dyTexCoord = dFdy(_texCoord0) * 0.5 * taaBias; - // Perform 4x supersampling for anisotropic filtering + // Perform 4x supersampling for anisotropic filtering float a; - a = evalSDF(_texCoord0); - a += evalSDF(_texCoord0+dxTexCoord); - a += evalSDF(_texCoord0+dyTexCoord); - a += evalSDF(_texCoord0+dxTexCoord+dyTexCoord); + a = evalSDF(_texCoord0); + a += evalSDF(_texCoord0+dxTexCoord); + a += evalSDF(_texCoord0+dyTexCoord); + a += evalSDF(_texCoord0+dxTexCoord+dyTexCoord); a *= 0.25; // discard if invisible @@ -62,8 +69,8 @@ void main() { packDeferredFragment( normalize(_normalWS), - a * Color.a, - Color.rgb, + a * params.color.a, + params.color.rgb, DEFAULT_ROUGHNESS, DEFAULT_METALLIC, DEFAULT_EMISSIVE, diff --git a/libraries/render-utils/src/sdf_text3D_transparent.slf b/libraries/render-utils/src/sdf_text3D_transparent.slf index 218236c26b..9dffca2038 100644 --- a/libraries/render-utils/src/sdf_text3D_transparent.slf +++ b/libraries/render-utils/src/sdf_text3D_transparent.slf @@ -14,8 +14,15 @@ <@include render-utils/ShaderConstants.h@> layout(binding=0) uniform sampler2D Font; -layout(location=RENDER_UTILS_UNIFORM_TEXT_OUTLINE) uniform bool Outline; -layout(location=RENDER_UTILS_UNIFORM_TEXT_COLOR) uniform vec4 Color; + +struct TextParams { + vec4 color; + vec4 outline; +}; + +layout(binding=0) uniform textParamsBuffer { + TextParams params; +}; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; @@ -31,7 +38,7 @@ const float outlineExpansion = 0.2; void main() { // retrieve signed distance float sdf = texture(Font, _texCoord0).g; - if (Outline) { + if (params.outline.x > 0.0) { if (sdf > interiorCutoff) { sdf = 1.0 - sdf; } else { @@ -51,8 +58,8 @@ void main() { packDeferredFragmentTranslucent( normalize(_normalWS), - a * Color.a, - Color.rgb, + a * params.color.a, + params.color.rgb, DEFAULT_FRESNEL, DEFAULT_ROUGHNESS); } \ No newline at end of file diff --git a/libraries/render-utils/src/simple_fade.slf b/libraries/render-utils/src/simple_fade.slf index e9f94c29bc..97ed0c570c 100644 --- a/libraries/render-utils/src/simple_fade.slf +++ b/libraries/render-utils/src/simple_fade.slf @@ -91,7 +91,7 @@ void main(void) { normal, 1.0, diffuse+fadeEmissive, - max(0, 1.0 - shininess / 128.0), + max(0.0, 1.0 - shininess / 128.0), DEFAULT_METALLIC, specular, specular); @@ -100,7 +100,7 @@ void main(void) { normal, 1.0, diffuse, - max(0, 1.0 - shininess / 128.0), + max(0.0, 1.0 - shininess / 128.0), length(specular), DEFAULT_EMISSIVE+fadeEmissive, DEFAULT_OCCLUSION, diff --git a/libraries/render-utils/src/simple_transparent_textured.slf b/libraries/render-utils/src/simple_transparent_textured.slf index 0e6198de68..5573a7aa22 100644 --- a/libraries/render-utils/src/simple_transparent_textured.slf +++ b/libraries/render-utils/src/simple_transparent_textured.slf @@ -17,7 +17,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(location=0) uniform sampler2D originalTexture; +layout(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index 13594c68f3..5c70174f8a 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -137,14 +137,14 @@ float getBlurCoef(int c) { float getAngleDitheringWorldPos(in vec3 pixelWorldPos) { vec3 worldPosFract = fract(pixelWorldPos * 1.0); - ivec3 pixelPos = ivec3(worldPosFract * 256); + ivec3 pixelPos = ivec3(worldPosFract * 256.0); - return isDitheringEnabled() * ((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) + (3 * pixelPos.y ^ pixelPos.z + pixelPos.x * pixelPos.z)) * 10 + getFrameDithering(); + return isDitheringEnabled() * float(((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) + (3 * pixelPos.y ^ pixelPos.z + pixelPos.x * pixelPos.z)) * 10) + getFrameDithering(); } float getAngleDithering(in ivec2 pixelPos) { // Hash function used in the AlchemyAO paper - return isDitheringEnabled() * (3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10 + getFrameDithering(); + return isDitheringEnabled() * float((3 * pixelPos.x ^ pixelPos.y + pixelPos.x * pixelPos.y) * 10) + getFrameDithering(); } float evalDiskRadius(float Zeye, vec2 imageSize) { @@ -203,7 +203,7 @@ vec3 getTapLocationClampedSSAO(int sampleNumber, float spinAngle, float outerRad if (redoTap) { tap.xy = tapPos - pixelPos; tap.z = length(tap.xy); - tap.z = 0; + tap.z = 0.0; } return tap; @@ -239,7 +239,7 @@ vec3 fetchTapUnfiltered(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) { vec2 tapUV = (vec2(ssP) + vec2(0.5)) / imageSize; - vec2 fetchUV = vec2(tapUV.x + side.w * 0.5 * (side.x - tapUV.x), tapUV.y); + vec2 fetchUV = vec2(tapUV.x + float(side.w) * 0.5 * (float(side.x) - tapUV.x), tapUV.y); vec3 P; P.xy = tapUV; @@ -249,7 +249,7 @@ vec3 fetchTapUnfiltered(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) { } vec3 fetchTap(ivec4 side, ivec2 ssC, vec3 tap, vec2 imageSize) { - int mipLevel = evalMipFromRadius(tap.z * doFetchMips()); + int mipLevel = evalMipFromRadius(tap.z * float(doFetchMips())); vec2 ssP = tap.xy + vec2(ssC); diff --git a/libraries/render-utils/src/ssao_debugOcclusion.slf b/libraries/render-utils/src/ssao_debugOcclusion.slf index b9f112cc6f..92e5a28a0b 100644 --- a/libraries/render-utils/src/ssao_debugOcclusion.slf +++ b/libraries/render-utils/src/ssao_debugOcclusion.slf @@ -84,15 +84,15 @@ void main(void) { float keepTapRadius = 1.0; int keepedMip = -1; bool keep = false; - - for (int i = 0; i < getNumSamples(); ++i) { + int sampleCount = int(getNumSamples()); + for (int i = 0; i < sampleCount; ++i) { vec3 tap = getTapLocationClampedSSAO(i, randomPatternRotationAngle, ssDiskRadius, cursorPixelPos, imageSize); // The occluding point in camera space vec2 fragToTap = vec2(ssC) + tap.xy - fragCoord.xy; if (dot(fragToTap,fragToTap) < keepTapRadius) { keep = true; - keepedMip = evalMipFromRadius(tap.z * doFetchMips()); + keepedMip = evalMipFromRadius(tap.z * float(doFetchMips())); } vec3 tapUVZ = fetchTap(side, ssC, tap, imageSize); diff --git a/libraries/render-utils/src/subsurfaceScattering_drawScattering.slf b/libraries/render-utils/src/subsurfaceScattering_drawScattering.slf index 00b60d6fd4..8664fa16fd 100644 --- a/libraries/render-utils/src/subsurfaceScattering_drawScattering.slf +++ b/libraries/render-utils/src/subsurfaceScattering_drawScattering.slf @@ -26,7 +26,8 @@ layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 _fragColor; -layout(location=GPU_UNIFORM_EXTRA0) uniform vec2 uniformCursorTexcoord = vec2(0.5); +// FIXME make into a uniform buffer or push constant if this shader ever comes into use +vec2 uniformCursorTexcoord = vec2(0.5); //uniform vec3 uniformLightVector = vec3(1.0); @@ -79,7 +80,7 @@ vec3 drawScatteringTableUV(vec2 cursor, vec2 texcoord) { vec3 distance = vec3(0.0); for (int c = 0; c < 3; c++) { - vec2 BRDFuv = vec2(clamp(bentNdotL[c] * 0.5 + 0.5, 0.0, 1.0), clamp(2 * curvature, 0.0, 1.0)); + vec2 BRDFuv = vec2(clamp(bentNdotL[c] * 0.5 + 0.5, 0.0, 1.0), clamp(2.0 * curvature, 0.0, 1.0)); vec2 delta = BRDFuv - texcoord; distance[c] = 1.0 - dot(delta, delta); } diff --git a/libraries/render-utils/src/surfaceGeometry_copyDepth.slf b/libraries/render-utils/src/surfaceGeometry_copyDepth.slf index 7eb097224e..f018ee1105 100644 --- a/libraries/render-utils/src/surfaceGeometry_copyDepth.slf +++ b/libraries/render-utils/src/surfaceGeometry_copyDepth.slf @@ -16,7 +16,7 @@ layout(binding=0) uniform sampler2D depthMap; layout(location=0) out vec4 outFragColor; void main(void) { - float Zdb = texelFetch(depthMap, ivec2(gl_FragCoord.xy), 0).x; - outFragColor = vec4(Zdb, 0.0, 0.0, 1.0); + float Zdb = texelFetch(depthMap, ivec2(gl_FragCoord.xy), 0).x; + outFragColor = vec4(Zdb, 0.0, 0.0, 1.0); } diff --git a/libraries/render-utils/src/taa.slh b/libraries/render-utils/src/taa.slh index 26ffe55263..2161ad9524 100644 --- a/libraries/render-utils/src/taa.slh +++ b/libraries/render-utils/src/taa.slh @@ -24,10 +24,10 @@ layout(binding=RENDER_UTILS_TEXTURE_TAA_NEXT) uniform sampler2D nextMap; struct TAAParams { - float none; - float blend; - float covarianceGamma; - float debugShowVelocityThreshold; + float none; + float blend; + float covarianceGamma; + float debugShowVelocityThreshold; ivec4 flags; vec4 pixelInfo_orbZoom; vec4 regionInfo; @@ -77,47 +77,47 @@ vec2 taa_getRegionFXAA() { #define USE_YCOCG 1 vec4 taa_fetchColor(sampler2D map, vec2 uv) { - vec4 c = texture(map, uv); - // Apply rapid pseudo tonemapping as TAA is applied to a tonemapped image, using luminance as weight, as proposed in - // https://de45xmedrsdbp.cloudfront.net/Resources/files/TemporalAA_small-59732822.pdf - float lum = dot(vec3(0.3,0.5,0.2),c.rgb); - c.rgb = c.rgb / (1.0+lum); + vec4 c = texture(map, uv); + // Apply rapid pseudo tonemapping as TAA is applied to a tonemapped image, using luminance as weight, as proposed in + // https://de45xmedrsdbp.cloudfront.net/Resources/files/TemporalAA_small-59732822.pdf + float lum = dot(vec3(0.3,0.5,0.2),c.rgb); + c.rgb = c.rgb / (1.0+lum); #if USE_YCOCG - return vec4(color_LinearToYCoCg(c.rgb), c.a); + return vec4(color_LinearToYCoCg(c.rgb), c.a); #else - return c; + return c; #endif } vec3 taa_resolveColor(vec3 color) { #if USE_YCOCG - color = max(vec3(0), color_YCoCgToUnclampedLinear(color)); + color = max(vec3(0), color_YCoCgToUnclampedLinear(color)); #endif - // Apply rapid inverse tonemapping, using luminance as weight, as proposed in - // https://de45xmedrsdbp.cloudfront.net/Resources/files/TemporalAA_small-59732822.pdf - float lum = dot(vec3(0.3,0.5,0.2),color.rgb); - color = color / (1.0-lum); - return color; + // Apply rapid inverse tonemapping, using luminance as weight, as proposed in + // https://de45xmedrsdbp.cloudfront.net/Resources/files/TemporalAA_small-59732822.pdf + float lum = dot(vec3(0.3,0.5,0.2),color.rgb); + color = color / (1.0-lum); + return color; } vec4 taa_fetchSourceMap(vec2 uv) { - return taa_fetchColor(sourceMap, uv); + return taa_fetchColor(sourceMap, uv); } vec4 taa_fetchHistoryMap(vec2 uv) { - return taa_fetchColor(historyMap, uv); + return taa_fetchColor(historyMap, uv); } vec4 taa_fetchNextMap(vec2 uv) { - return taa_fetchColor(nextMap, uv); + return taa_fetchColor(nextMap, uv); } vec2 taa_fetchVelocityMap(vec2 uv) { - return texture(velocityMap, uv).xy; + return texture(velocityMap, uv).xy; } float taa_fetchDepth(vec2 uv) { - return -texture(depthMap, vec2(uv), 0).x; + return -texture(depthMap, vec2(uv), 0.0).x; } @@ -141,35 +141,35 @@ vec2 taa_getTexelSize() { vec3 taa_findClosestFragment3x3(vec2 uv) { - vec2 dd = abs(taa_getTexelSize()); - vec2 du = vec2(dd.x, 0.0); - vec2 dv = vec2(0.0, dd.y); + vec2 dd = abs(taa_getTexelSize()); + vec2 du = vec2(dd.x, 0.0); + vec2 dv = vec2(0.0, dd.y); - vec3 dtl = vec3(-1, -1, taa_fetchDepth(uv - dv - du)); - vec3 dtc = vec3( 0, -1, taa_fetchDepth(uv - dv)); - vec3 dtr = vec3( 1, -1, taa_fetchDepth(uv - dv + du)); + vec3 dtl = vec3(-1, -1, taa_fetchDepth(uv - dv - du)); + vec3 dtc = vec3( 0, -1, taa_fetchDepth(uv - dv)); + vec3 dtr = vec3( 1, -1, taa_fetchDepth(uv - dv + du)); - vec3 dml = vec3(-1, 0, taa_fetchDepth(uv - du)); - vec3 dmc = vec3( 0, 0, taa_fetchDepth(uv)); - vec3 dmr = vec3( 1, 0, taa_fetchDepth(uv + du)); + vec3 dml = vec3(-1, 0, taa_fetchDepth(uv - du)); + vec3 dmc = vec3( 0, 0, taa_fetchDepth(uv)); + vec3 dmr = vec3( 1, 0, taa_fetchDepth(uv + du)); - vec3 dbl = vec3(-1, 1, taa_fetchDepth(uv + dv - du)); - vec3 dbc = vec3( 0, 1, taa_fetchDepth(uv + dv)); - vec3 dbr = vec3( 1, 1, taa_fetchDepth(uv + dv + du)); + vec3 dbl = vec3(-1, 1, taa_fetchDepth(uv + dv - du)); + vec3 dbc = vec3( 0, 1, taa_fetchDepth(uv + dv)); + vec3 dbr = vec3( 1, 1, taa_fetchDepth(uv + dv + du)); - vec3 dmin = dtl; - if (ZCMP_GT(dmin.z, dtc.z)) dmin = dtc; - if (ZCMP_GT(dmin.z, dtr.z)) dmin = dtr; + vec3 dmin = dtl; + if (ZCMP_GT(dmin.z, dtc.z)) dmin = dtc; + if (ZCMP_GT(dmin.z, dtr.z)) dmin = dtr; - if (ZCMP_GT(dmin.z, dml.z)) dmin = dml; - if (ZCMP_GT(dmin.z, dmc.z)) dmin = dmc; - if (ZCMP_GT(dmin.z, dmr.z)) dmin = dmr; + if (ZCMP_GT(dmin.z, dml.z)) dmin = dml; + if (ZCMP_GT(dmin.z, dmc.z)) dmin = dmc; + if (ZCMP_GT(dmin.z, dmr.z)) dmin = dmr; - if (ZCMP_GT(dmin.z, dbl.z)) dmin = dbl; - if (ZCMP_GT(dmin.z, dbc.z)) dmin = dbc; - if (ZCMP_GT(dmin.z, dbr.z)) dmin = dbr; + if (ZCMP_GT(dmin.z, dbl.z)) dmin = dbl; + if (ZCMP_GT(dmin.z, dbc.z)) dmin = dbc; + if (ZCMP_GT(dmin.z, dbr.z)) dmin = dbr; - return vec3(uv + dd.xy * dmin.xy, dmin.z); + return vec3(uv + dd.xy * dmin.xy, dmin.z); } vec2 taa_fetchVelocityMapBest(vec2 uv) { @@ -230,7 +230,7 @@ vec2 taa_fromEyeUVToFragUV(vec2 eyeUV, int stereoSide) { vec2 fragUV = eyeUV; if (isStereo()) { fragUV.x *= 0.5; - fragUV.x += stereoSide*0.5; + fragUV.x += float(stereoSide)*0.5; } return fragUV; } @@ -264,8 +264,8 @@ mat3 taa_evalNeighbourColorVariance(vec3 sourceColor, vec2 fragUV, vec2 fragVelo vec2 texelSize = taa_getTexelSize(); - vec2 du = vec2(texelSize.x, 0.0); - vec2 dv = vec2(0.0, texelSize.y); + vec2 du = vec2(texelSize.x, 0.0); + vec2 dv = vec2(0.0, texelSize.y); vec3 sampleColor = taa_fetchSourceMap(fragUV - dv - du).rgb; vec3 sumSamples = sampleColor; @@ -320,72 +320,72 @@ mat3 taa_evalNeighbourColorRegion(vec3 sourceColor, vec2 fragUV, vec2 fragVeloci vec3 cmin, cmax, cavg; #if MINMAX_3X3_ROUNDED - vec2 du = vec2(texelSize.x, 0.0); - vec2 dv = vec2(0.0, texelSize.y); + vec2 du = vec2(texelSize.x, 0.0); + vec2 dv = vec2(0.0, texelSize.y); - vec3 ctl = taa_fetchSourceMap(fragUV - dv - du).rgb; - vec3 ctc = taa_fetchSourceMap(fragUV - dv).rgb; - vec3 ctr = taa_fetchSourceMap(fragUV - dv + du).rgb; - vec3 cml = taa_fetchSourceMap(fragUV - du).rgb; - vec3 cmc = sourceColor; //taa_fetchSourceMap(fragUV).rgb; // could resuse the same osurce sample isn't it ? - vec3 cmr = taa_fetchSourceMap(fragUV + du).rgb; - vec3 cbl = taa_fetchSourceMap(fragUV + dv - du).rgb; - vec3 cbc = taa_fetchSourceMap(fragUV + dv).rgb; - vec3 cbr = taa_fetchSourceMap(fragUV + dv + du).rgb; + vec3 ctl = taa_fetchSourceMap(fragUV - dv - du).rgb; + vec3 ctc = taa_fetchSourceMap(fragUV - dv).rgb; + vec3 ctr = taa_fetchSourceMap(fragUV - dv + du).rgb; + vec3 cml = taa_fetchSourceMap(fragUV - du).rgb; + vec3 cmc = sourceColor; //taa_fetchSourceMap(fragUV).rgb; // could resuse the same osurce sample isn't it ? + vec3 cmr = taa_fetchSourceMap(fragUV + du).rgb; + vec3 cbl = taa_fetchSourceMap(fragUV + dv - du).rgb; + vec3 cbc = taa_fetchSourceMap(fragUV + dv).rgb; + vec3 cbr = taa_fetchSourceMap(fragUV + dv + du).rgb; - cmin = min(ctl, min(ctc, min(ctr, min(cml, min(cmc, min(cmr, min(cbl, min(cbc, cbr)))))))); - cmax = max(ctl, max(ctc, max(ctr, max(cml, max(cmc, max(cmr, max(cbl, max(cbc, cbr)))))))); + cmin = min(ctl, min(ctc, min(ctr, min(cml, min(cmc, min(cmr, min(cbl, min(cbc, cbr)))))))); + cmax = max(ctl, max(ctc, max(ctr, max(cml, max(cmc, max(cmr, max(cbl, max(cbc, cbr)))))))); - #if MINMAX_3X3_ROUNDED || USE_YCOCG || USE_CLIPPING - cavg = (ctl + ctc + ctr + cml + cmc + cmr + cbl + cbc + cbr) / 9.0; + #if MINMAX_3X3_ROUNDED || USE_YCOCG || USE_CLIPPING + cavg = (ctl + ctc + ctr + cml + cmc + cmr + cbl + cbc + cbr) / 9.0; #elif cavg = (cmin + cmax ) * 0.5; - #endif + #endif - #if MINMAX_3X3_ROUNDED - vec3 cmin5 = min(ctc, min(cml, min(cmc, min(cmr, cbc)))); - vec3 cmax5 = max(ctc, max(cml, max(cmc, max(cmr, cbc)))); - vec3 cavg5 = (ctc + cml + cmc + cmr + cbc) / 5.0; - cmin = 0.5 * (cmin + cmin5); - cmax = 0.5 * (cmax + cmax5); - cavg = 0.5 * (cavg + cavg5); - #endif + #if MINMAX_3X3_ROUNDED + vec3 cmin5 = min(ctc, min(cml, min(cmc, min(cmr, cbc)))); + vec3 cmax5 = max(ctc, max(cml, max(cmc, max(cmr, cbc)))); + vec3 cavg5 = (ctc + cml + cmc + cmr + cbc) / 5.0; + cmin = 0.5 * (cmin + cmin5); + cmax = 0.5 * (cmax + cmax5); + cavg = 0.5 * (cavg + cavg5); + #endif #else - const float _SubpixelThreshold = 0.5; - const float _GatherBase = 0.5; - const float _GatherSubpixelMotion = 0.1666; + const float _SubpixelThreshold = 0.5; + const float _GatherBase = 0.5; + const float _GatherSubpixelMotion = 0.1666; - vec2 texel_vel = fragVelocity * imageSize; - float texel_vel_mag = length(texel_vel) * -fragZe; - float k_subpixel_motion = clamp(_SubpixelThreshold / (0.0001 + texel_vel_mag), 0.0, 1.0); - float k_min_max_support = _GatherBase + _GatherSubpixelMotion * k_subpixel_motion; + vec2 texel_vel = fragVelocity * imageSize; + float texel_vel_mag = length(texel_vel) * -fragZe; + float k_subpixel_motion = clamp(_SubpixelThreshold / (0.0001 + texel_vel_mag), 0.0, 1.0); + float k_min_max_support = _GatherBase + _GatherSubpixelMotion * k_subpixel_motion; - vec2 ss_offset01 = k_min_max_support * vec2(-texelSize.x, texelSize.y); - vec2 ss_offset11 = k_min_max_support * vec2(texelSize.x, texelSize.y); - vec3 c00 = taa_fetchSourceMap(fragUV - ss_offset11).rgb; - vec3 c10 = taa_fetchSourceMap(fragUV - ss_offset01).rgb; - vec3 c01 = taa_fetchSourceMap(fragUV + ss_offset01).rgb; - vec3 c11 = taa_fetchSourceMap(fragUV + ss_offset11).rgb; + vec2 ss_offset01 = k_min_max_support * vec2(-texelSize.x, texelSize.y); + vec2 ss_offset11 = k_min_max_support * vec2(texelSize.x, texelSize.y); + vec3 c00 = taa_fetchSourceMap(fragUV - ss_offset11).rgb; + vec3 c10 = taa_fetchSourceMap(fragUV - ss_offset01).rgb; + vec3 c01 = taa_fetchSourceMap(fragUV + ss_offset01).rgb; + vec3 c11 = taa_fetchSourceMap(fragUV + ss_offset11).rgb; - cmin = min(c00, min(c10, min(c01, c11))); - cmax = max(c00, max(c10, max(c01, c11))); + cmin = min(c00, min(c10, min(c01, c11))); + cmax = max(c00, max(c10, max(c01, c11))); cavg = (cmin + cmax ) * 0.5; - #if USE_YCOCG || USE_CLIPPING - cavg = (c00 + c10 + c01 + c11) / 4.0; + #if USE_YCOCG || USE_CLIPPING + cavg = (c00 + c10 + c01 + c11) / 4.0; #elif cavg = (cmin + cmax ) * 0.5; - #endif + #endif #endif - // shrink chroma min-max - #if USE_YCOCG - vec2 chroma_extent = vec2(0.25 * 0.5 * (cmax.r - cmin.r)); - vec2 chroma_center = sourceColor.gb; - cmin.yz = chroma_center - chroma_extent; - cmax.yz = chroma_center + chroma_extent; - cavg.yz = chroma_center; - #endif + // shrink chroma min-max + #if USE_YCOCG + vec2 chroma_extent = vec2(0.25 * 0.5 * (cmax.r - cmin.r)); + vec2 chroma_center = sourceColor.gb; + cmin.yz = chroma_center - chroma_extent; + cmax.yz = chroma_center + chroma_extent; + cavg.yz = chroma_center; + #endif return mat3(cmin, cmax, cavg); } @@ -393,22 +393,22 @@ mat3 taa_evalNeighbourColorRegion(vec3 sourceColor, vec2 fragUV, vec2 fragVeloci //#define USE_OPTIMIZATIONS 0 vec3 taa_clampColor(vec3 colorMin, vec3 colorMax, vec3 colorSource, vec3 color) { - const float eps = 0.00001; + const float eps = 0.00001; vec3 p = colorSource; vec3 q = color; - // note: only clips towards aabb center (but fast!) - vec3 p_clip = 0.5 * (colorMax + colorMin); - vec3 e_clip = 0.5 * (colorMax - colorMin) + vec3(eps); + // note: only clips towards aabb center (but fast!) + vec3 p_clip = 0.5 * (colorMax + colorMin); + vec3 e_clip = 0.5 * (colorMax - colorMin) + vec3(eps); - vec3 v_clip = q - p_clip; - vec3 v_unit = v_clip.xyz / e_clip; - vec3 a_unit = abs(v_unit); - float ma_unit = max(a_unit.x, max(a_unit.y, a_unit.z)); + vec3 v_clip = q - p_clip; + vec3 v_unit = v_clip.xyz / e_clip; + vec3 a_unit = abs(v_unit); + float ma_unit = max(a_unit.x, max(a_unit.y, a_unit.z)); - if (ma_unit > 1.0) - return p_clip + v_clip / ma_unit; - else - return q;// point inside aabb + if (ma_unit > 1.0) + return p_clip + v_clip / ma_unit; + else + return q;// point inside aabb } vec3 taa_evalConstrainColor(vec3 sourceColor, vec2 sourceUV, vec2 sourceVel, vec3 candidateColor) { @@ -416,25 +416,25 @@ vec3 taa_evalConstrainColor(vec3 sourceColor, vec2 sourceUV, vec2 sourceVel, vec colorMinMaxAvg = taa_evalNeighbourColorVariance(sourceColor, sourceUV, sourceVel); - // clamp history to neighbourhood of current sample + // clamp history to neighbourhood of current sample return taa_clampColor(colorMinMaxAvg[0], colorMinMaxAvg[1], sourceColor, candidateColor); } vec3 taa_evalFeedbackColor(vec3 sourceColor, vec3 historyColor, float blendFactor) { const float _FeedbackMin = 0.1; const float _FeedbackMax = 0.9; - // feedback weight from unbiased luminance diff (t.lottes) - #if USE_YCOCG - float lum0 = sourceColor.r; - float lum1 = historyColor.r; - #else - float lum0 = Luminance(sourceColor.rgb); - float lum1 = Luminance(historyColor.rgb); - #endif - float unbiased_diff = abs(lum0 - lum1) / max(lum0, max(lum1, 0.2)); - float unbiased_weight = 1.0 - unbiased_diff; - float unbiased_weight_sqr = unbiased_weight * unbiased_weight; - float k_feedback = mix(_FeedbackMin, _FeedbackMax, unbiased_weight_sqr); + // feedback weight from unbiased luminance diff (t.lottes) + #if USE_YCOCG + float lum0 = sourceColor.r; + float lum1 = historyColor.r; + #else + float lum0 = Luminance(sourceColor.rgb); + float lum1 = Luminance(historyColor.rgb); + #endif + float unbiased_diff = abs(lum0 - lum1) / max(lum0, max(lum1, 0.2)); + float unbiased_weight = 1.0 - unbiased_diff; + float unbiased_weight_sqr = unbiased_weight * unbiased_weight; + float k_feedback = mix(_FeedbackMin, _FeedbackMax, unbiased_weight_sqr); vec3 nextColor = mix(historyColor, sourceColor, k_feedback * blendFactor).xyz; @@ -478,7 +478,7 @@ vec3 taa_evalFXAA(vec2 fragUV) { vec3 rgbSW = texture(sourceMap, fragUV + (vec2(-1.0, +1.0) * texelSize)).xyz; vec3 rgbSE = texture(sourceMap, fragUV + (vec2(+1.0, +1.0) * texelSize)).xyz; vec3 rgbM = texture(sourceMap, fragUV).xyz; - + // convert RGB values to luminance vec3 luma = vec3(0.299, 0.587, 0.114); float lumaNW = dot(rgbNW, luma); @@ -486,11 +486,11 @@ vec3 taa_evalFXAA(vec2 fragUV) { float lumaSW = dot(rgbSW, luma); float lumaSE = dot(rgbSE, luma); float lumaM = dot( rgbM, luma); - + // luma range of local neighborhood float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - + // direction perpendicular to local luma gradient vec2 dir; dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); @@ -502,7 +502,7 @@ vec3 taa_evalFXAA(vec2 fragUV) { float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), dir * rcpDirMin)) * texelSize; - + // perform additional texture sampling perpendicular to gradient vec3 rgbA = (1.0 / 2.0) * ( texture(sourceMap, fragUV + dir * (1.0 / 3.0 - 0.5)).xyz + diff --git a/libraries/render-utils/src/taa_blend.slf b/libraries/render-utils/src/taa_blend.slf index d2e23b590f..50575a6a07 100644 --- a/libraries/render-utils/src/taa_blend.slf +++ b/libraries/render-utils/src/taa_blend.slf @@ -23,7 +23,7 @@ void main(void) { // Pixel being shaded - vec3 sourceColor = texture(sourceMap, varTexCoord0).xyz; + vec3 sourceColor = texture(sourceMap, varTexCoord0).xyz; vec2 imageSize = getWidthHeight(0); vec2 texelSize = getInvWidthHeight(); @@ -57,7 +57,7 @@ void main(void) { vec2 cursorVelocityDir = cursorVelocity / cursorVelocityLength; vec2 cursorVelocityNor = vec2(cursorVelocityDir.y, -cursorVelocityDir.x); - if ((dot(cursorVelocityDir, cursorToFragVec) < 0) && abs(dot(cursorVelocityNor, cursorToFragVec)) < 1.0) { + if ((dot(cursorVelocityDir, cursorToFragVec) < 0.0) && abs(dot(cursorVelocityNor, cursorToFragVec)) < 1.0) { vec3 speedColor = taa_getVelocityColorRelative(cursorToFragLength); @@ -69,7 +69,7 @@ void main(void) { float tenPercentHeight = 0.1 * imageSize.y; float centerWidth = imageSize.x * 0.5; - //vec2 nextOrbPos = vec2(centerWidth, imageSize.y - 3 * tenPercentHeight); + //vec2 nextOrbPos = vec2(centerWidth, imageSize.y - 3.0 * tenPercentHeight); vec2 nextOrbPos = cursorPos; vec2 nextOrbPosToPix = pixPos - nextOrbPos; float nextOrbPosToPixLength = length(nextOrbPosToPix); @@ -124,9 +124,9 @@ void main(void) { // draw region splitter if ((abs(distToRegionDebug) < getInvWidthHeight().x) || (abs(distToRegionFXAA) < getInvWidthHeight().x)) { - outFragColor.rgb = vec3(1.0, 1.0, 0.0); - return; - } + outFragColor.rgb = vec3(1.0, 1.0, 0.0); + return; + } if (distToRegionFXAA > 0.0) { return; @@ -138,7 +138,7 @@ void main(void) { return; } - outFragColor = vec4(nextColor, 1.0); + outFragColor = vec4(nextColor, 1.0); vec3 prevColor = nextColor; @@ -146,7 +146,7 @@ void main(void) { prevColor = texture(historyMap, prevTexCoord).xyz; } - outFragColor.xyz = mix(prevColor, vec3(1,0,1), clamp(distance(prevColor, nextColor) - 0.01, 0, 1)); + outFragColor.xyz = mix(prevColor, vec3(1,0,1), clamp(distance(prevColor, nextColor) - 0.01, 0.0, 1.0)); if (pixVelocityLength > params.debugShowVelocityThreshold) { vec3 speedColor = taa_getVelocityColorAboveThreshold(pixVelocityLength); diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index aca6ddb79f..68a1e59dc3 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -256,29 +256,30 @@ void Font::setupGPU() { } } -void Font::rebuildVertices(float x, float y, const QString& str, const glm::vec2& bounds) { - _verticesBuffer = std::make_shared(); - _numVertices = 0; - _indicesBuffer = std::make_shared(); - _numIndices = 0; +void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm::vec2& origin, const glm::vec2& bounds) { + drawInfo.verticesBuffer = std::make_shared(); + drawInfo.indicesBuffer = std::make_shared(); + drawInfo.indexCount = 0; + int numVertices = 0; - _lastStringRendered = str; - _lastBounds = bounds; + drawInfo.string = str; + drawInfo.bounds = bounds; + drawInfo.origin = origin; // Top left of text - glm::vec2 advance = glm::vec2(x, y); + glm::vec2 advance = origin; foreach(const QString& token, tokenizeForWrapping(str)) { bool isNewLine = (token == QString('\n')); bool forceNewLine = false; // Handle wrapping - if (!isNewLine && (bounds.x != -1) && (advance.x + computeExtent(token).x > x + bounds.x)) { + if (!isNewLine && (bounds.x != -1) && (advance.x + computeExtent(token).x > origin.x + bounds.x)) { // We are out of the x bound, force new line forceNewLine = true; } if (isNewLine || forceNewLine) { // Character return, move the advance to a new line - advance = glm::vec2(x, advance.y - _leading); + advance = glm::vec2(origin.x, advance.y - _leading); if (isNewLine) { // No need to draw anything, go directly to next token @@ -288,7 +289,7 @@ void Font::rebuildVertices(float x, float y, const QString& str, const glm::vec2 break; } } - if ((bounds.y != -1) && (advance.y - _fontSize < -y - bounds.y)) { + if ((bounds.y != -1) && (advance.y - _fontSize < -origin.y - bounds.y)) { // We are out of the y bound, stop drawing break; } @@ -297,11 +298,11 @@ void Font::rebuildVertices(float x, float y, const QString& str, const glm::vec2 if (!isNewLine) { for (auto c : token) { auto glyph = _glyphs[c]; - quint16 verticesOffset = _numVertices; + quint16 verticesOffset = numVertices; QuadBuilder qd(glyph, advance - glm::vec2(0.0f, _ascent)); - _verticesBuffer->append(sizeof(QuadBuilder), (const gpu::Byte*)&qd); - _numVertices += 4; + drawInfo.verticesBuffer->append(qd); + numVertices += 4; // Sam's recommended triangle slices // Triangle tri1 = { v0, v1, v3 }; @@ -327,8 +328,8 @@ void Font::rebuildVertices(float x, float y, const QString& str, const glm::vec2 indices[3] = verticesOffset + 2; indices[4] = verticesOffset + 1; indices[5] = verticesOffset + 3; - _indicesBuffer->append(sizeof(indices), (const gpu::Byte*)indices); - _numIndices += NUMBER_OF_INDICES_PER_QUAD; + drawInfo.indicesBuffer->append(sizeof(indices), (const gpu::Byte*)indices); + drawInfo.indexCount += NUMBER_OF_INDICES_PER_QUAD; // Advance by glyph size @@ -341,26 +342,39 @@ void Font::rebuildVertices(float x, float y, const QString& str, const glm::vec2 } } -void Font::drawString(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4* color, - EffectType effectType, const glm::vec2& bounds, bool layered) { +void Font::drawString(gpu::Batch& batch, Font::DrawInfo& drawInfo, const QString& str, const glm::vec4& color, + EffectType effectType, const glm::vec2& origin, const glm::vec2& bounds, bool layered) { if (str == "") { return; } - if (str != _lastStringRendered || bounds != _lastBounds) { - rebuildVertices(x, y, str, bounds); + if (str != drawInfo.string || bounds != drawInfo.bounds || origin != drawInfo.origin) { + buildVertices(drawInfo, str, origin, bounds); } setupGPU(); - batch.setPipeline(((*color).a < 1.0f || layered) ? _transparentPipeline : _pipeline); - batch.setResourceTexture(render_utils::slot::texture::TextFont, _texture); - batch._glUniform1i(render_utils::slot::uniform::TextOutline, (effectType == OUTLINE_EFFECT)); + struct GpuDrawParams { + glm::vec4 color; + glm::vec4 outline; + }; + + if (!drawInfo.paramsBuffer || drawInfo.params.color != color || drawInfo.params.effect != effectType) { + drawInfo.params.color = color; + drawInfo.params.effect = effectType; + GpuDrawParams gpuDrawParams; + gpuDrawParams.color = ColorUtils::sRGBToLinearVec4(drawInfo.params.color); + gpuDrawParams.outline.x = (drawInfo.params.effect == OUTLINE_EFFECT) ? 1 : 0; + drawInfo.paramsBuffer = std::make_shared(sizeof(GpuDrawParams), nullptr); + drawInfo.paramsBuffer->setSubData(0, sizeof(GpuDrawParams), (const gpu::Byte*)&gpuDrawParams); + } // need the gamma corrected color here - glm::vec4 lrgba = ColorUtils::sRGBToLinearVec4(*color); - batch._glUniform4fv(render_utils::slot::uniform::TextColor, 1, (const float*)&lrgba); + + batch.setPipeline((color.a < 1.0f || layered) ? _transparentPipeline : _pipeline); batch.setInputFormat(_format); - batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride); - batch.setIndexBuffer(gpu::UINT16, _indicesBuffer, 0); - batch.drawIndexed(gpu::TRIANGLES, _numIndices, 0); + batch.setInputBuffer(0, drawInfo.verticesBuffer, 0, _format->getChannels().at(0)._stride); + batch.setResourceTexture(render_utils::slot::texture::TextFont, _texture); + batch.setUniformBuffer(0, drawInfo.paramsBuffer, 0, sizeof(GpuDrawParams)); + batch.setIndexBuffer(gpu::UINT16, drawInfo.indicesBuffer, 0); + batch.drawIndexed(gpu::TRIANGLES, drawInfo.indexCount, 0); } diff --git a/libraries/render-utils/src/text/Font.h b/libraries/render-utils/src/text/Font.h index 2fa2b65fa5..9a0a9b4734 100644 --- a/libraries/render-utils/src/text/Font.h +++ b/libraries/render-utils/src/text/Font.h @@ -23,16 +23,34 @@ public: void read(QIODevice& path); + struct DrawParams { + vec4 color{ -1 }; + EffectType effect; + }; + + struct DrawInfo { + gpu::BufferPointer verticesBuffer; + gpu::BufferPointer indicesBuffer; + gpu::BufferPointer paramsBuffer; + uint32_t indexCount; + + QString string; + glm::vec2 origin; + glm::vec2 bounds; + DrawParams params; + }; + glm::vec2 computeExtent(const QString& str) const; float getFontSize() const { return _fontSize; } // Render string to batch - void drawString(gpu::Batch& batch, float x, float y, const QString& str, - const glm::vec4* color, EffectType effectType, - const glm::vec2& bound, bool layered = false); + void drawString(gpu::Batch& batch, DrawInfo& drawInfo, const QString& str, + const glm::vec4& color, EffectType effectType, + const glm::vec2& origin, const glm::vec2& bound, bool layered = false); static Pointer load(const QString& family); + private: static Pointer load(QIODevice& fontFile); QStringList tokenizeForWrapping(const QString& str) const; @@ -40,7 +58,7 @@ private: glm::vec2 computeTokenExtent(const QString& str) const; const Glyph& getGlyph(const QChar& c) const; - void rebuildVertices(float x, float y, const QString& str, const glm::vec2& bounds); + void buildVertices(DrawInfo& drawInfo, const QString& str, const glm::vec2& origin, const glm::vec2& bounds); void setupGPU(); @@ -66,15 +84,7 @@ private: gpu::PipelinePointer _transparentPipeline; gpu::TexturePointer _texture; gpu::Stream::FormatPointer _format; - gpu::BufferPointer _verticesBuffer; - gpu::BufferPointer _indicesBuffer; gpu::BufferStreamPointer _stream; - unsigned int _numVertices = 0; - unsigned int _numIndices = 0; - - // last string render characteristics - QString _lastStringRendered; - glm::vec2 _lastBounds; }; #endif diff --git a/libraries/render-utils/src/velocityBuffer_cameraMotion.slf b/libraries/render-utils/src/velocityBuffer_cameraMotion.slf index 6932766d63..083440dbf8 100644 --- a/libraries/render-utils/src/velocityBuffer_cameraMotion.slf +++ b/libraries/render-utils/src/velocityBuffer_cameraMotion.slf @@ -27,11 +27,11 @@ void main(void) { ivec4 stereoSide; ivec2 framePixelPos = getPixelPosTexcoordPosAndSide(gl_FragCoord.xy, pixelPos, texcoordPos, stereoSide); - float Zdb = texelFetch(depthMap, ivec2(gl_FragCoord.xy), 0).x; + float Zdb = texelFetch(depthMap, ivec2(gl_FragCoord.xy), 0).x; - // The position of the pixel fragment in Eye space then in world space + // The position of the pixel fragment in Eye space then in world space vec3 eyePos = evalUnjitteredEyePositionFromZdb(stereoSide.x, Zdb, texcoordPos); - vec3 worldPos = (getViewInverse() * vec4(eyePos, 1.0)).xyz; + vec3 worldPos = (getViewInverse() * vec4(eyePos, 1.0)).xyz; vec3 prevEyePos = (getPreviousView() * vec4(worldPos, 1.0)).xyz; vec4 prevClipPos = (getUnjitteredProjection(stereoSide.x) * vec4(prevEyePos, 1.0)); diff --git a/libraries/render-utils/src/zone_drawAmbient.slf b/libraries/render-utils/src/zone_drawAmbient.slf index e560d91308..f20d83e913 100644 --- a/libraries/render-utils/src/zone_drawAmbient.slf +++ b/libraries/render-utils/src/zone_drawAmbient.slf @@ -44,7 +44,7 @@ void main(void) { // vec3 ambient = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(lightAmbient), fragNormal).xyz; // _fragColor = vec4( 0.5 * (fragNormal + vec3(1.0)), 1.0); - vec3 color = (sphereUV.x > 0 ? ambientMap : ambientSH); + vec3 color = (sphereUV.x > 0.0 ? ambientMap : ambientSH); color = color * 1.0 - base.w + base.xyz * base.w; const float INV_GAMMA_22 = 1.0 / 2.2; diff --git a/libraries/render-utils/src/zone_drawKeyLight.slf b/libraries/render-utils/src/zone_drawKeyLight.slf index 99e9357cb0..7174914ed8 100644 --- a/libraries/render-utils/src/zone_drawKeyLight.slf +++ b/libraries/render-utils/src/zone_drawKeyLight.slf @@ -36,7 +36,7 @@ void main(void) { vec3 outSpherePos = normalize(vec3(sphereUV, -sqrt(1.0 - sphereR2))); vec3 outNormal = vec3(getViewInverse() * vec4(outSpherePos, 0.0)); - float val = step(SUN_THRESHOLD, dot(-lightDirection, outNormal)); + float val = step(SUN_THRESHOLD, dot(-lightDirection, outNormal)); color = lightIrradiance * vec3(val); @@ -45,7 +45,7 @@ void main(void) { vec3 inSpherePos = normalize(vec3(inSphereUV, sqrt(1.0 - dot(inSphereUV.xy, inSphereUV.xy)))); vec3 inNormal = vec3(getViewInverse() * vec4(inSpherePos, 0.0)); - vec3 marbleColor = max(lightIrradiance * vec3(dot(-lightDirection, inNormal)), vec3(0.01)); + vec3 marbleColor = max(lightIrradiance * vec3(dot(-lightDirection, inNormal)), vec3(0.01)); color += marbleColor; } diff --git a/libraries/render/src/render/DrawSceneOctree.cpp b/libraries/render/src/render/DrawSceneOctree.cpp index 2cb8a5d8ef..6c87d2f56b 100644 --- a/libraries/render/src/render/DrawSceneOctree.cpp +++ b/libraries/render/src/render/DrawSceneOctree.cpp @@ -36,6 +36,9 @@ const gpu::PipelinePointer DrawSceneOctree::getDrawCellBoundsPipeline() { // Good to go add the brand new pipeline _drawCellBoundsPipeline = gpu::Pipeline::create(program, state); + _cellBoundsFormat = std::make_shared(); + _cellBoundsFormat->setAttribute(0, 0, gpu::Element(gpu::VEC4, gpu::INT32, gpu::XYZW), 0, gpu::Stream::PER_INSTANCE); + _cellBoundsBuffer = std::make_shared(); } return _drawCellBoundsPipeline; } @@ -82,8 +85,11 @@ void DrawSceneOctree::run(const RenderContextPointer& renderContext, const ItemS // bind the one gpu::Pipeline we need batch.setPipeline(getDrawCellBoundsPipeline()); + batch.setInputFormat(_cellBoundsFormat); - auto drawCellBounds = [this, &scene, &batch](const std::vector& cells) { + std::vector cellBounds; + auto drawCellBounds = [this, &cellBounds, &scene, &batch](const std::vector& cells) { + cellBounds.reserve(cellBounds.size() + cells.size()); for (const auto& cellID : cells) { auto cell = scene->getSpatialTree().getConcreteCell(cellID); auto cellLoc = cell.getlocation(); @@ -98,14 +104,19 @@ void DrawSceneOctree::run(const RenderContextPointer& renderContext, const ItemS } else if (!empty && !_showVisibleCells) { continue; } - - batch._glUniform4iv(gpu::slot::uniform::Extra0, 1, ((const int*)(&cellLocation))); - batch.draw(gpu::LINES, 24, 0); + cellBounds.push_back(cellLocation); } }; drawCellBounds(inSelection.cellSelection.insideCells); drawCellBounds(inSelection.cellSelection.partialCells); + auto size = cellBounds.size() * sizeof(ivec4); + if (size > _cellBoundsBuffer->getSize()) { + _cellBoundsBuffer->resize(size); + } + _cellBoundsBuffer->setSubData(0, cellBounds); + batch.setInputBuffer(0, _cellBoundsBuffer, 0, sizeof(ivec4)); + batch.drawInstanced((uint32_t)cellBounds.size(), gpu::LINES, 24); // Draw the LOD Reticle { diff --git a/libraries/render/src/render/DrawSceneOctree.h b/libraries/render/src/render/DrawSceneOctree.h index 0b2cd6f685..3f7c07ded3 100644 --- a/libraries/render/src/render/DrawSceneOctree.h +++ b/libraries/render/src/render/DrawSceneOctree.h @@ -54,6 +54,8 @@ namespace render { gpu::PipelinePointer _drawCellBoundsPipeline; gpu::PipelinePointer _drawLODReticlePipeline; gpu::PipelinePointer _drawItemBoundPipeline; + gpu::BufferPointer _cellBoundsBuffer; + gpu::Stream::FormatPointer _cellBoundsFormat; bool _showVisibleCells; // initialized by Config bool _showEmptyCells; // initialized by Config diff --git a/libraries/render/src/render/DrawStatus.cpp b/libraries/render/src/render/DrawStatus.cpp index 9b7d4ace2b..a1b61a4e77 100644 --- a/libraries/render/src/render/DrawStatus.cpp +++ b/libraries/render/src/render/DrawStatus.cpp @@ -170,13 +170,45 @@ void DrawStatus::run(const RenderContextPointer& renderContext, const Input& inp batch.setPipeline(getDrawItemStatusPipeline()); if (_showNetwork) { - for (size_t i = 0; i < itemBounds.size(); i++) { - batch._glUniform3fv(gpu::slot::uniform::Extra0, 1, (const float*)&itemBounds[i].bound.getCorner()); - batch._glUniform3fv(gpu::slot::uniform::Extra1, 1, ((const float*)&itemBounds[i].bound.getScale())); - batch._glUniform4iv(gpu::slot::uniform::Extra2, 1, (const int*)&(itemStatus[i].first)); - batch._glUniform4iv(gpu::slot::uniform::Extra3, 1, (const int*)&(itemStatus[i].second)); - batch.draw(gpu::TRIANGLES, 24 * NUM_STATUS_VEC4_PER_ITEM, 0); + if (!_instanceBuffer) { + _instanceBuffer = std::make_shared(); } + + struct InstanceData { + vec4 boundPos; + vec4 boundDim; + ivec4 status0; + ivec4 status1; + }; + + if (!_vertexFormat) { + _vertexFormat = std::make_shared(); + _vertexFormat->setAttribute(0, 0, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW), offsetof(InstanceData, boundPos), gpu::Stream::PER_INSTANCE); + _vertexFormat->setAttribute(1, 0, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW), offsetof(InstanceData, boundDim), gpu::Stream::PER_INSTANCE); + _vertexFormat->setAttribute(2, 0, gpu::Element(gpu::VEC4, gpu::INT32, gpu::XYZW), offsetof(InstanceData, status0), gpu::Stream::PER_INSTANCE); + _vertexFormat->setAttribute(3, 0, gpu::Element(gpu::VEC4, gpu::INT32, gpu::XYZW), offsetof(InstanceData, status1), gpu::Stream::PER_INSTANCE); + } + + batch.setInputFormat(_vertexFormat); + std::vector instanceData; + instanceData.resize(itemBounds.size()); + for (size_t i = 0; i < itemBounds.size(); i++) { + InstanceData& item = instanceData[i]; + const auto& bound = itemBounds[i].bound; + const auto& status = itemStatus[i]; + item.boundPos = vec4(bound.getCorner(), 1.0f); + item.boundDim = vec4(bound.getScale(), 1.0f); + item.status0 = status.first; + item.status1 = status.second; + } + + auto instanceBufferSize = sizeof(InstanceData) * instanceData.size(); + if (_instanceBuffer->getSize() < instanceBufferSize) { + _instanceBuffer->resize(instanceBufferSize); + } + _instanceBuffer->setSubData(0, instanceData); + batch.setInputBuffer(0, _instanceBuffer, 0, sizeof(InstanceData)); + batch.drawInstanced((uint32_t)instanceData.size(), gpu::TRIANGLES, 24 * NUM_STATUS_VEC4_PER_ITEM); } batch.setResourceTexture(0, 0); }); diff --git a/libraries/render/src/render/DrawStatus.h b/libraries/render/src/render/DrawStatus.h index 96269fda4d..2959ca59c5 100644 --- a/libraries/render/src/render/DrawStatus.h +++ b/libraries/render/src/render/DrawStatus.h @@ -63,6 +63,8 @@ namespace render { gpu::PipelinePointer _drawItemStatusPipeline; gpu::BufferPointer _boundsBuffer; + gpu::BufferPointer _instanceBuffer; + gpu::Stream::FormatPointer _vertexFormat; gpu::TexturePointer _statusIconMap; }; } diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 8fb800291e..12f75049b2 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -184,8 +184,13 @@ void DrawBounds::run(const RenderContextPointer& renderContext, _drawBuffer = std::make_shared(sizeOfItemBound); } - _drawBuffer->setData(numItems * sizeOfItemBound, (const gpu::Byte*) items.data()); + if (!_paramsBuffer) { + _paramsBuffer = std::make_shared(sizeof(vec4), nullptr); + } + _drawBuffer->setData(numItems * sizeOfItemBound, (const gpu::Byte*) items.data()); + glm::vec4 color(glm::vec3(0.0f), -(float) numItems); + _paramsBuffer->setSubData(0, color); gpu::doInBatch("DrawBounds::run", args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -202,7 +207,7 @@ void DrawBounds::run(const RenderContextPointer& renderContext, batch.setPipeline(getPipeline()); glm::vec4 color(glm::vec3(0.0f), -(float) numItems); - batch._glUniform4fv(gpu::slot::uniform::Color, 1, (const float*)(&color)); + batch.setUniformBuffer(0, _paramsBuffer); batch.setResourceBuffer(0, _drawBuffer); static const int NUM_VERTICES_PER_CUBE = 24; @@ -212,9 +217,10 @@ void DrawBounds::run(const RenderContextPointer& renderContext, gpu::Stream::FormatPointer DrawQuadVolume::_format; -DrawQuadVolume::DrawQuadVolume(const glm::vec3& color) : - _color{ color } { +DrawQuadVolume::DrawQuadVolume(const glm::vec3& color) { _meshVertices = gpu::BufferView(std::make_shared(sizeof(glm::vec3) * 8, nullptr), gpu::Element::VEC3F_XYZ); + _params = std::make_shared(sizeof(glm::vec4), nullptr); + _params->setSubData(0, vec4(color, 1.0)); if (!_format) { _format = std::make_shared(); _format->setAttribute(gpu::Stream::POSITION, gpu::Stream::POSITION, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); @@ -248,8 +254,7 @@ void DrawQuadVolume::run(const render::RenderContextPointer& renderContext, cons batch.setProjectionTransform(projMat); batch.setViewTransform(viewMat); batch.setPipeline(getPipeline()); - - batch._glUniform4f(0, _color.x, _color.y, _color.z, 1.0f); + batch.setUniformBuffer(0, _params); batch.setInputFormat(_format); batch.setInputBuffer(gpu::Stream::POSITION, _meshVertices); batch.setIndexBuffer(indices); diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index 6b98fb2977..1ef4b8caf1 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -66,6 +66,7 @@ private: const gpu::PipelinePointer getPipeline(); gpu::PipelinePointer _boundsPipeline; gpu::BufferPointer _drawBuffer; + gpu::BufferPointer _paramsBuffer; }; class DrawQuadVolumeConfig : public render::JobConfig { @@ -95,7 +96,7 @@ protected: const gpu::BufferView& indices, int indexCount); gpu::BufferView _meshVertices; - glm::vec3 _color; + gpu::BufferPointer _params; bool _isUpdateEnabled{ true }; static gpu::Stream::FormatPointer _format; diff --git a/libraries/render/src/render/drawCellBounds.slv b/libraries/render/src/render/drawCellBounds.slv index f3cc4c6411..24cc6254fd 100644 --- a/libraries/render/src/render/drawCellBounds.slv +++ b/libraries/render/src/render/drawCellBounds.slv @@ -20,8 +20,7 @@ <$declareColorWheel()$> <@include SceneOctree.slh@> -layout(location=GPU_UNIFORM_EXTRA0) uniform ivec4 inCellLocation; - +layout(location=0) in ivec4 inCellLocation; layout(location=0) out vec4 varColor; void main(void) { @@ -62,5 +61,5 @@ void main(void) { TransformObject obj = getTransformObject(); <$transformModelToClipPos(cam, obj, pos, gl_Position)$> - varColor = vec4(colorWheel(fract(float(inCellLocation.w) / 5.0)), 0.8 + 0.2 * cellIsEmpty); + varColor = vec4(colorWheel(fract(float(inCellLocation.w) / 5.0)), 0.8 + 0.2 * float(cellIsEmpty)); } \ No newline at end of file diff --git a/libraries/render/src/render/drawItemBounds.slv b/libraries/render/src/render/drawItemBounds.slv index 8925009160..ea4d0f24e6 100644 --- a/libraries/render/src/render/drawItemBounds.slv +++ b/libraries/render/src/render/drawItemBounds.slv @@ -20,7 +20,14 @@ <@include gpu/Color.slh@> <$declareColorWheel()$> -layout(location=GPU_UNIFORM_COLOR) uniform vec4 inColor; +struct DrawItemBoundsParams { + vec4 color; +}; + +layout(binding=0) uniform drawItemBoundsParamsBuffer { + DrawItemBoundsParams params; +}; + struct ItemBound { vec4 id_boundPos; @@ -91,10 +98,10 @@ void main(void) { TransformObject obj = getTransformObject(); <$transformModelToClipPos(cam, obj, pos, gl_Position)$> - if (inColor.w < 0.0) { - varColor = vec4(colorWheel(float(boundID)/(-inColor.w)), 1.0); + if (params.color.w < 0.0) { + varColor = vec4(colorWheel(float(boundID)/(-params.color.w)), 1.0); } else { - varColor = vec4(colorWheel(float(inColor.w)), 1.0); + varColor = vec4(colorWheel(float(params.color.w)), 1.0); } varTexcoord = vec2(cubeVec.w, length(boundDim)); diff --git a/libraries/render/src/render/drawItemStatus.slf b/libraries/render/src/render/drawItemStatus.slf index 309a73ae15..9409ee6171 100644 --- a/libraries/render/src/render/drawItemStatus.slf +++ b/libraries/render/src/render/drawItemStatus.slf @@ -18,7 +18,7 @@ layout(location=0) out vec4 outFragColor; layout(binding=0) uniform sampler2D _icons; vec2 getIconTexcoord(float icon, vec2 uv) { const vec2 ICON_COORD_SIZE = vec2(0.0625, 1.0); - return vec2((uv.x + icon) * ICON_COORD_SIZE.x, uv.y * ICON_COORD_SIZE.y); + return vec2((uv.x + icon) * ICON_COORD_SIZE.x, uv.y * ICON_COORD_SIZE.y); } void main(void) { diff --git a/libraries/render/src/render/drawItemStatus.slv b/libraries/render/src/render/drawItemStatus.slv index e92bdda248..7aac26fe2e 100644 --- a/libraries/render/src/render/drawItemStatus.slv +++ b/libraries/render/src/render/drawItemStatus.slv @@ -20,10 +20,10 @@ layout(location=0) out vec4 varColor; layout(location=1) out vec3 varTexcoord; -layout(location=GPU_UNIFORM_EXTRA0) uniform vec3 inBoundPos; -layout(location=GPU_UNIFORM_EXTRA1) uniform vec3 inBoundDim; -layout(location=GPU_UNIFORM_EXTRA2) uniform ivec4 inStatus0; -layout(location=GPU_UNIFORM_EXTRA3) uniform ivec4 inStatus1; +layout(location=0) in vec3 inBoundPos; +layout(location=1) in vec3 inBoundDim; +layout(location=2) in ivec4 inStatus0; +layout(location=3) in ivec4 inStatus1; vec3 paintRainbow(float normalizedHue) { float v = normalizedHue * 6.f; diff --git a/libraries/script-engine/src/AssetScriptingInterface.h b/libraries/script-engine/src/AssetScriptingInterface.h index 72d6901fb5..0e05a563b2 100644 --- a/libraries/script-engine/src/AssetScriptingInterface.h +++ b/libraries/script-engine/src/AssetScriptingInterface.h @@ -108,6 +108,10 @@ public: Q_INVOKABLE void setBakingEnabled(QString path, bool enabled, QScriptValue callback); #if (PR_BUILD || DEV_BUILD) + /** + * This function is purely for development purposes, and not meant for use in a + * production context. It is not a public-facing API, so it should not contain jsdoc. + */ Q_INVOKABLE void sendFakedHandshake(); #endif diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index ce4ec89950..7f2a992f68 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -271,7 +271,7 @@ void ScriptEngine::disconnectNonEssentialSignals() { // Ensure the thread should be running, and does exist if (_isRunning && _isThreaded && (workerThread = thread())) { connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit); - connect(this, &QObject::destroyed, workerThread, &QObject::deleteLater); + connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater); } } @@ -386,7 +386,7 @@ void ScriptEngine::runInThread() { // disconnectNonEssentialSignals() method connect(workerThread, &QThread::started, this, &ScriptEngine::run); connect(this, &ScriptEngine::doneRunning, workerThread, &QThread::quit); - connect(this, &QObject::destroyed, workerThread, &QObject::deleteLater); + connect(workerThread, &QThread::finished, workerThread, &QObject::deleteLater); workerThread->start(); } diff --git a/libraries/shared/src/AvatarConstants.h b/libraries/shared/src/AvatarConstants.h index 986d39e94d..6c38d08c96 100644 --- a/libraries/shared/src/AvatarConstants.h +++ b/libraries/shared/src/AvatarConstants.h @@ -68,6 +68,7 @@ const glm::quat DEFAULT_AVATAR_RIGHTFOOT_ROT { -0.4016716778278351f, 0.915461599 const float DEFAULT_AVATAR_MAX_WALKING_SPEED = 2.6f; // meters / second const float DEFAULT_AVATAR_MAX_WALKING_BACKWARD_SPEED = 2.2f; // meters / second const float DEFAULT_AVATAR_MAX_FLYING_SPEED = 30.0f; // meters / second +const float DEFAULT_AVATAR_WALK_SPEED_THRESHOLD = 0.15f; const float DEFAULT_AVATAR_GRAVITY = -5.0f; // meters / second^2 const float DEFAULT_AVATAR_JUMP_SPEED = 3.5f; // meters / second diff --git a/libraries/shared/src/NestableTransformNode.cpp b/libraries/shared/src/NestableTransformNode.cpp index 17456d69ce..9723f388f6 100644 --- a/libraries/shared/src/NestableTransformNode.cpp +++ b/libraries/shared/src/NestableTransformNode.cpp @@ -8,24 +8,7 @@ #include "NestableTransformNode.h" -NestableTransformNode::NestableTransformNode(SpatiallyNestableWeakPointer spatiallyNestable, int jointIndex) : - _spatiallyNestable(spatiallyNestable), - _jointIndex(jointIndex) -{ -} - -Transform NestableTransformNode::getTransform() { - auto nestable = _spatiallyNestable.lock(); - if (!nestable) { - return Transform(); - } - - bool success; - Transform jointWorldTransform = nestable->getTransform(_jointIndex, success); - - if (success) { - return jointWorldTransform; - } else { - return Transform(); - } +template<> +glm::vec3 BaseNestableTransformNode::getActualScale(const std::shared_ptr& nestablePointer) const { + return nestablePointer->getAbsoluteJointScaleInObjectFrame(_jointIndex); } \ No newline at end of file diff --git a/libraries/shared/src/NestableTransformNode.h b/libraries/shared/src/NestableTransformNode.h index 131de9e786..2f9bc2e985 100644 --- a/libraries/shared/src/NestableTransformNode.h +++ b/libraries/shared/src/NestableTransformNode.h @@ -12,14 +12,48 @@ #include "SpatiallyNestable.h" -class NestableTransformNode : public TransformNode { +template +class BaseNestableTransformNode : public TransformNode { public: - NestableTransformNode(SpatiallyNestableWeakPointer spatiallyNestable, int jointIndex); - Transform getTransform() override; + BaseNestableTransformNode(std::weak_ptr spatiallyNestable, int jointIndex) : + _spatiallyNestable(spatiallyNestable), + _jointIndex(jointIndex) { + auto nestablePointer = _spatiallyNestable.lock(); + if (nestablePointer) { + glm::vec3 nestableDimensions = getActualScale(nestablePointer); + _baseScale = glm::max(glm::vec3(0.001f), nestableDimensions); + } + } + + Transform getTransform() override { + std::shared_ptr nestable = _spatiallyNestable.lock(); + if (!nestable) { + return Transform(); + } + + bool success; + Transform jointWorldTransform = nestable->getTransform(_jointIndex, success); + + if (!success) { + return Transform(); + } + + jointWorldTransform.setScale(getActualScale(nestable) / _baseScale); + + return jointWorldTransform; + } + + glm::vec3 getActualScale(const std::shared_ptr& nestablePointer) const; protected: - SpatiallyNestableWeakPointer _spatiallyNestable; + std::weak_ptr _spatiallyNestable; int _jointIndex; + glm::vec3 _baseScale { 1.0f }; +}; + +class NestableTransformNode : public BaseNestableTransformNode { +public: + NestableTransformNode(std::weak_ptr spatiallyNestable, int jointIndex) : BaseNestableTransformNode(spatiallyNestable, jointIndex) {}; }; #endif // hifi_NestableTransformNode_h \ No newline at end of file diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 02f5fa570c..d59c58def8 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -259,10 +259,11 @@ public: * A CollisionRegion defines a volume for checking collisions in the physics simulation. * @typedef {object} CollisionRegion -* @property {Shape} shape - The information about the collision region's size and shape. +* @property {Shape} shape - The information about the collision region's size and shape. Dimensions are in world space, but will scale with the parent if defined. * @property {Vec3} position - The position of the collision region, relative to a parent if defined. * @property {Quat} orientation - The orientation of the collision region, relative to a parent if defined. * @property {float} threshold - The approximate minimum penetration depth for a test object to be considered in contact with the collision region. +* The depth is measured in world space, but will scale with the parent if defined. * @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or an overlay. * @property {number} parentJointIndex - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint) * @property {string} joint - If "Mouse," parents the pick to the mouse. If "Avatar," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar. diff --git a/libraries/ui/src/InteractiveWindow.cpp b/libraries/ui/src/InteractiveWindow.cpp index 5078fcb602..6c7f2d503f 100644 --- a/libraries/ui/src/InteractiveWindow.cpp +++ b/libraries/ui/src/InteractiveWindow.cpp @@ -13,12 +13,19 @@ #include #include +#include +#include #include #include #include "OffscreenUi.h" #include "shared/QtHelpers.h" +#include "MainWindow.h" + +#ifdef Q_OS_WIN +#include +#endif static auto CONTENT_WINDOW_QML = QUrl("InteractiveWindow.qml"); @@ -87,6 +94,12 @@ InteractiveWindow::InteractiveWindow(const QString& sourceUrl, const QVariantMap connect(object, SIGNAL(windowClosed()), this, SIGNAL(closed()), Qt::QueuedConnection); connect(object, SIGNAL(selfDestruct()), this, SLOT(close()), Qt::QueuedConnection); +#ifdef Q_OS_WIN + connect(object, SIGNAL(nativeWindowChanged()), this, SLOT(parentNativeWindowToMainWindow()), Qt::QueuedConnection); + connect(object, SIGNAL(interactiveWindowVisibleChanged()), this, SLOT(parentNativeWindowToMainWindow()), Qt::QueuedConnection); + connect(object, SIGNAL(presentationModeChanged()), this, SLOT(parentNativeWindowToMainWindow()), Qt::QueuedConnection); +#endif + QUrl sourceURL{ sourceUrl }; // If the passed URL doesn't correspond to a known scheme, assume it's a local file path if (!KNOWN_SCHEMES.contains(sourceURL.scheme(), Qt::CaseInsensitive)) { @@ -279,6 +292,24 @@ int InteractiveWindow::getPresentationMode() const { return _qmlWindow->property(PRESENTATION_MODE_PROPERTY).toInt(); } +#ifdef Q_OS_WIN +void InteractiveWindow::parentNativeWindowToMainWindow() { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "parentNativeWindowToMainWindow"); + return; + } + if (_qmlWindow.isNull()) { + return; + } + const auto nativeWindowProperty = _qmlWindow->property("nativeWindow"); + if (nativeWindowProperty.isNull() || !nativeWindowProperty.isValid()) { + return; + } + const auto nativeWindow = qvariant_cast(nativeWindowProperty); + SetWindowLongPtr((HWND)nativeWindow->winId(), GWLP_HWNDPARENT, (LONG)MainWindow::findMainWindow()->winId()); +} +#endif + void InteractiveWindow::setPresentationMode(int presentationMode) { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "setPresentationMode", Q_ARG(int, presentationMode)); diff --git a/libraries/ui/src/InteractiveWindow.h b/libraries/ui/src/InteractiveWindow.h index bf832550b5..f456b32e8d 100644 --- a/libraries/ui/src/InteractiveWindow.h +++ b/libraries/ui/src/InteractiveWindow.h @@ -84,6 +84,10 @@ private: Q_INVOKABLE void setPresentationMode(int presentationMode); Q_INVOKABLE int getPresentationMode() const; +#ifdef Q_OS_WIN + Q_INVOKABLE void parentNativeWindowToMainWindow(); +#endif + public slots: /**jsdoc diff --git a/libraries/ui/src/MainWindow.cpp b/libraries/ui/src/MainWindow.cpp index f9fc71e417..680433b2f9 100644 --- a/libraries/ui/src/MainWindow.cpp +++ b/libraries/ui/src/MainWindow.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "ui/Logging.h" @@ -39,6 +40,18 @@ MainWindow::~MainWindow() { qCDebug(uiLogging) << "Destroying main window"; } +QWindow* MainWindow::findMainWindow() { + auto windows = qApp->topLevelWindows(); + QWindow* result = nullptr; + for (const auto& window : windows) { + if (window->objectName().contains("MainWindow")) { + result = window; + break; + } + } + return result; +} + void MainWindow::restoreGeometry() { // Did not use setGeometry() on purpose, // see http://doc.qt.io/qt-5/qsettings.html#restoring-the-state-of-a-gui-application diff --git a/libraries/ui/src/MainWindow.h b/libraries/ui/src/MainWindow.h index 75421340a2..fbd48e5eb1 100644 --- a/libraries/ui/src/MainWindow.h +++ b/libraries/ui/src/MainWindow.h @@ -21,6 +21,8 @@ class MainWindow : public QMainWindow { public: explicit MainWindow(QWidget* parent = NULL); ~MainWindow(); + + static QWindow* findMainWindow(); public slots: void restoreGeometry(); diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index a5ef1457db..d82cfbbf3f 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -29,6 +29,7 @@ #include "ui/Logging.h" #include +#include "MainWindow.h" /**jsdoc * @namespace OffscreenFlags @@ -649,20 +650,7 @@ public: } private: - - static QWindow* findMainWindow() { - auto windows = qApp->topLevelWindows(); - QWindow* result = nullptr; - for (auto window : windows) { - if (window->objectName().contains("MainWindow")) { - result = window; - break; - } - } - return result; - } - - QWindow* const _mainWindow { findMainWindow() }; + QWindow* const _mainWindow { MainWindow::findMainWindow() }; QWindow* _hackWindow { nullptr }; }; diff --git a/libraries/workload/src/workload/ViewTask.h b/libraries/workload/src/workload/ViewTask.h index 7c1e4944f5..207bc04276 100644 --- a/libraries/workload/src/workload/ViewTask.h +++ b/libraries/workload/src/workload/ViewTask.h @@ -192,7 +192,7 @@ namespace workload { struct Data { - bool regulateViewRanges{ false }; // regulation is OFF by default + bool regulateViewRanges{ true }; // regulation is ON by default } data; struct DataExport { diff --git a/scripts/developer/debugging/debugWindow.js b/scripts/developer/debugging/debugWindow.js index 9522676007..993ca49a40 100644 --- a/scripts/developer/debugging/debugWindow.js +++ b/scripts/developer/debugging/debugWindow.js @@ -23,7 +23,7 @@ if (scripts.length >= 2) { var qml = Script.resolvePath('debugWindow.qml'); var HMD_DEBUG_WINDOW_GEOMETRY_KEY = 'hmdDebugWindowGeometry'; -var hmdDebugWindowGeometryValue = Settings.getValue(HMD_DEBUG_WINDOW_GEOMETRY_KEY) +var hmdDebugWindowGeometryValue = Settings.getValue(HMD_DEBUG_WINDOW_GEOMETRY_KEY); var windowWidth = 400; var windowHeight = 900; @@ -34,12 +34,13 @@ var windowY = 0; if (hmdDebugWindowGeometryValue !== '') { var geometry = JSON.parse(hmdDebugWindowGeometryValue); - - windowWidth = geometry.width - windowHeight = geometry.height - windowX = geometry.x - windowY = geometry.y - hasPosition = true; + if ((geometry.x !== 0) && (geometry.y !== 0)) { + windowWidth = geometry.width; + windowHeight = geometry.height; + windowX = geometry.x; + windowY = geometry.y; + hasPosition = true; + } } var window = new OverlayWindow({ @@ -52,6 +53,12 @@ if (hasPosition) { window.setPosition(windowX, windowY); } +window.visibleChanged.connect(function() { + if (!window.visible) { + window.setVisible(true); + } +}); + window.closed.connect(function () { Script.stop(); }); var getFormattedDate = function() { @@ -93,10 +100,10 @@ Script.scriptEnding.connect(function () { y: window.position.y, width: window.size.x, height: window.size.y - }) + }); Settings.setValue(HMD_DEBUG_WINDOW_GEOMETRY_KEY, geometry); window.close(); -}) +}); }()); diff --git a/scripts/developer/utilities/audio/Stats.qml b/scripts/developer/utilities/audio/Stats.qml index 7f559ea664..f359e9b04c 100644 --- a/scripts/developer/utilities/audio/Stats.qml +++ b/scripts/developer/utilities/audio/Stats.qml @@ -12,12 +12,12 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import "../../../../resources/qml/controls-uit" as HifiControls +import "qrc:////qml//controls-uit" as HifiControls Column { id: stats width: parent.width - property bool showGraphs: toggleGraphs.checked + property alias showGraphs: toggleGraphs.toggle Item { width: parent.width @@ -25,10 +25,10 @@ Column { HifiControls.Button { id: toggleGraphs - property bool checked: false + property bool toggle: false anchors.horizontalCenter: parent.horizontalCenter - text: checked ? "Hide graphs" : "Show graphs" - onClicked: function() { checked = !checked; } + text: toggle ? "Hide graphs" : "Show graphs" + onClicked: { toggle = !toggle;} } } @@ -40,7 +40,8 @@ Column { Section { label: "Latency" - description: "Audio pipeline latency, broken out and summed" + // description: "Audio pipeline latency, broken out and summed" + description: label control: ColumnLayout { MovingValue { label: "Input Read"; source: AudioStats.inputReadMsMax; showGraphs: stats.showGraphs } MovingValue { label: "Input Ring"; source: AudioStats.inputUnplayedMsMax; showGraphs: stats.showGraphs } @@ -62,7 +63,8 @@ Column { Section { label: "Upstream Jitter" - description: "Timegaps in packets sent to the mixer" + // description: "Timegaps in packets sent to the mixer" + description: label control: Jitter { max: AudioStats.sentTimegapMsMaxWindow avg: AudioStats.sentTimegapMsAvgWindow @@ -76,13 +78,15 @@ Column { Section { label: "Mixer (upstream)" - description: "This client's remote audio stream, as seen by the server's mixer" + // description: "This client's remote audio stream, as seen by the server's mixer" + description: label control: Stream { stream: AudioStats.mixerStream; showGraphs: stats.showGraphs } } Section { label: "Client (downstream)" - description: "This client's received audio stream, between the network and the OS" + // description: "This client's received audio stream, between the network and the OS" + description: label control: Stream { stream: AudioStats.clientStream; showGraphs: stats.showGraphs } } } diff --git a/scripts/developer/utilities/audio/TabletStats.qml b/scripts/developer/utilities/audio/TabletStats.qml index 130b90f032..2f8d212a2a 100644 --- a/scripts/developer/utilities/audio/TabletStats.qml +++ b/scripts/developer/utilities/audio/TabletStats.qml @@ -12,7 +12,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import "../../../../resources/qml/styles-uit" +import "qrc:////qml//styles-uit" Item { id: dialog diff --git a/scripts/system/edit.js b/scripts/system/edit.js index e340c75a8b..ed2a179613 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -1739,7 +1739,6 @@ function getPositionToCreateEntity(extra) { position = Vec3.sum(Camera.position, Vec3.multiply(Quat.getForward(Camera.orientation), CREATE_DISTANCE + delta)); } else { position = Vec3.sum(MyAvatar.position, Vec3.multiply(Quat.getForward(MyAvatar.orientation), CREATE_DISTANCE + delta)); - position.y += 0.5; } if (position.x > HALF_TREE_SCALE || position.y > HALF_TREE_SCALE || position.z > HALF_TREE_SCALE) { diff --git a/scripts/system/modules/createWindow.js b/scripts/system/modules/createWindow.js index 7369cf91f8..0c4412abfb 100644 --- a/scripts/system/modules/createWindow.js +++ b/scripts/system/modules/createWindow.js @@ -125,6 +125,9 @@ module.exports = (function() { Script.scriptEnding.connect(this, function() { this.window.close(); + // FIXME: temp solution for reload crash (MS18269), + // we should decide on proper object ownership strategy for InteractiveWindow API + this.window = null; }); }, setVisible: function(visible) { diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 46ddeb2bab..8fafac7685 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -127,7 +127,7 @@ return; } stories[story.id] = story; - var message = story.username + " says something is happening in " + story.place_name + ". Open GOTO to join them."; + var message = story.username + " " + story.action_string + " in " + story.place_name + ". Open GOTO to join them."; Window.displayAnnouncement(message); didNotify = true; }); diff --git a/tests/shaders/src/ShaderTests.cpp b/tests/shaders/src/ShaderTests.cpp index 4dd15710f9..03dc034cd0 100644 --- a/tests/shaders/src/ShaderTests.cpp +++ b/tests/shaders/src/ShaderTests.cpp @@ -230,8 +230,8 @@ void ShaderTests::testShaderLoad() { auto glBackend = std::static_pointer_cast(_gpuContext->getBackend()); auto glshader = gpu::gl::GLShader::sync(*glBackend, *program); if (!glshader) { - qDebug() << "Failed to compile or link vertex " << vertexId << " fragment " << fragmentId; - continue; + qWarning() << "Failed to compile or link vertex " << vertexId << " fragment " << fragmentId; + QFAIL("Program link error"); } QVERIFY(glshader != nullptr); @@ -301,7 +301,7 @@ void ShaderTests::testShaderLoad() { QFAIL(error.what()); } - for (uint32_t i = 0; i <= maxShader; ++i) { + for (uint32_t i = 1; i <= maxShader; ++i) { auto used = usedShaders.count(i); if (0 != usedShaders.count(i)) { continue;