Merge pull request #6476 from AndrewMeadows/arrow

fix for objects suffering from very small updates to physics properties
This commit is contained in:
Philip Rosedale 2015-11-24 11:22:25 -08:00
commit dde01b2071
9 changed files with 180 additions and 166 deletions

View file

@ -679,7 +679,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
})); }));
userInputMapper->registerDevice(_applicationStateDevice); userInputMapper->registerDevice(_applicationStateDevice);
// Setup the keyboardMouseDevice and the user input mapper with the default bindings // Setup the keyboardMouseDevice and the user input mapper with the default bindings
userInputMapper->registerDevice(_keyboardMouseDevice->getInputDevice()); userInputMapper->registerDevice(_keyboardMouseDevice->getInputDevice());
@ -749,7 +749,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
_oldHandRightClick[0] = false; _oldHandRightClick[0] = false;
_oldHandLeftClick[1] = false; _oldHandLeftClick[1] = false;
_oldHandRightClick[1] = false; _oldHandRightClick[1] = false;
auto applicationUpdater = DependencyManager::get<AutoUpdater>(); auto applicationUpdater = DependencyManager::get<AutoUpdater>();
connect(applicationUpdater.data(), &AutoUpdater::newVersionIsAvailable, dialogsManager.data(), &DialogsManager::showUpdateDialog); connect(applicationUpdater.data(), &AutoUpdater::newVersionIsAvailable, dialogsManager.data(), &DialogsManager::showUpdateDialog);
applicationUpdater->checkForUpdate(); applicationUpdater->checkForUpdate();
@ -768,7 +768,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
// If the user clicks an an entity, we will check that it's an unlocked web entity, and if so, set the focus to it // If the user clicks an an entity, we will check that it's an unlocked web entity, and if so, set the focus to it
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity,
[this, entityScriptingInterface](const EntityItemID& entityItemID, const MouseEvent& event) { [this, entityScriptingInterface](const EntityItemID& entityItemID, const MouseEvent& event) {
if (_keyboardFocusedItem != entityItemID) { if (_keyboardFocusedItem != entityItemID) {
_keyboardFocusedItem = UNKNOWN_ENTITY_ID; _keyboardFocusedItem = UNKNOWN_ENTITY_ID;
@ -817,7 +817,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
}); });
// If the user clicks somewhere where there is NO entity at all, we will release focus // If the user clicks somewhere where there is NO entity at all, we will release focus
connect(getEntities(), &EntityTreeRenderer::mousePressOffEntity, connect(getEntities(), &EntityTreeRenderer::mousePressOffEntity,
[=](const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId) { [=](const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId) {
_keyboardFocusedItem = UNKNOWN_ENTITY_ID; _keyboardFocusedItem = UNKNOWN_ENTITY_ID;
if (_keyboardFocusHighlight) { if (_keyboardFocusHighlight) {
@ -826,17 +826,17 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
}); });
connect(this, &Application::applicationStateChanged, this, &Application::activeChanged); connect(this, &Application::applicationStateChanged, this, &Application::activeChanged);
qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0); qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0);
} }
void Application::aboutToQuit() { void Application::aboutToQuit() {
emit beforeAboutToQuit(); emit beforeAboutToQuit();
getActiveDisplayPlugin()->deactivate(); getActiveDisplayPlugin()->deactivate();
_aboutToQuit = true; _aboutToQuit = true;
cleanupBeforeQuit(); cleanupBeforeQuit();
} }
@ -860,16 +860,16 @@ void Application::cleanupBeforeQuit() {
_keyboardFocusHighlight = nullptr; _keyboardFocusHighlight = nullptr;
_entities.clear(); // this will allow entity scripts to properly shutdown _entities.clear(); // this will allow entity scripts to properly shutdown
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
// send the domain a disconnect packet, force stoppage of domain-server check-ins // send the domain a disconnect packet, force stoppage of domain-server check-ins
nodeList->getDomainHandler().disconnect(); nodeList->getDomainHandler().disconnect();
nodeList->setIsShuttingDown(true); nodeList->setIsShuttingDown(true);
// tell the packet receiver we're shutting down, so it can drop packets // tell the packet receiver we're shutting down, so it can drop packets
nodeList->getPacketReceiver().setShouldDropPackets(true); nodeList->getPacketReceiver().setShouldDropPackets(true);
_entities.shutdown(); // tell the entities system we're shutting down, so it will stop running scripts _entities.shutdown(); // tell the entities system we're shutting down, so it will stop running scripts
ScriptEngine::stopAllScripts(this); // stop all currently running global scripts ScriptEngine::stopAllScripts(this); // stop all currently running global scripts
@ -947,7 +947,7 @@ Application::~Application() {
DependencyManager::destroy<GeometryCache>(); DependencyManager::destroy<GeometryCache>();
DependencyManager::destroy<ScriptCache>(); DependencyManager::destroy<ScriptCache>();
DependencyManager::destroy<SoundCache>(); DependencyManager::destroy<SoundCache>();
// cleanup the AssetClient thread // cleanup the AssetClient thread
QThread* assetThread = DependencyManager::get<AssetClient>()->thread(); QThread* assetThread = DependencyManager::get<AssetClient>()->thread();
DependencyManager::destroy<AssetClient>(); DependencyManager::destroy<AssetClient>();
@ -955,14 +955,14 @@ Application::~Application() {
assetThread->wait(); assetThread->wait();
QThread* nodeThread = DependencyManager::get<NodeList>()->thread(); QThread* nodeThread = DependencyManager::get<NodeList>()->thread();
// remove the NodeList from the DependencyManager // remove the NodeList from the DependencyManager
DependencyManager::destroy<NodeList>(); DependencyManager::destroy<NodeList>();
// ask the node thread to quit and wait until it is done // ask the node thread to quit and wait until it is done
nodeThread->quit(); nodeThread->quit();
nodeThread->wait(); nodeThread->wait();
Leapmotion::destroy(); Leapmotion::destroy();
RealSense::destroy(); RealSense::destroy();
@ -1058,7 +1058,7 @@ void Application::initializeUi() {
resizeGL(); resizeGL();
} }
}); });
// This will set up the input plugins UI // This will set up the input plugins UI
_activeInputPlugins.clear(); _activeInputPlugins.clear();
foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) {
@ -1100,8 +1100,8 @@ void Application::paintGL() {
return; return;
} }
// Some plugins process message events, potentially leading to // Some plugins process message events, potentially leading to
// re-entering a paint event. don't allow further processing if this // re-entering a paint event. don't allow further processing if this
// happens // happens
if (_inPaint) { if (_inPaint) {
return; return;
@ -1137,17 +1137,17 @@ void Application::paintGL() {
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
PerformanceTimer perfTimer("Mirror"); PerformanceTimer perfTimer("Mirror");
auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebufferDepthColor(); auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebufferDepthColor();
renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
renderRearViewMirror(&renderArgs, _mirrorViewRect); renderRearViewMirror(&renderArgs, _mirrorViewRect);
renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE;
{ {
float ratio = ((float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale()); float ratio = ((float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale());
// Flip the src and destination rect horizontally to do the mirror // Flip the src and destination rect horizontally to do the mirror
auto mirrorRect = glm::ivec4(0, 0, _mirrorViewRect.width() * ratio, _mirrorViewRect.height() * ratio); auto mirrorRect = glm::ivec4(0, 0, _mirrorViewRect.width() * ratio, _mirrorViewRect.height() * ratio);
auto mirrorRectDest = glm::ivec4(mirrorRect.z, mirrorRect.y, mirrorRect.x, mirrorRect.w); auto mirrorRectDest = glm::ivec4(mirrorRect.z, mirrorRect.y, mirrorRect.x, mirrorRect.w);
auto selfieFbo = DependencyManager::get<FramebufferCache>()->getSelfieFramebuffer(); auto selfieFbo = DependencyManager::get<FramebufferCache>()->getSelfieFramebuffer();
gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) { gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) {
batch.setFramebuffer(selfieFbo); batch.setFramebuffer(selfieFbo);
@ -1169,9 +1169,9 @@ void Application::paintGL() {
{ {
PerformanceTimer perfTimer("CameraUpdates"); PerformanceTimer perfTimer("CameraUpdates");
auto myAvatar = getMyAvatar(); auto myAvatar = getMyAvatar();
myAvatar->startCapture(); myAvatar->startCapture();
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN);
@ -1208,26 +1208,26 @@ void Application::paintGL() {
* (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); * (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f)));
} else { } else {
_myCamera.setPosition(myAvatar->getDefaultEyePosition() _myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ myAvatar->getOrientation() + myAvatar->getOrientation()
* (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f))); * (myAvatar->getScale() * myAvatar->getBoomLength() * glm::vec3(0.0f, 0.0f, 1.0f)));
} }
} }
} else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
if (isHMDMode()) { if (isHMDMode()) {
glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix());
_myCamera.setRotation(myAvatar->getWorldAlignedOrientation() _myCamera.setRotation(myAvatar->getWorldAlignedOrientation()
* glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)) * hmdRotation); * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)) * hmdRotation);
glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix());
_myCamera.setPosition(myAvatar->getDefaultEyePosition() _myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ glm::vec3(0, _raiseMirror * myAvatar->getScale(), 0) + glm::vec3(0, _raiseMirror * myAvatar->getScale(), 0)
+ (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror
+ (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))) * hmdOffset); + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))) * hmdOffset);
} else { } else {
_myCamera.setRotation(myAvatar->getWorldAlignedOrientation() _myCamera.setRotation(myAvatar->getWorldAlignedOrientation()
* glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
_myCamera.setPosition(myAvatar->getDefaultEyePosition() _myCamera.setPosition(myAvatar->getDefaultEyePosition()
+ glm::vec3(0, _raiseMirror * myAvatar->getScale(), 0) + glm::vec3(0, _raiseMirror * myAvatar->getScale(), 0)
+ (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
} }
@ -1246,7 +1246,7 @@ void Application::paintGL() {
} }
} }
} }
// Update camera position // Update camera position
if (!isHMDMode()) { if (!isHMDMode()) {
_myCamera.update(1.0f / _fps); _myCamera.update(1.0f / _fps);
} }
@ -1264,12 +1264,12 @@ void Application::paintGL() {
if (displayPlugin->isStereo()) { if (displayPlugin->isStereo()) {
// Stereo modes will typically have a larger projection matrix overall, // Stereo modes will typically have a larger projection matrix overall,
// so we ask for the 'mono' projection matrix, which for stereo and HMD // so we ask for the 'mono' projection matrix, which for stereo and HMD
// plugins will imply the combined projection for both eyes. // plugins will imply the combined projection for both eyes.
// //
// This is properly implemented for the Oculus plugins, but for OpenVR // This is properly implemented for the Oculus plugins, but for OpenVR
// and Stereo displays I'm not sure how to get / calculate it, so we're // and Stereo displays I'm not sure how to get / calculate it, so we're
// just relying on the left FOV in each case and hoping that the // just relying on the left FOV in each case and hoping that the
// overall culling margin of error doesn't cause popping in the // overall culling margin of error doesn't cause popping in the
// right eye. There are FIXMEs in the relevant plugins // right eye. There are FIXMEs in the relevant plugins
_myCamera.setProjection(displayPlugin->getProjection(Mono, _myCamera.getProjection())); _myCamera.setProjection(displayPlugin->getProjection(Mono, _myCamera.getProjection()));
renderArgs._context->enableStereo(true); renderArgs._context->enableStereo(true);
@ -1279,11 +1279,11 @@ void Application::paintGL() {
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>(); auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
float IPDScale = hmdInterface->getIPDScale(); float IPDScale = hmdInterface->getIPDScale();
// FIXME we probably don't need to set the projection matrix every frame, // FIXME we probably don't need to set the projection matrix every frame,
// only when the display plugin changes (or in non-HMD modes when the user // only when the display plugin changes (or in non-HMD modes when the user
// changes the FOV manually, which right now I don't think they can. // changes the FOV manually, which right now I don't think they can.
for_each_eye([&](Eye eye) { for_each_eye([&](Eye eye) {
// For providing the stereo eye views, the HMD head pose has already been // For providing the stereo eye views, the HMD head pose has already been
// applied to the avatar, so we need to get the difference between the head // applied to the avatar, so we need to get the difference between the head
// pose applied to the avatar and the per eye pose, and use THAT as // pose applied to the avatar and the per eye pose, and use THAT as
// the per-eye stereo matrix adjustment. // the per-eye stereo matrix adjustment.
mat4 eyeToHead = displayPlugin->getEyeToHeadTransform(eye); mat4 eyeToHead = displayPlugin->getEyeToHeadTransform(eye);
@ -1293,10 +1293,10 @@ void Application::paintGL() {
mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * IPDScale); mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * IPDScale);
eyeOffsets[eye] = eyeOffsetTransform; eyeOffsets[eye] = eyeOffsetTransform;
// Tell the plugin what pose we're using to render. In this case we're just using the // Tell the plugin what pose we're using to render. In this case we're just using the
// unmodified head pose because the only plugin that cares (the Oculus plugin) uses it // unmodified head pose because the only plugin that cares (the Oculus plugin) uses it
// for rotational timewarp. If we move to support positonal timewarp, we need to // for rotational timewarp. If we move to support positonal timewarp, we need to
// ensure this contains the full pose composed with the eye offsets. // ensure this contains the full pose composed with the eye offsets.
mat4 headPose = displayPlugin->getHeadPose(); mat4 headPose = displayPlugin->getHeadPose();
displayPlugin->setEyeRenderPose(eye, headPose); displayPlugin->setEyeRenderPose(eye, headPose);
@ -1343,7 +1343,7 @@ void Application::paintGL() {
PerformanceTimer perfTimer("pluginOutput"); PerformanceTimer perfTimer("pluginOutput");
auto primaryFbo = framebufferCache->getPrimaryFramebuffer(); auto primaryFbo = framebufferCache->getPrimaryFramebuffer();
GLuint finalTexture = gpu::GLBackend::getTextureID(primaryFbo->getRenderBuffer(0)); GLuint finalTexture = gpu::GLBackend::getTextureID(primaryFbo->getRenderBuffer(0));
// Ensure the rendering context commands are completed when rendering // Ensure the rendering context commands are completed when rendering
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0); GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
// Ensure the sync object is flushed to the driver thread before releasing the context // Ensure the sync object is flushed to the driver thread before releasing the context
// CRITICAL for the mac driver apparently. // CRITICAL for the mac driver apparently.
@ -1394,7 +1394,7 @@ void Application::audioMuteToggled() {
} }
void Application::faceTrackerMuteToggled() { void Application::faceTrackerMuteToggled() {
QAction* muteAction = Menu::getInstance()->getActionForOption(MenuOption::MuteFaceTracking); QAction* muteAction = Menu::getInstance()->getActionForOption(MenuOption::MuteFaceTracking);
Q_CHECK_PTR(muteAction); Q_CHECK_PTR(muteAction);
bool isMuted = getSelectedFaceTracker()->isMuted(); bool isMuted = getSelectedFaceTracker()->isMuted();
@ -1427,7 +1427,7 @@ void Application::resizeGL() {
if (nullptr == _displayPlugin) { if (nullptr == _displayPlugin) {
return; return;
} }
auto displayPlugin = getActiveDisplayPlugin(); auto displayPlugin = getActiveDisplayPlugin();
// Set the desired FBO texture size. If it hasn't changed, this does nothing. // Set the desired FBO texture size. If it hasn't changed, this does nothing.
// Otherwise, it must rebuild the FBOs // Otherwise, it must rebuild the FBOs
@ -1437,14 +1437,14 @@ void Application::resizeGL() {
_renderResolution = renderSize; _renderResolution = renderSize;
DependencyManager::get<FramebufferCache>()->setFrameBufferSize(fromGlm(renderSize)); DependencyManager::get<FramebufferCache>()->setFrameBufferSize(fromGlm(renderSize));
} }
// FIXME the aspect ratio for stereo displays is incorrect based on this. // FIXME the aspect ratio for stereo displays is incorrect based on this.
float aspectRatio = displayPlugin->getRecommendedAspectRatio(); float aspectRatio = displayPlugin->getRecommendedAspectRatio();
_myCamera.setProjection(glm::perspective(glm::radians(_fieldOfView.get()), aspectRatio, _myCamera.setProjection(glm::perspective(glm::radians(_fieldOfView.get()), aspectRatio,
DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP)); DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP));
// Possible change in aspect ratio // Possible change in aspect ratio
loadViewFrustum(_myCamera, _viewFrustum); loadViewFrustum(_myCamera, _viewFrustum);
auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto offscreenUi = DependencyManager::get<OffscreenUi>();
auto uiSize = displayPlugin->getRecommendedUiSize(); auto uiSize = displayPlugin->getRecommendedUiSize();
// Bit of a hack since there's no device pixel ratio change event I can find. // Bit of a hack since there's no device pixel ratio change event I can find.
@ -1613,7 +1613,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
if (isMeta) { if (isMeta) {
auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto offscreenUi = DependencyManager::get<OffscreenUi>();
offscreenUi->load("Browser.qml"); offscreenUi->load("Browser.qml");
} }
break; break;
case Qt::Key_X: case Qt::Key_X:
@ -2109,7 +2109,7 @@ void Application::wheelEvent(QWheelEvent* event) {
if (_controllerScriptingInterface->isWheelCaptured()) { if (_controllerScriptingInterface->isWheelCaptured()) {
return; return;
} }
if (Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) { if (Menu::getInstance()->isOptionChecked(KeyboardMouseDevice::NAME)) {
_keyboardMouseDevice->wheelEvent(event); _keyboardMouseDevice->wheelEvent(event);
} }
@ -2227,7 +2227,7 @@ void Application::idle(uint64_t now) {
_idleLoopStdev.reset(); _idleLoopStdev.reset();
} }
} }
_overlayConductor.update(secondsSinceLastUpdate); _overlayConductor.update(secondsSinceLastUpdate);
// check for any requested background downloads. // check for any requested background downloads.
@ -2481,7 +2481,7 @@ void Application::init() {
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString); DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
qCDebug(interfaceapp) << "Loaded settings"; qCDebug(interfaceapp) << "Loaded settings";
Leapmotion::init(); Leapmotion::init();
RealSense::init(); RealSense::init();
@ -2539,7 +2539,7 @@ void Application::setAvatarUpdateThreading(bool isThreaded) {
if (_avatarUpdate && (_avatarUpdate->isThreaded() == isThreaded)) { if (_avatarUpdate && (_avatarUpdate->isThreaded() == isThreaded)) {
return; return;
} }
auto myAvatar = getMyAvatar(); auto myAvatar = getMyAvatar();
bool isRigEnabled = myAvatar->getEnableRigAnimations(); bool isRigEnabled = myAvatar->getEnableRigAnimations();
bool isGraphEnabled = myAvatar->getEnableAnimGraph(); bool isGraphEnabled = myAvatar->getEnableAnimGraph();
@ -2756,7 +2756,7 @@ void Application::updateDialogs(float deltaTime) {
if(audioStatsDialog) { if(audioStatsDialog) {
audioStatsDialog->update(); audioStatsDialog->update();
} }
// Update bandwidth dialog, if any // Update bandwidth dialog, if any
BandwidthDialog* bandwidthDialog = dialogsManager->getBandwidthDialog(); BandwidthDialog* bandwidthDialog = dialogsManager->getBandwidthDialog();
if (bandwidthDialog) { if (bandwidthDialog) {
@ -2892,7 +2892,7 @@ void Application::update(float deltaTime) {
_entities.getTree()->withWriteLock([&] { _entities.getTree()->withWriteLock([&] {
_physicsEngine->stepSimulation(); _physicsEngine->stepSimulation();
}); });
if (_physicsEngine->hasOutgoingChanges()) { if (_physicsEngine->hasOutgoingChanges()) {
_entities.getTree()->withWriteLock([&] { _entities.getTree()->withWriteLock([&] {
_entitySimulation.handleOutgoingChanges(_physicsEngine->getOutgoingChanges(), _physicsEngine->getSessionID()); _entitySimulation.handleOutgoingChanges(_physicsEngine->getOutgoingChanges(), _physicsEngine->getSessionID());
@ -3026,10 +3026,10 @@ int Application::sendNackPackets() {
foreach(const OCTREE_PACKET_SEQUENCE& missingNumber, missingSequenceNumbers) { foreach(const OCTREE_PACKET_SEQUENCE& missingNumber, missingSequenceNumbers) {
nackPacketList->writePrimitive(missingNumber); nackPacketList->writePrimitive(missingNumber);
} }
if (nackPacketList->getNumPackets()) { if (nackPacketList->getNumPackets()) {
packetsSent += nackPacketList->getNumPackets(); packetsSent += nackPacketList->getNumPackets();
// send the packet list // send the packet list
nodeList->sendPacketList(std::move(nackPacketList), *node); nodeList->sendPacketList(std::move(nackPacketList), *node);
} }
@ -3635,7 +3635,7 @@ void Application::renderRearViewMirror(RenderArgs* renderArgs, const QRect& regi
float fov = MIRROR_FIELD_OF_VIEW; float fov = MIRROR_FIELD_OF_VIEW;
auto myAvatar = getMyAvatar(); auto myAvatar = getMyAvatar();
// bool eyeRelativeCamera = false; // bool eyeRelativeCamera = false;
if (billboard) { if (billboard) {
fov = BILLBOARD_FIELD_OF_VIEW; // degees fov = BILLBOARD_FIELD_OF_VIEW; // degees
@ -3843,7 +3843,7 @@ void Application::nodeKilled(SharedNodePointer node) {
Menu::getInstance()->getActionForOption(MenuOption::UploadAsset)->setEnabled(false); Menu::getInstance()->getActionForOption(MenuOption::UploadAsset)->setEnabled(false);
} }
} }
void Application::trackIncomingOctreePacket(NLPacket& packet, SharedNodePointer sendingNode, bool wasStatsPacket) { void Application::trackIncomingOctreePacket(NLPacket& packet, SharedNodePointer sendingNode, bool wasStatsPacket) {
// Attempt to identify the sender from its address. // Attempt to identify the sender from its address.
@ -3868,7 +3868,7 @@ int Application::processOctreeStats(NLPacket& packet, SharedNodePointer sendingN
int statsMessageLength = 0; int statsMessageLength = 0;
const QUuid& nodeUUID = sendingNode->getUUID(); const QUuid& nodeUUID = sendingNode->getUUID();
// now that we know the node ID, let's add these stats to the stats for that node... // now that we know the node ID, let's add these stats to the stats for that node...
_octreeServerSceneStats.withWriteLock([&] { _octreeServerSceneStats.withWriteLock([&] {
OctreeSceneStats& octreeStats = _octreeServerSceneStats[nodeUUID]; OctreeSceneStats& octreeStats = _octreeServerSceneStats[nodeUUID];
@ -4069,7 +4069,7 @@ bool Application::acceptURL(const QString& urlString, bool defaultUpload) {
Qt::AutoConnection, Q_ARG(const QString&, urlString)); Qt::AutoConnection, Q_ARG(const QString&, urlString));
return true; return true;
} }
QUrl url(urlString); QUrl url(urlString);
QHashIterator<QString, AcceptURLMethod> i(_acceptedExtensions); QHashIterator<QString, AcceptURLMethod> i(_acceptedExtensions);
QString lowerPath = url.path().toLower(); QString lowerPath = url.path().toLower();
@ -4080,7 +4080,7 @@ bool Application::acceptURL(const QString& urlString, bool defaultUpload) {
return (this->*method)(urlString); return (this->*method)(urlString);
} }
} }
return defaultUpload && askToUploadAsset(urlString); return defaultUpload && askToUploadAsset(urlString);
} }
@ -4162,10 +4162,10 @@ bool Application::askToUploadAsset(const QString& filename) {
QString("You don't have upload rights on that domain.\n\n")); QString("You don't have upload rights on that domain.\n\n"));
return false; return false;
} }
QUrl url { filename }; QUrl url { filename };
if (auto upload = DependencyManager::get<AssetClient>()->createUpload(url.toLocalFile())) { if (auto upload = DependencyManager::get<AssetClient>()->createUpload(url.toLocalFile())) {
QMessageBox messageBox; QMessageBox messageBox;
messageBox.setWindowTitle("Asset upload"); messageBox.setWindowTitle("Asset upload");
messageBox.setText("You are about to upload the following file to the asset server:\n" + messageBox.setText("You are about to upload the following file to the asset server:\n" +
@ -4173,19 +4173,19 @@ bool Application::askToUploadAsset(const QString& filename) {
messageBox.setInformativeText("Do you want to continue?"); messageBox.setInformativeText("Do you want to continue?");
messageBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); messageBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
messageBox.setDefaultButton(QMessageBox::Ok); messageBox.setDefaultButton(QMessageBox::Ok);
// Option to drop model in world for models // Option to drop model in world for models
if (filename.endsWith(FBX_EXTENSION) || filename.endsWith(OBJ_EXTENSION)) { if (filename.endsWith(FBX_EXTENSION) || filename.endsWith(OBJ_EXTENSION)) {
auto checkBox = new QCheckBox(&messageBox); auto checkBox = new QCheckBox(&messageBox);
checkBox->setText("Add to scene"); checkBox->setText("Add to scene");
messageBox.setCheckBox(checkBox); messageBox.setCheckBox(checkBox);
} }
if (messageBox.exec() != QMessageBox::Ok) { if (messageBox.exec() != QMessageBox::Ok) {
upload->deleteLater(); upload->deleteLater();
return false; return false;
} }
// connect to the finished signal so we know when the AssetUpload is done // connect to the finished signal so we know when the AssetUpload is done
if (messageBox.checkBox() && (messageBox.checkBox()->checkState() == Qt::Checked)) { if (messageBox.checkBox() && (messageBox.checkBox()->checkState() == Qt::Checked)) {
// Custom behavior for models // Custom behavior for models
@ -4195,12 +4195,12 @@ bool Application::askToUploadAsset(const QString& filename) {
&AssetUploadDialogFactory::getInstance(), &AssetUploadDialogFactory::getInstance(),
&AssetUploadDialogFactory::handleUploadFinished); &AssetUploadDialogFactory::handleUploadFinished);
} }
// start the upload now // start the upload now
upload->start(); upload->start();
return true; return true;
} }
// display a message box with the error // display a message box with the error
QMessageBox::warning(_window, "Failed Upload", QString("Failed to upload %1.\n\n").arg(filename)); QMessageBox::warning(_window, "Failed Upload", QString("Failed to upload %1.\n\n").arg(filename));
return false; return false;
@ -4208,20 +4208,20 @@ bool Application::askToUploadAsset(const QString& filename) {
void Application::modelUploadFinished(AssetUpload* upload, const QString& hash) { void Application::modelUploadFinished(AssetUpload* upload, const QString& hash) {
auto filename = QFileInfo(upload->getFilename()).fileName(); auto filename = QFileInfo(upload->getFilename()).fileName();
if ((upload->getError() == AssetUpload::NoError) && if ((upload->getError() == AssetUpload::NoError) &&
(filename.endsWith(FBX_EXTENSION) || filename.endsWith(OBJ_EXTENSION))) { (filename.endsWith(FBX_EXTENSION) || filename.endsWith(OBJ_EXTENSION))) {
auto entities = DependencyManager::get<EntityScriptingInterface>(); auto entities = DependencyManager::get<EntityScriptingInterface>();
EntityItemProperties properties; EntityItemProperties properties;
properties.setType(EntityTypes::Model); properties.setType(EntityTypes::Model);
properties.setModelURL(QString("%1:%2.%3").arg(URL_SCHEME_ATP).arg(hash).arg(upload->getExtension())); properties.setModelURL(QString("%1:%2.%3").arg(URL_SCHEME_ATP).arg(hash).arg(upload->getExtension()));
properties.setPosition(_myCamera.getPosition() + _myCamera.getOrientation() * Vectors::FRONT * 2.0f); properties.setPosition(_myCamera.getPosition() + _myCamera.getOrientation() * Vectors::FRONT * 2.0f);
properties.setName(QUrl(upload->getFilename()).fileName()); properties.setName(QUrl(upload->getFilename()).fileName());
entities->addEntity(properties); entities->addEntity(properties);
upload->deleteLater(); upload->deleteLater();
} else { } else {
AssetUploadDialogFactory::getInstance().handleUploadFinished(upload, hash); AssetUploadDialogFactory::getInstance().handleUploadFinished(upload, hash);
@ -4510,7 +4510,7 @@ void Application::takeSnapshot() {
_snapshotShareDialog = new SnapshotShareDialog(fileName, _glWidget); _snapshotShareDialog = new SnapshotShareDialog(fileName, _glWidget);
} }
_snapshotShareDialog->show(); _snapshotShareDialog->show();
} }
float Application::getRenderResolutionScale() const { float Application::getRenderResolutionScale() const {
@ -4755,8 +4755,8 @@ void Application::updateDisplayMode() {
return; return;
} }
// Some plugins *cough* Oculus *cough* process message events from inside their // Some plugins *cough* Oculus *cough* process message events from inside their
// display function, and we don't want to change the display plugin underneath // display function, and we don't want to change the display plugin underneath
// the paintGL call, so we need to guard against that // the paintGL call, so we need to guard against that
if (_inPaint) { if (_inPaint) {
qDebug() << "Deferring plugin switch until out of painting"; qDebug() << "Deferring plugin switch until out of painting";
@ -4790,14 +4790,14 @@ void Application::updateDisplayMode() {
oldDisplayPlugin = _displayPlugin; oldDisplayPlugin = _displayPlugin;
_displayPlugin = newDisplayPlugin; _displayPlugin = newDisplayPlugin;
// If the displayPlugin is a screen based HMD, then it will want the HMDTools displayed // If the displayPlugin is a screen based HMD, then it will want the HMDTools displayed
// Direct Mode HMDs (like windows Oculus) will be isHmd() but will have a screen of -1 // Direct Mode HMDs (like windows Oculus) will be isHmd() but will have a screen of -1
bool newPluginWantsHMDTools = newDisplayPlugin ? bool newPluginWantsHMDTools = newDisplayPlugin ?
(newDisplayPlugin->isHmd() && (newDisplayPlugin->getHmdScreen() >= 0)) : false; (newDisplayPlugin->isHmd() && (newDisplayPlugin->getHmdScreen() >= 0)) : false;
bool oldPluginWantedHMDTools = oldDisplayPlugin ? bool oldPluginWantedHMDTools = oldDisplayPlugin ?
(oldDisplayPlugin->isHmd() && (oldDisplayPlugin->getHmdScreen() >= 0)) : false; (oldDisplayPlugin->isHmd() && (oldDisplayPlugin->getHmdScreen() >= 0)) : false;
// Only show the hmd tools after the correct plugin has // Only show the hmd tools after the correct plugin has
// been activated so that it's UI is setup correctly // been activated so that it's UI is setup correctly
if (newPluginWantsHMDTools) { if (newPluginWantsHMDTools) {
@ -4807,7 +4807,7 @@ void Application::updateDisplayMode() {
if (oldDisplayPlugin) { if (oldDisplayPlugin) {
oldDisplayPlugin->deactivate(); oldDisplayPlugin->deactivate();
_offscreenContext->makeCurrent(); _offscreenContext->makeCurrent();
// if the old plugin was HMD and the new plugin is not HMD, then hide our hmdtools // if the old plugin was HMD and the new plugin is not HMD, then hide our hmdtools
if (oldPluginWantedHMDTools && !newPluginWantsHMDTools) { if (oldPluginWantedHMDTools && !newPluginWantsHMDTools) {
DependencyManager::get<DialogsManager>()->hmdTools(false); DependencyManager::get<DialogsManager>()->hmdTools(false);
@ -4940,7 +4940,7 @@ void Application::setPalmData(Hand* hand, const controller::Pose& pose, float de
rawVelocity = glm::vec3(0.0f); rawVelocity = glm::vec3(0.0f);
} }
palm.setRawVelocity(rawVelocity); // meters/sec palm.setRawVelocity(rawVelocity); // meters/sec
// Angular Velocity of Palm // Angular Velocity of Palm
glm::quat deltaRotation = rotation * glm::inverse(palm.getRawRotation()); glm::quat deltaRotation = rotation * glm::inverse(palm.getRawRotation());
glm::vec3 angularVelocity(0.0f); glm::vec3 angularVelocity(0.0f);
@ -5020,7 +5020,7 @@ void Application::emulateMouse(Hand* hand, float click, float shift, HandData::H
pos.setY(canvasSize.y / 2.0f + cursorRange * yAngle); pos.setY(canvasSize.y / 2.0f + cursorRange * yAngle);
} }
//If we are off screen then we should stop processing, and if a trigger or bumper is pressed, //If we are off screen then we should stop processing, and if a trigger or bumper is pressed,
//we should unpress them. //we should unpress them.
if (pos.x() == INT_MAX) { if (pos.x() == INT_MAX) {

View file

@ -35,4 +35,4 @@ namespace AudioConstants {
} }
#endif // hifi_AudioConstants_h #endif // hifi_AudioConstants_h

View file

@ -622,7 +622,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
auto nodeList = DependencyManager::get<NodeList>(); auto nodeList = DependencyManager::get<NodeList>();
const QUuid& myNodeID = nodeList->getSessionUUID(); const QUuid& myNodeID = nodeList->getSessionUUID();
bool weOwnSimulation = _simulationOwner.matchesValidID(myNodeID); bool weOwnSimulation = _simulationOwner.matchesValidID(myNodeID);
if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_SIMULATION_OWNER_AND_ACTIONS_OVER_WIRE) { if (args.bitstreamVersion >= VERSION_ENTITIES_HAVE_SIMULATION_OWNER_AND_ACTIONS_OVER_WIRE) {
// pack SimulationOwner and terse update properties near each other // pack SimulationOwner and terse update properties near each other
@ -799,17 +799,11 @@ void EntityItem::setDensity(float density) {
_density = glm::max(glm::min(density, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); _density = glm::max(glm::min(density, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY);
} }
const float ACTIVATION_RELATIVE_DENSITY_DELTA = 0.01f; // 1 percent
void EntityItem::updateDensity(float density) { void EntityItem::updateDensity(float density) {
float clampedDensity = glm::max(glm::min(density, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); float clampedDensity = glm::max(glm::min(density, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY);
if (_density != clampedDensity) { if (_density != clampedDensity) {
_density = clampedDensity; _density = clampedDensity;
_dirtyFlags |= Simulation::DIRTY_MASS;
if (fabsf(_density - clampedDensity) / _density > ACTIVATION_RELATIVE_DENSITY_DELTA) {
// the density has changed enough that we should update the physics simulation
_dirtyFlags |= Simulation::DIRTY_MASS;
}
} }
} }
@ -822,11 +816,16 @@ void EntityItem::setMass(float mass) {
// compute new density // compute new density
const float MIN_VOLUME = 1.0e-6f; // 0.001mm^3 const float MIN_VOLUME = 1.0e-6f; // 0.001mm^3
float newDensity = 1.0f;
if (volume < 1.0e-6f) { if (volume < 1.0e-6f) {
// avoid divide by zero // avoid divide by zero
_density = glm::min(mass / MIN_VOLUME, ENTITY_ITEM_MAX_DENSITY); newDensity = glm::min(mass / MIN_VOLUME, ENTITY_ITEM_MAX_DENSITY);
} else { } else {
_density = glm::max(glm::min(mass / volume, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); newDensity = glm::max(glm::min(mass / volume, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY);
}
if (_density != newDensity) {
_density = newDensity;
_dirtyFlags |= Simulation::DIRTY_MASS;
} }
} }
@ -884,12 +883,12 @@ void EntityItem::simulateKinematicMotion(float timeElapsed, bool setFlags) {
#ifdef WANT_DEBUG #ifdef WANT_DEBUG
qCDebug(entities) << "EntityItem::simulateKinematicMotion timeElapsed" << timeElapsed; qCDebug(entities) << "EntityItem::simulateKinematicMotion timeElapsed" << timeElapsed;
#endif #endif
const float MIN_TIME_SKIP = 0.0f; const float MIN_TIME_SKIP = 0.0f;
const float MAX_TIME_SKIP = 1.0f; // in seconds const float MAX_TIME_SKIP = 1.0f; // in seconds
timeElapsed = glm::clamp(timeElapsed, MIN_TIME_SKIP, MAX_TIME_SKIP); timeElapsed = glm::clamp(timeElapsed, MIN_TIME_SKIP, MAX_TIME_SKIP);
if (hasActions()) { if (hasActions()) {
return; return;
} }
@ -1312,24 +1311,16 @@ void EntityItem::updatePosition(const glm::vec3& value) {
if (shouldSuppressLocationEdits()) { if (shouldSuppressLocationEdits()) {
return; return;
} }
auto delta = glm::distance(getPosition(), value); if (getPosition() != value) {
if (delta > IGNORE_POSITION_DELTA) {
_dirtyFlags |= Simulation::DIRTY_POSITION;
setPosition(value); setPosition(value);
if (delta > ACTIVATION_POSITION_DELTA) { _dirtyFlags |= Simulation::DIRTY_POSITION;
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
}
} }
} }
void EntityItem::updateDimensions(const glm::vec3& value) { void EntityItem::updateDimensions(const glm::vec3& value) {
auto delta = glm::distance(getDimensions(), value); if (getDimensions() != value) {
if (delta > IGNORE_DIMENSIONS_DELTA) {
setDimensions(value); setDimensions(value);
if (delta > ACTIVATION_DIMENSIONS_DELTA) { _dirtyFlags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
// rebuilding the shape will always activate
_dirtyFlags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS);
}
} }
} }
@ -1339,14 +1330,7 @@ void EntityItem::updateRotation(const glm::quat& rotation) {
} }
if (getRotation() != rotation) { if (getRotation() != rotation) {
setRotation(rotation); setRotation(rotation);
_dirtyFlags |= Simulation::DIRTY_ROTATION;
auto alignmentDot = glm::abs(glm::dot(getRotation(), rotation));
if (alignmentDot < IGNORE_ALIGNMENT_DOT) {
_dirtyFlags |= Simulation::DIRTY_ROTATION;
}
if (alignmentDot < ACTIVATION_ALIGNMENT_DOT) {
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
}
} }
} }
@ -1367,11 +1351,8 @@ void EntityItem::updateMass(float mass) {
newDensity = glm::max(glm::min(mass / volume, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); newDensity = glm::max(glm::min(mass / volume, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY);
} }
float oldDensity = _density; if (_density != newDensity) {
_density = newDensity; _density = newDensity;
if (fabsf(_density - oldDensity) / _density > ACTIVATION_RELATIVE_DENSITY_DELTA) {
// the density has changed enough that we should update the physics simulation
_dirtyFlags |= Simulation::DIRTY_MASS; _dirtyFlags |= Simulation::DIRTY_MASS;
} }
} }
@ -1380,38 +1361,29 @@ void EntityItem::updateVelocity(const glm::vec3& value) {
if (shouldSuppressLocationEdits()) { if (shouldSuppressLocationEdits()) {
return; return;
} }
auto delta = glm::distance(_velocity, value); if (_velocity != value) {
if (delta > IGNORE_LINEAR_VELOCITY_DELTA) {
_dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY;
const float MIN_LINEAR_SPEED = 0.001f; const float MIN_LINEAR_SPEED = 0.001f;
if (glm::length(value) < MIN_LINEAR_SPEED) { if (glm::length(value) < MIN_LINEAR_SPEED) {
_velocity = ENTITY_ITEM_ZERO_VEC3; _velocity = ENTITY_ITEM_ZERO_VEC3;
} else { } else {
_velocity = value; _velocity = value;
// only activate when setting non-zero velocity
if (delta > ACTIVATION_LINEAR_VELOCITY_DELTA) {
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
}
} }
_dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY;
} }
} }
void EntityItem::updateDamping(float value) { void EntityItem::updateDamping(float value) {
auto clampedDamping = glm::clamp(value, 0.0f, 1.0f); auto clampedDamping = glm::clamp(value, 0.0f, 1.0f);
if (fabsf(_damping - clampedDamping) > IGNORE_DAMPING_DELTA) { if (_damping != clampedDamping) {
_damping = clampedDamping; _damping = clampedDamping;
_dirtyFlags |= Simulation::DIRTY_MATERIAL; _dirtyFlags |= Simulation::DIRTY_MATERIAL;
} }
} }
void EntityItem::updateGravity(const glm::vec3& value) { void EntityItem::updateGravity(const glm::vec3& value) {
auto delta = glm::distance(_gravity, value); if (_gravity != value) {
if (delta > IGNORE_GRAVITY_DELTA) {
_gravity = value; _gravity = value;
_dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY; _dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY;
if (delta > ACTIVATION_GRAVITY_DELTA) {
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
}
} }
} }
@ -1419,25 +1391,20 @@ void EntityItem::updateAngularVelocity(const glm::vec3& value) {
if (shouldSuppressLocationEdits()) { if (shouldSuppressLocationEdits()) {
return; return;
} }
auto delta = glm::distance(_angularVelocity, value); if (_angularVelocity != value) {
if (delta > IGNORE_ANGULAR_VELOCITY_DELTA) {
_dirtyFlags |= Simulation::DIRTY_ANGULAR_VELOCITY;
const float MIN_ANGULAR_SPEED = 0.0002f; const float MIN_ANGULAR_SPEED = 0.0002f;
if (glm::length(value) < MIN_ANGULAR_SPEED) { if (glm::length(value) < MIN_ANGULAR_SPEED) {
_angularVelocity = ENTITY_ITEM_ZERO_VEC3; _angularVelocity = ENTITY_ITEM_ZERO_VEC3;
} else { } else {
_angularVelocity = value; _angularVelocity = value;
// only activate when setting non-zero velocity
if (delta > ACTIVATION_ANGULAR_VELOCITY_DELTA) {
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
}
} }
_dirtyFlags |= Simulation::DIRTY_ANGULAR_VELOCITY;
} }
} }
void EntityItem::updateAngularDamping(float value) { void EntityItem::updateAngularDamping(float value) {
auto clampedDamping = glm::clamp(value, 0.0f, 1.0f); auto clampedDamping = glm::clamp(value, 0.0f, 1.0f);
if (fabsf(_angularDamping - clampedDamping) > IGNORE_DAMPING_DELTA) { if (_angularDamping != clampedDamping) {
_angularDamping = clampedDamping; _angularDamping = clampedDamping;
_dirtyFlags |= Simulation::DIRTY_MATERIAL; _dirtyFlags |= Simulation::DIRTY_MATERIAL;
} }

View file

@ -48,6 +48,7 @@ namespace render {
class PendingChanges; class PendingChanges;
} }
/*
// these thesholds determine what updates will be ignored (client and server) // these thesholds determine what updates will be ignored (client and server)
const float IGNORE_POSITION_DELTA = 0.0001f; const float IGNORE_POSITION_DELTA = 0.0001f;
const float IGNORE_DIMENSIONS_DELTA = 0.0005f; const float IGNORE_DIMENSIONS_DELTA = 0.0005f;
@ -64,6 +65,7 @@ const float ACTIVATION_ALIGNMENT_DOT = 0.99990f;
const float ACTIVATION_LINEAR_VELOCITY_DELTA = 0.01f; const float ACTIVATION_LINEAR_VELOCITY_DELTA = 0.01f;
const float ACTIVATION_GRAVITY_DELTA = 0.1f; const float ACTIVATION_GRAVITY_DELTA = 0.1f;
const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f; const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f;
*/
#define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0; #define DONT_ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() = 0;
#define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { }; #define ALLOW_INSTANTIATION virtual void pureVirtualFunctionPlaceHolder() { };

View file

@ -95,7 +95,7 @@ void EntityMotionState::updateServerPhysicsVariables(const QUuid& sessionID) {
} }
// virtual // virtual
bool EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) { bool EntityMotionState::handleEasyChanges(uint32_t& flags, PhysicsEngine* engine) {
assert(entityTreeIsLocked()); assert(entityTreeIsLocked());
updateServerPhysicsVariables(engine->getSessionID()); updateServerPhysicsVariables(engine->getSessionID());
ObjectMotionState::handleEasyChanges(flags, engine); ObjectMotionState::handleEasyChanges(flags, engine);
@ -120,7 +120,7 @@ bool EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine)
} }
if (flags & Simulation::DIRTY_SIMULATOR_OWNERSHIP) { if (flags & Simulation::DIRTY_SIMULATOR_OWNERSHIP) {
// (DIRTY_SIMULATOR_OWNERSHIP really means "we should bid for ownership with SCRIPT priority") // (DIRTY_SIMULATOR_OWNERSHIP really means "we should bid for ownership with SCRIPT priority")
// we're manipulating this object directly via script, so we artificially // we're manipulating this object directly via script, so we artificially
// manipulate the logic to trigger an immediate bid for ownership // manipulate the logic to trigger an immediate bid for ownership
setOutgoingPriority(SCRIPT_EDIT_SIMULATION_PRIORITY); setOutgoingPriority(SCRIPT_EDIT_SIMULATION_PRIORITY);
} }
@ -133,7 +133,7 @@ bool EntityMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine)
// virtual // virtual
bool EntityMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine) { bool EntityMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) {
updateServerPhysicsVariables(engine->getSessionID()); updateServerPhysicsVariables(engine->getSessionID());
return ObjectMotionState::handleHardAndEasyChanges(flags, engine); return ObjectMotionState::handleHardAndEasyChanges(flags, engine);
} }

View file

@ -29,8 +29,8 @@ public:
virtual ~EntityMotionState(); virtual ~EntityMotionState();
void updateServerPhysicsVariables(const QUuid& sessionID); void updateServerPhysicsVariables(const QUuid& sessionID);
virtual bool handleEasyChanges(uint32_t flags, PhysicsEngine* engine); virtual bool handleEasyChanges(uint32_t& flags, PhysicsEngine* engine);
virtual bool handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine); virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine);
/// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem /// \return MOTION_TYPE_DYNAMIC or MOTION_TYPE_STATIC based on params set in EntityItem
virtual MotionType computeObjectMotionType() const; virtual MotionType computeObjectMotionType() const;

View file

@ -17,6 +17,14 @@
#include "PhysicsHelpers.h" #include "PhysicsHelpers.h"
#include "PhysicsLogging.h" #include "PhysicsLogging.h"
// these thresholds determine what updates (object-->body) will activate the physical object
const float ACTIVATION_POSITION_DELTA = 0.005f;
const float ACTIVATION_ALIGNMENT_DOT = 0.99990f;
const float ACTIVATION_LINEAR_VELOCITY_DELTA = 0.01f;
const float ACTIVATION_GRAVITY_DELTA = 0.1f;
const float ACTIVATION_ANGULAR_VELOCITY_DELTA = 0.03f;
// origin of physics simulation in world-frame // origin of physics simulation in world-frame
glm::vec3 _worldOffset(0.0f); glm::vec3 _worldOffset(0.0f);
@ -128,28 +136,65 @@ void ObjectMotionState::setRigidBody(btRigidBody* body) {
} }
} }
bool ObjectMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine) { bool ObjectMotionState::handleEasyChanges(uint32_t& flags, PhysicsEngine* engine) {
if (flags & Simulation::DIRTY_POSITION) { if (flags & Simulation::DIRTY_POSITION) {
btTransform worldTrans; btTransform worldTrans = _body->getWorldTransform();
if (flags & Simulation::DIRTY_ROTATION) { btVector3 newPosition = glmToBullet(getObjectPosition());
worldTrans.setRotation(glmToBullet(getObjectRotation())); float delta = (newPosition - worldTrans.getOrigin()).length();
} else { if (delta > ACTIVATION_POSITION_DELTA) {
worldTrans = _body->getWorldTransform(); flags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
}
worldTrans.setOrigin(newPosition);
if (flags & Simulation::DIRTY_ROTATION) {
btQuaternion newRotation = glmToBullet(getObjectRotation());
float alignmentDot = fabsf(worldTrans.getRotation().dot(newRotation));
if (alignmentDot < ACTIVATION_ALIGNMENT_DOT) {
flags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
}
worldTrans.setRotation(newRotation);
} }
worldTrans.setOrigin(glmToBullet(getObjectPosition()));
_body->setWorldTransform(worldTrans); _body->setWorldTransform(worldTrans);
} else if (flags & Simulation::DIRTY_ROTATION) { } else if (flags & Simulation::DIRTY_ROTATION) {
btTransform worldTrans = _body->getWorldTransform(); btTransform worldTrans = _body->getWorldTransform();
worldTrans.setRotation(glmToBullet(getObjectRotation())); btQuaternion newRotation = glmToBullet(getObjectRotation());
float alignmentDot = fabsf(worldTrans.getRotation().dot(newRotation));
if (alignmentDot < ACTIVATION_ALIGNMENT_DOT) {
flags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
}
worldTrans.setRotation(newRotation);
_body->setWorldTransform(worldTrans); _body->setWorldTransform(worldTrans);
} }
if (flags & Simulation::DIRTY_LINEAR_VELOCITY) { if (flags & Simulation::DIRTY_LINEAR_VELOCITY) {
_body->setLinearVelocity(glmToBullet(getObjectLinearVelocity())); btVector3 newLinearVelocity = glmToBullet(getObjectLinearVelocity());
_body->setGravity(glmToBullet(getObjectGravity())); if (!(flags & Simulation::DIRTY_PHYSICS_ACTIVATION)) {
float delta = (newLinearVelocity - _body->getLinearVelocity()).length();
if (delta > ACTIVATION_LINEAR_VELOCITY_DELTA) {
flags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
}
}
_body->setLinearVelocity(newLinearVelocity);
btVector3 newGravity = glmToBullet(getObjectGravity());
if (!(flags & Simulation::DIRTY_PHYSICS_ACTIVATION)) {
float delta = (newGravity - _body->getGravity()).length();
if (delta > ACTIVATION_GRAVITY_DELTA ||
(delta > 0.0f && _body->getGravity().length2() == 0.0f)) {
flags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
}
}
_body->setGravity(newGravity);
} }
if (flags & Simulation::DIRTY_ANGULAR_VELOCITY) { if (flags & Simulation::DIRTY_ANGULAR_VELOCITY) {
_body->setAngularVelocity(glmToBullet(getObjectAngularVelocity())); btVector3 newAngularVelocity = glmToBullet(getObjectAngularVelocity());
if (!(flags & Simulation::DIRTY_PHYSICS_ACTIVATION)) {
float delta = (newAngularVelocity - _body->getAngularVelocity()).length();
if (delta > ACTIVATION_ANGULAR_VELOCITY_DELTA) {
flags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
}
}
_body->setAngularVelocity(newAngularVelocity);
} }
if (flags & Simulation::DIRTY_MATERIAL) { if (flags & Simulation::DIRTY_MATERIAL) {
@ -163,7 +208,7 @@ bool ObjectMotionState::handleEasyChanges(uint32_t flags, PhysicsEngine* engine)
return true; return true;
} }
bool ObjectMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine) { bool ObjectMotionState::handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine) {
if (flags & Simulation::DIRTY_SHAPE) { if (flags & Simulation::DIRTY_SHAPE) {
// make sure the new shape is valid // make sure the new shape is valid
if (!isReadyToComputeShape()) { if (!isReadyToComputeShape()) {
@ -195,8 +240,8 @@ bool ObjectMotionState::handleHardAndEasyChanges(uint32_t flags, PhysicsEngine*
if (flags & EASY_DIRTY_PHYSICS_FLAGS) { if (flags & EASY_DIRTY_PHYSICS_FLAGS) {
handleEasyChanges(flags, engine); handleEasyChanges(flags, engine);
} }
// it is possible that there are no HARD flags at this point (if DIRTY_SHAPE was removed) // it is possible there are no HARD flags at this point (if DIRTY_SHAPE was removed)
// so we check again befoe we reinsert: // so we check again before we reinsert:
if (flags & HARD_DIRTY_PHYSICS_FLAGS) { if (flags & HARD_DIRTY_PHYSICS_FLAGS) {
engine->reinsertObject(this); engine->reinsertObject(this);
} }

View file

@ -80,8 +80,8 @@ public:
ObjectMotionState(btCollisionShape* shape); ObjectMotionState(btCollisionShape* shape);
~ObjectMotionState(); ~ObjectMotionState();
virtual bool handleEasyChanges(uint32_t flags, PhysicsEngine* engine); virtual bool handleEasyChanges(uint32_t& flags, PhysicsEngine* engine);
virtual bool handleHardAndEasyChanges(uint32_t flags, PhysicsEngine* engine); virtual bool handleHardAndEasyChanges(uint32_t& flags, PhysicsEngine* engine);
void updateBodyMaterialProperties(); void updateBodyMaterialProperties();
void updateBodyVelocities(); void updateBodyVelocities();

View file

@ -244,14 +244,14 @@ void PhysicsEngine::stepSimulation() {
float timeStep = btMin(dt, MAX_TIMESTEP); float timeStep = btMin(dt, MAX_TIMESTEP);
if (_myAvatarController) { if (_myAvatarController) {
// ADEBUG TODO: move this stuff outside and in front of stepSimulation, because // TODO: move this stuff outside and in front of stepSimulation, because
// the updateShapeIfNecessary() call needs info from MyAvatar and should // the updateShapeIfNecessary() call needs info from MyAvatar and should
// be done on the main thread during the pre-simulation stuff // be done on the main thread during the pre-simulation stuff
if (_myAvatarController->needsRemoval()) { if (_myAvatarController->needsRemoval()) {
_myAvatarController->setDynamicsWorld(nullptr); _myAvatarController->setDynamicsWorld(nullptr);
// We must remove any existing contacts for the avatar so that any new contacts will have // We must remove any existing contacts for the avatar so that any new contacts will have
// valid data. MyAvatar's RigidBody is the ONLY one in the simulation that does not yet // valid data. MyAvatar's RigidBody is the ONLY one in the simulation that does not yet
// have a MotionState so we pass nullptr to removeContacts(). // have a MotionState so we pass nullptr to removeContacts().
removeContacts(nullptr); removeContacts(nullptr);
} }