Merge branch 'master' into quest-demo

This commit is contained in:
amerhifi 2019-02-28 14:06:47 -08:00 committed by GitHub
commit 35dc13e06a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
54 changed files with 1713 additions and 381 deletions

View file

@ -25,13 +25,13 @@
#include <AccountManager.h> #include <AccountManager.h>
#include <Assignment.h> #include <Assignment.h>
#include <AvatarData.h>
#include <HifiConfigVariantMap.h> #include <HifiConfigVariantMap.h>
#include <HTTPConnection.h> #include <HTTPConnection.h>
#include <NLPacketList.h> #include <NLPacketList.h>
#include <NumericalConstants.h> #include <NumericalConstants.h>
#include <SettingHandle.h> #include <SettingHandle.h>
#include <SettingHelpers.h> #include <SettingHelpers.h>
#include <AvatarData.h> //for KillAvatarReason
#include <FingerprintUtils.h> #include <FingerprintUtils.h>
#include "DomainServerNodeData.h" #include "DomainServerNodeData.h"
@ -870,14 +870,6 @@ void DomainServerSettingsManager::processNodeKickRequestPacket(QSharedPointer<Re
} }
} }
// if we are here, then we kicked them, so send the KillAvatar message
auto packet = NLPacket::create(PacketType::KillAvatar, NUM_BYTES_RFC4122_UUID + sizeof(KillAvatarReason), true);
packet->write(nodeUUID.toRfc4122());
packet->writePrimitive(KillAvatarReason::NoReason);
// send to avatar mixer, it sends the kill to everyone else
limitedNodeList->broadcastToNodes(std::move(packet), NodeSet() << NodeType::AvatarMixer);
if (newPermissions) { if (newPermissions) {
qDebug() << "Removing connect permission for node" << uuidStringWithoutCurlyBraces(matchingNode->getUUID()) qDebug() << "Removing connect permission for node" << uuidStringWithoutCurlyBraces(matchingNode->getUUID())
<< "after kick request from" << uuidStringWithoutCurlyBraces(sendingNode->getUUID()); << "after kick request from" << uuidStringWithoutCurlyBraces(sendingNode->getUUID());

View file

@ -2302,31 +2302,31 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
DependencyManager::get<PickManager>()->setPrecisionPicking(rayPickID, value); DependencyManager::get<PickManager>()->setPrecisionPicking(rayPickID, value);
}); });
EntityItem::setBillboardRotationOperator([this](const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode) { EntityItem::setBillboardRotationOperator([this](const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode, const glm::vec3& frustumPos) {
if (billboardMode == BillboardMode::YAW) { if (billboardMode == BillboardMode::YAW) {
//rotate about vertical to face the camera //rotate about vertical to face the camera
ViewFrustum frustum; glm::vec3 dPosition = frustumPos - position;
copyViewFrustum(frustum);
glm::vec3 dPosition = frustum.getPosition() - position;
// If x and z are 0, atan(x, z) is undefined, so default to 0 degrees // If x and z are 0, atan(x, z) is undefined, so default to 0 degrees
float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z); float yawRotation = dPosition.x == 0.0f && dPosition.z == 0.0f ? 0.0f : glm::atan(dPosition.x, dPosition.z);
return glm::quat(glm::vec3(0.0f, yawRotation, 0.0f)); return glm::quat(glm::vec3(0.0f, yawRotation, 0.0f));
} else if (billboardMode == BillboardMode::FULL) { } else if (billboardMode == BillboardMode::FULL) {
ViewFrustum frustum;
copyViewFrustum(frustum);
glm::vec3 cameraPos = frustum.getPosition();
// use the referencial from the avatar, y isn't always up // use the referencial from the avatar, y isn't always up
glm::vec3 avatarUP = DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldOrientation() * Vectors::UP; glm::vec3 avatarUP = DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldOrientation() * Vectors::UP;
// check to see if glm::lookAt will work / using glm::lookAt variable name // check to see if glm::lookAt will work / using glm::lookAt variable name
glm::highp_vec3 s(glm::cross(position - cameraPos, avatarUP)); glm::highp_vec3 s(glm::cross(position - frustumPos, avatarUP));
// make sure s is not NaN for any component // make sure s is not NaN for any component
if (glm::length2(s) > 0.0f) { if (glm::length2(s) > 0.0f) {
return glm::conjugate(glm::toQuat(glm::lookAt(cameraPos, position, avatarUP))); return glm::conjugate(glm::toQuat(glm::lookAt(frustumPos, position, avatarUP)));
} }
} }
return rotation; return rotation;
}); });
EntityItem::setPrimaryViewFrustumPositionOperator([this]() {
ViewFrustum viewFrustum;
copyViewFrustum(viewFrustum);
return viewFrustum.getPosition();
});
render::entities::WebEntityRenderer::setAcquireWebSurfaceOperator([this](const QString& url, bool htmlContent, QSharedPointer<OffscreenQmlSurface>& webSurface, bool& cachedWebSurface) { render::entities::WebEntityRenderer::setAcquireWebSurfaceOperator([this](const QString& url, bool htmlContent, QSharedPointer<OffscreenQmlSurface>& webSurface, bool& cachedWebSurface) {
bool isTablet = url == TabletScriptingInterface::QML; bool isTablet = url == TabletScriptingInterface::QML;
@ -4981,6 +4981,15 @@ void Application::idle() {
} }
} }
{
if (_keyboardFocusWaitingOnRenderable && getEntities()->renderableForEntityId(_keyboardFocusedEntity.get())) {
_keyboardFocusWaitingOnRenderable = false;
QUuid entityId = _keyboardFocusedEntity.get();
setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
setKeyboardFocusEntity(entityId);
}
}
{ {
PerformanceTimer perfTimer("pluginIdle"); PerformanceTimer perfTimer("pluginIdle");
PerformanceWarning warn(showWarnings, "Application::idle()... pluginIdle()"); PerformanceWarning warn(showWarnings, "Application::idle()... pluginIdle()");
@ -5809,7 +5818,7 @@ void Application::setKeyboardFocusEntity(const QUuid& id) {
if (qApp->getLoginDialogPoppedUp() && !_loginDialogID.isNull()) { if (qApp->getLoginDialogPoppedUp() && !_loginDialogID.isNull()) {
if (id == _loginDialogID) { if (id == _loginDialogID) {
emit loginDialogFocusEnabled(); emit loginDialogFocusEnabled();
} else { } else if (!_keyboardFocusWaitingOnRenderable) {
// that's the only entity we want in focus; // that's the only entity we want in focus;
return; return;
} }
@ -5826,7 +5835,10 @@ void Application::setKeyboardFocusEntity(const QUuid& id) {
if (properties.getVisible()) { if (properties.getVisible()) {
auto entities = getEntities(); auto entities = getEntities();
auto entityId = _keyboardFocusedEntity.get(); auto entityId = _keyboardFocusedEntity.get();
if (entities->wantsKeyboardFocus(entityId)) { auto entityItemRenderable = entities->renderableForEntityId(entityId);
if (!entityItemRenderable) {
_keyboardFocusWaitingOnRenderable = true;
} else if (entityItemRenderable->wantsKeyboardFocus()) {
entities->setProxyWindow(entityId, _window->windowHandle()); entities->setProxyWindow(entityId, _window->windowHandle());
if (_keyboardMouseDevice->isActive()) { if (_keyboardMouseDevice->isActive()) {
_keyboardMouseDevice->pluginFocusOutEvent(); _keyboardMouseDevice->pluginFocusOutEvent();

View file

@ -733,6 +733,7 @@ private:
bool _failedToConnectToEntityServer { false }; bool _failedToConnectToEntityServer { false };
bool _reticleClickPressed { false }; bool _reticleClickPressed { false };
bool _keyboardFocusWaitingOnRenderable { false };
int _avatarAttachmentRequest = 0; int _avatarAttachmentRequest = 0;

View file

@ -297,6 +297,9 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
avatar->setIsNewAvatar(false); avatar->setIsNewAvatar(false);
} }
avatar->simulate(deltaTime, inView); avatar->simulate(deltaTime, inView);
if (avatar->getSkeletonModel()->isLoaded() && avatar->getWorkloadRegion() == workload::Region::R1) {
_myAvatar->addAvatarHandsToFlow(avatar);
}
avatar->updateRenderItem(renderTransaction); avatar->updateRenderItem(renderTransaction);
avatar->updateSpaceProxy(workloadTransaction); avatar->updateSpaceProxy(workloadTransaction);
avatar->setLastRenderUpdateTime(startTime); avatar->setLastRenderUpdateTime(startTime);
@ -716,7 +719,7 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic
} }
} }
if (rayAvatarResult._intersect && pickAgainstMesh) { if (avatar && rayAvatarResult._intersect && pickAgainstMesh) {
glm::vec3 localRayOrigin = avatar->worldToJointPoint(ray.origin, rayAvatarResult._intersectWithJoint); glm::vec3 localRayOrigin = avatar->worldToJointPoint(ray.origin, rayAvatarResult._intersectWithJoint);
glm::vec3 localRayPoint = avatar->worldToJointPoint(ray.origin + rayAvatarResult._distance * rayDirection, rayAvatarResult._intersectWithJoint); glm::vec3 localRayPoint = avatar->worldToJointPoint(ray.origin + rayAvatarResult._distance * rayDirection, rayAvatarResult._intersectWithJoint);

View file

@ -32,6 +32,17 @@ void GrabManager::simulateGrabs() {
bool success; bool success;
SpatiallyNestablePointer grabbedThing = SpatiallyNestable::findByID(grabbedThingID, success); SpatiallyNestablePointer grabbedThing = SpatiallyNestable::findByID(grabbedThingID, success);
if (success && grabbedThing) { if (success && grabbedThing) {
auto entity = std::dynamic_pointer_cast<EntityItem>(grabbedThing);
if (entity) {
if (entity->getLocked()) {
continue; // even if someone else claims to be grabbing it, don't move a locked thing
}
const GrabPropertyGroup& grabProps = entity->getGrabProperties();
if (!grabProps.getGrabbable()) {
continue; // even if someone else claims to be grabbing it, don't move non-grabbable
}
}
glm::vec3 finalPosition = acc.finalizePosition(); glm::vec3 finalPosition = acc.finalizePosition();
glm::quat finalOrientation = acc.finalizeOrientation(); glm::quat finalOrientation = acc.finalizeOrientation();
grabbedThing->setTransform(createMatFromQuatAndPos(finalOrientation, finalPosition)); grabbedThing->setTransform(createMatFromQuatAndPos(finalOrientation, finalPosition));

69
interface/src/avatar/MyAvatar.cpp Executable file → Normal file
View file

@ -932,7 +932,8 @@ void MyAvatar::simulate(float deltaTime, bool inView) {
bool isPhysicsEnabled = qApp->isPhysicsEnabled(); bool isPhysicsEnabled = qApp->isPhysicsEnabled();
bool zoneAllowsFlying = zoneInteractionProperties.first; bool zoneAllowsFlying = zoneInteractionProperties.first;
bool collisionlessAllowed = zoneInteractionProperties.second; bool collisionlessAllowed = zoneInteractionProperties.second;
_characterController.setFlyingAllowed((zoneAllowsFlying && _enableFlying) || !isPhysicsEnabled); _characterController.setZoneFlyingAllowed(zoneAllowsFlying || !isPhysicsEnabled);
_characterController.setComfortFlyingAllowed(_enableFlying);
_characterController.setCollisionlessAllowed(collisionlessAllowed); _characterController.setCollisionlessAllowed(collisionlessAllowed);
} }
@ -5317,6 +5318,72 @@ void MyAvatar::releaseGrab(const QUuid& grabID) {
} }
} }
void MyAvatar::addAvatarHandsToFlow(const std::shared_ptr<Avatar>& otherAvatar) {
auto &flow = _skeletonModel->getRig().getFlow();
for (auto &handJointName : HAND_COLLISION_JOINTS) {
int jointIndex = otherAvatar->getJointIndex(handJointName);
if (jointIndex != -1) {
glm::vec3 position = otherAvatar->getJointPosition(jointIndex);
flow.setOthersCollision(otherAvatar->getID(), jointIndex, position);
}
}
}
void MyAvatar::useFlow(bool isActive, bool isCollidable, const QVariantMap& physicsConfig, const QVariantMap& collisionsConfig) {
if (_skeletonModel->isLoaded()) {
_skeletonModel->getRig().initFlow(isActive);
auto &flow = _skeletonModel->getRig().getFlow();
auto &collisionSystem = flow.getCollisionSystem();
collisionSystem.setActive(isCollidable);
auto physicsGroups = physicsConfig.keys();
if (physicsGroups.size() > 0) {
for (auto &groupName : physicsGroups) {
auto settings = physicsConfig[groupName].toMap();
FlowPhysicsSettings physicsSettings;
if (settings.contains("active")) {
physicsSettings._active = settings["active"].toBool();
}
if (settings.contains("damping")) {
physicsSettings._damping = settings["damping"].toFloat();
}
if (settings.contains("delta")) {
physicsSettings._delta = settings["delta"].toFloat();
}
if (settings.contains("gravity")) {
physicsSettings._gravity = settings["gravity"].toFloat();
}
if (settings.contains("inertia")) {
physicsSettings._inertia = settings["inertia"].toFloat();
}
if (settings.contains("radius")) {
physicsSettings._radius = settings["radius"].toFloat();
}
if (settings.contains("stiffness")) {
physicsSettings._stiffness = settings["stiffness"].toFloat();
}
flow.setPhysicsSettingsForGroup(groupName, physicsSettings);
}
}
auto collisionJoints = collisionsConfig.keys();
if (collisionJoints.size() > 0) {
collisionSystem.resetCollisions();
for (auto &jointName : collisionJoints) {
int jointIndex = getJointIndex(jointName);
FlowCollisionSettings collisionsSettings;
auto settings = collisionsConfig[jointName].toMap();
collisionsSettings._entityID = getID();
if (settings.contains("radius")) {
collisionsSettings._radius = settings["radius"].toFloat();
}
if (settings.contains("offset")) {
collisionsSettings._offset = vec3FromVariant(settings["offset"]);
}
collisionSystem.addCollisionSphere(jointIndex, collisionsSettings);
}
}
}
}
void MyAvatar::sendPacket(const QUuid& entityID, const EntityItemProperties& properties) const { void MyAvatar::sendPacket(const QUuid& entityID, const EntityItemProperties& properties) const {
auto treeRenderer = DependencyManager::get<EntityTreeRenderer>(); auto treeRenderer = DependencyManager::get<EntityTreeRenderer>();
EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr; EntityTreePointer entityTree = treeRenderer ? treeRenderer->getTree() : nullptr;

View file

@ -1184,6 +1184,20 @@ public:
void avatarEntityDataToJson(QJsonObject& root) const override; void avatarEntityDataToJson(QJsonObject& root) const override;
int sendAvatarDataPacket(bool sendAll = false) override; int sendAvatarDataPacket(bool sendAll = false) override;
void addAvatarHandsToFlow(const std::shared_ptr<Avatar>& otherAvatar);
/**jsdoc
* Init flow simulation on avatar.
* @function MyAvatar.useFlow
* @param {boolean} - Set to <code>true</code> to activate flow simulation.
* @param {boolean} - Set to <code>true</code> to activate collisions.
* @param {Object} physicsConfig - object with the customized physic parameters
* i.e. {"hair": {"active": true, "stiffness": 0.0, "radius": 0.04, "gravity": -0.035, "damping": 0.8, "inertia": 0.8, "delta": 0.35}}
* @param {Object} collisionsConfig - object with the customized collision parameters
* i.e. {"Spine2": {"type": "sphere", "radius": 0.14, "offset": {"x": 0.0, "y": 0.2, "z": 0.0}}}
*/
Q_INVOKABLE void useFlow(bool isActive, bool isCollidable, const QVariantMap& physicsConfig = QVariantMap(), const QVariantMap& collisionsConfig = QVariantMap());
public slots: public slots:
/**jsdoc /**jsdoc

View file

@ -368,7 +368,6 @@ void OtherAvatar::simulate(float deltaTime, bool inView) {
PROFILE_RANGE(simulation, "grabs"); PROFILE_RANGE(simulation, "grabs");
applyGrabChanges(); applyGrabChanges();
} }
updateFadingStatus(); updateFadingStatus();
} }

View file

@ -48,6 +48,7 @@ public:
void rebuildCollisionShape() override; void rebuildCollisionShape() override;
void setWorkloadRegion(uint8_t region); void setWorkloadRegion(uint8_t region);
uint8_t getWorkloadRegion() { return _workloadRegion; }
bool shouldBeInPhysicsSimulation() const; bool shouldBeInPhysicsSimulation() const;
bool needsPhysicsUpdate() const; bool needsPhysicsUpdate() const;

View file

@ -72,7 +72,7 @@ void SafeLanding::addTrackedEntity(const EntityItemID& entityID) {
Locker lock(_lock); Locker lock(_lock);
EntityItemPointer entity = _entityTree->findEntityByID(entityID); EntityItemPointer entity = _entityTree->findEntityByID(entityID);
if (entity && entity->getCreated() < _startTime) { if (entity && !entity->isLocalEntity() && entity->getCreated() < _startTime) {
_trackedEntities.emplace(entityID, entity); _trackedEntities.emplace(entityID, entity);
int trackedEntityCount = (int)_trackedEntities.size(); int trackedEntityCount = (int)_trackedEntities.size();
@ -81,7 +81,7 @@ void SafeLanding::addTrackedEntity(const EntityItemID& entityID) {
_maxTrackedEntityCount = trackedEntityCount; _maxTrackedEntityCount = trackedEntityCount;
_trackedEntityStabilityCount = 0; _trackedEntityStabilityCount = 0;
} }
qCDebug(interfaceapp) << "Safe Landing: Tracking entity " << entity->getItemName(); //qCDebug(interfaceapp) << "Safe Landing: Tracking entity " << entity->getItemName();
} }
} }
} }

View file

@ -27,8 +27,9 @@ QString Audio::HMD { "VR" };
Setting::Handle<bool> enableNoiseReductionSetting { QStringList { Audio::AUDIO, "NoiseReduction" }, true }; Setting::Handle<bool> enableNoiseReductionSetting { QStringList { Audio::AUDIO, "NoiseReduction" }, true };
float Audio::loudnessToLevel(float loudness) { float Audio::loudnessToLevel(float loudness) {
float level = 6.02059991f * fastLog2f(loudness); // level in dBFS float level = loudness * (1/32768.0f); // level in [0, 1]
level = (level + 48.0f) * (1/39.0f); // map [-48, -9] dBFS to [0, 1] level = 6.02059991f * fastLog2f(level); // convert to dBFS
level = (level + 48.0f) * (1/42.0f); // map [-48, -6] dBFS to [0, 1]
return glm::clamp(level, 0.0f, 1.0f); return glm::clamp(level, 0.0f, 1.0f);
} }

View file

@ -295,14 +295,14 @@ QString Overlays::overlayToEntityType(const QString& type) {
} \ } \
} }
static QHash<QUuid, glm::quat> savedRotations = QHash<QUuid, glm::quat>(); static QHash<QUuid, std::pair<glm::quat, bool>> savedRotations = QHash<QUuid, std::pair<glm::quat, bool>>();
EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& overlayProps, const QString& type, bool add, const QUuid& id) { EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& overlayProps, const QString& type, bool add, const QUuid& id) {
glm::quat rotation; std::pair<glm::quat, bool> rotation;
return convertOverlayToEntityProperties(overlayProps, rotation, type, add, id); return convertOverlayToEntityProperties(overlayProps, rotation, type, add, id);
} }
EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& overlayProps, glm::quat& rotationToSave, const QString& type, bool add, const QUuid& id) { EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& overlayProps, std::pair<glm::quat, bool>& rotationToSave, const QString& type, bool add, const QUuid& id) {
overlayProps["type"] = type; overlayProps["type"] = type;
SET_OVERLAY_PROP_DEFAULT(alpha, 0.7); SET_OVERLAY_PROP_DEFAULT(alpha, 0.7);
@ -311,7 +311,11 @@ EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& ove
RENAME_PROP(start, position); RENAME_PROP(start, position);
} }
RENAME_PROP(point, position); RENAME_PROP(point, position);
if (type != "Model") {
RENAME_PROP(scale, dimensions); RENAME_PROP(scale, dimensions);
} else {
RENAME_PROP(scale, modelScale);
}
RENAME_PROP(size, dimensions); RENAME_PROP(size, dimensions);
RENAME_PROP(orientation, rotation); RENAME_PROP(orientation, rotation);
RENAME_PROP(localOrientation, localRotation); RENAME_PROP(localOrientation, localRotation);
@ -561,27 +565,31 @@ EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& ove
if (type == "Text" || type == "Image" || type == "Grid" || type == "Web") { if (type == "Text" || type == "Image" || type == "Grid" || type == "Web") {
glm::quat originalRotation = ENTITY_ITEM_DEFAULT_ROTATION; glm::quat originalRotation = ENTITY_ITEM_DEFAULT_ROTATION;
bool local = false;
{ {
auto iter = overlayProps.find("rotation"); auto iter = overlayProps.find("rotation");
if (iter != overlayProps.end()) { if (iter != overlayProps.end()) {
originalRotation = quatFromVariant(iter.value()); originalRotation = quatFromVariant(iter.value());
local = false;
} else { } else {
iter = overlayProps.find("localRotation"); iter = overlayProps.find("localRotation");
if (iter != overlayProps.end()) { if (iter != overlayProps.end()) {
originalRotation = quatFromVariant(iter.value()); originalRotation = quatFromVariant(iter.value());
local = true;
} else if (!add) { } else if (!add) {
auto iter2 = savedRotations.find(id); auto iter2 = savedRotations.find(id);
if (iter2 != savedRotations.end()) { if (iter2 != savedRotations.end()) {
originalRotation = iter2.value(); originalRotation = iter2.value().first;
local = iter2.value().second;
} }
} }
} }
} }
if (!add) { if (!add) {
savedRotations[id] = originalRotation; savedRotations[id] = { originalRotation, local };
} else { } else {
rotationToSave = originalRotation; rotationToSave = { originalRotation, local };
} }
glm::vec3 dimensions = ENTITY_ITEM_DEFAULT_DIMENSIONS; glm::vec3 dimensions = ENTITY_ITEM_DEFAULT_DIMENSIONS;
@ -612,7 +620,11 @@ EntityItemProperties Overlays::convertOverlayToEntityProperties(QVariantMap& ove
rotation = glm::angleAxis((float)M_PI, rotation * Vectors::UP) * rotation; rotation = glm::angleAxis((float)M_PI, rotation * Vectors::UP) * rotation;
} }
if (local) {
overlayProps["localRotation"] = quatToVariant(rotation); overlayProps["localRotation"] = quatToVariant(rotation);
} else {
overlayProps["rotation"] = quatToVariant(rotation);
}
overlayProps["dimensions"] = vec3toVariant(glm::abs(dimensions)); overlayProps["dimensions"] = vec3toVariant(glm::abs(dimensions));
} }
} }
@ -636,7 +648,11 @@ QVariantMap Overlays::convertEntityToOverlayProperties(const EntityItemPropertie
RENAME_PROP(position, start); RENAME_PROP(position, start);
} }
RENAME_PROP(position, point); RENAME_PROP(position, point);
if (type != "Model") {
RENAME_PROP(dimensions, scale); RENAME_PROP(dimensions, scale);
} else {
RENAME_PROP(modelScale, scale);
}
RENAME_PROP(dimensions, size); RENAME_PROP(dimensions, size);
RENAME_PROP(ignorePickIntersection, ignoreRayIntersection); RENAME_PROP(ignorePickIntersection, ignoreRayIntersection);
@ -790,7 +806,7 @@ QUuid Overlays::addOverlay(const QString& type, const QVariant& properties) {
if (type == "rectangle3d") { if (type == "rectangle3d") {
propertyMap["shape"] = "Quad"; propertyMap["shape"] = "Quad";
} }
glm::quat rotationToSave; std::pair<glm::quat, bool> rotationToSave;
QUuid id = DependencyManager::get<EntityScriptingInterface>()->addEntityInternal(convertOverlayToEntityProperties(propertyMap, rotationToSave, entityType, true), entity::HostType::LOCAL); QUuid id = DependencyManager::get<EntityScriptingInterface>()->addEntityInternal(convertOverlayToEntityProperties(propertyMap, rotationToSave, entityType, true), entity::HostType::LOCAL);
if (entityType == "Text" || entityType == "Image" || entityType == "Grid" || entityType == "Web") { if (entityType == "Text" || entityType == "Image" || entityType == "Grid" || entityType == "Web") {
savedRotations[id] = rotationToSave; savedRotations[id] = rotationToSave;
@ -1718,7 +1734,8 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
* *
* @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and * @property {Vec3} position - The position of the overlay center. Synonyms: <code>p1</code>, <code>point</code>, and
* <code>start</code>. * <code>start</code>.
* @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>scale</code>, <code>size</code>. * @property {Vec3} dimensions - The dimensions of the overlay. Synonyms: <code>size</code>.
* @property {Vec3} scale - The scale factor applied to the model's dimensions.
* @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>. * @property {Quat} rotation - The orientation of the overlay. Synonym: <code>orientation</code>.
* @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a * @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a
* <code>parentID</code> set, otherwise the same value as <code>position</code>. * <code>parentID</code> set, otherwise the same value as <code>position</code>.

View file

@ -729,7 +729,7 @@ private:
QVariantMap convertEntityToOverlayProperties(const EntityItemProperties& entityProps); QVariantMap convertEntityToOverlayProperties(const EntityItemProperties& entityProps);
EntityItemProperties convertOverlayToEntityProperties(QVariantMap& overlayProps, const QString& type, bool add, const QUuid& id); EntityItemProperties convertOverlayToEntityProperties(QVariantMap& overlayProps, const QString& type, bool add, const QUuid& id);
EntityItemProperties convertOverlayToEntityProperties(QVariantMap& overlayProps, glm::quat& rotationToSave, const QString& type, bool add, const QUuid& id = QUuid()); EntityItemProperties convertOverlayToEntityProperties(QVariantMap& overlayProps, std::pair<glm::quat, bool>& rotationToSave, const QString& type, bool add, const QUuid& id = QUuid());
private slots: private slots:
void mousePressPointerEvent(const QUuid& id, const PointerEvent& event); void mousePressPointerEvent(const QUuid& id, const PointerEvent& event);

View file

@ -99,65 +99,64 @@ void AnimClip::copyFromNetworkAnim() {
assert(_networkAnim && _networkAnim->isLoaded() && _skeleton); assert(_networkAnim && _networkAnim->isLoaded() && _skeleton);
_anim.clear(); _anim.clear();
// build a mapping from animation joint indices to skeleton joint indices. auto avatarSkeleton = getSkeleton();
// build a mapping from animation joint indices to avatar joint indices.
// by matching joints with the same name. // by matching joints with the same name.
const HFMModel& hfmModel = _networkAnim->getHFMModel(); const HFMModel& animModel = _networkAnim->getHFMModel();
AnimSkeleton animSkeleton(hfmModel); AnimSkeleton animSkeleton(animModel);
const auto animJointCount = animSkeleton.getNumJoints(); const int animJointCount = animSkeleton.getNumJoints();
const auto skeletonJointCount = _skeleton->getNumJoints(); const int avatarJointCount = avatarSkeleton->getNumJoints();
std::vector<int> jointMap; std::vector<int> animToAvatarJointIndexMap;
jointMap.reserve(animJointCount); animToAvatarJointIndexMap.reserve(animJointCount);
for (int i = 0; i < animJointCount; i++) { for (int animJointIndex = 0; animJointIndex < animJointCount; animJointIndex++) {
int skeletonJoint = _skeleton->nameToJointIndex(animSkeleton.getJointName(i)); QString animJointName = animSkeleton.getJointName(animJointIndex);
jointMap.push_back(skeletonJoint); int avatarJointIndex = avatarSkeleton->nameToJointIndex(animJointName);
animToAvatarJointIndexMap.push_back(avatarJointIndex);
} }
const int frameCount = hfmModel.animationFrames.size(); const int animFrameCount = animModel.animationFrames.size();
_anim.resize(frameCount); _anim.resize(animFrameCount);
for (int frame = 0; frame < frameCount; frame++) { for (int frame = 0; frame < animFrameCount; frame++) {
const HFMAnimationFrame& hfmAnimFrame = hfmModel.animationFrames[frame]; const HFMAnimationFrame& animFrame = animModel.animationFrames[frame];
// init all joints in animation to default pose // init all joints in animation to default pose
// this will give us a resonable result for bones in the model skeleton but not in the animation. // this will give us a resonable result for bones in the avatar skeleton but not in the animation.
_anim[frame].reserve(skeletonJointCount); _anim[frame].reserve(avatarJointCount);
for (int skeletonJoint = 0; skeletonJoint < skeletonJointCount; skeletonJoint++) { for (int avatarJointIndex = 0; avatarJointIndex < avatarJointCount; avatarJointIndex++) {
_anim[frame].push_back(_skeleton->getRelativeDefaultPose(skeletonJoint)); _anim[frame].push_back(avatarSkeleton->getRelativeDefaultPose(avatarJointIndex));
} }
for (int animJoint = 0; animJoint < animJointCount; animJoint++) { for (int animJointIndex = 0; animJointIndex < animJointCount; animJointIndex++) {
int skeletonJoint = jointMap[animJoint]; int avatarJointIndex = animToAvatarJointIndexMap[animJointIndex];
const glm::vec3& hfmAnimTrans = hfmAnimFrame.translations[animJoint]; // skip joints that are in the animation but not in the avatar.
const glm::quat& hfmAnimRot = hfmAnimFrame.rotations[animJoint]; if (avatarJointIndex >= 0 && avatarJointIndex < avatarJointCount) {
// skip joints that are in the animation but not in the skeleton. const glm::vec3& animTrans = animFrame.translations[animJointIndex];
if (skeletonJoint >= 0 && skeletonJoint < skeletonJointCount) { const glm::quat& animRot = animFrame.rotations[animJointIndex];
AnimPose preRot, postRot; const AnimPose& animPreRotPose = animSkeleton.getPreRotationPose(animJointIndex);
preRot = animSkeleton.getPreRotationPose(animJoint); AnimPose animPostRotPose = animSkeleton.getPostRotationPose(animJointIndex);
postRot = animSkeleton.getPostRotationPose(animJoint); AnimPose animRotPose(glm::vec3(1.0f), animRot, glm::vec3());
// cancel out scale // adjust anim scale to equal the scale from the avatar joint.
preRot.scale() = glm::vec3(1.0f); // we do not support animated scale.
postRot.scale() = glm::vec3(1.0f); const AnimPose& avatarDefaultPose = avatarSkeleton->getRelativeDefaultPose(avatarJointIndex);
animPostRotPose.scale() = avatarDefaultPose.scale();
AnimPose rot(glm::vec3(1.0f), hfmAnimRot, glm::vec3()); // retarget translation from animation to avatar
const glm::vec3& animZeroTrans = animModel.animationFrames[0].translations[animJointIndex];
// adjust translation offsets, so large translation animatons on the reference skeleton
// will be adjusted when played on a skeleton with short limbs.
const glm::vec3& hfmZeroTrans = hfmModel.animationFrames[0].translations[animJoint];
const AnimPose& relDefaultPose = _skeleton->getRelativeDefaultPose(skeletonJoint);
float boneLengthScale = 1.0f; float boneLengthScale = 1.0f;
const float EPSILON = 0.0001f; const float EPSILON = 0.0001f;
if (fabsf(glm::length(hfmZeroTrans)) > EPSILON) { if (fabsf(glm::length(animZeroTrans)) > EPSILON) {
boneLengthScale = glm::length(relDefaultPose.trans()) / glm::length(hfmZeroTrans); boneLengthScale = glm::length(avatarDefaultPose.trans()) / glm::length(animZeroTrans);
} }
AnimPose animTransPose = AnimPose(glm::vec3(1.0f), glm::quat(), avatarDefaultPose.trans() + boneLengthScale * (animTrans - animZeroTrans));
AnimPose trans = AnimPose(glm::vec3(1.0f), glm::quat(), relDefaultPose.trans() + boneLengthScale * (hfmAnimTrans - hfmZeroTrans)); _anim[frame][avatarJointIndex] = animTransPose * animPreRotPose * animRotPose * animPostRotPose;
_anim[frame][skeletonJoint] = trans * preRot * rot * postRot;
} }
} }
} }
@ -165,7 +164,7 @@ void AnimClip::copyFromNetworkAnim() {
// mirrorAnim will be re-built on demand, if needed. // mirrorAnim will be re-built on demand, if needed.
_mirrorAnim.clear(); _mirrorAnim.clear();
_poses.resize(skeletonJointCount); _poses.resize(avatarJointCount);
} }
void AnimClip::buildMirrorAnim() { void AnimClip::buildMirrorAnim() {

View file

@ -0,0 +1,783 @@
//
// Flow.cpp
//
// Created by Luis Cuenca on 1/21/2019.
// Copyright 2019 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 "Flow.h"
#include "Rig.h"
#include "AnimSkeleton.h"
const std::map<QString, FlowPhysicsSettings> PRESET_FLOW_DATA = { { "hair", FlowPhysicsSettings() },
{ "skirt", FlowPhysicsSettings(true, 1.0f, DEFAULT_GRAVITY, 0.65f, 0.8f, 0.45f, 0.01f) },
{ "breast", FlowPhysicsSettings(true, 1.0f, DEFAULT_GRAVITY, 0.65f, 0.8f, 0.45f, 0.01f) } };
const std::map<QString, FlowCollisionSettings> PRESET_COLLISION_DATA = {
{ "Spine2", FlowCollisionSettings(QUuid(), FlowCollisionType::CollisionSphere, glm::vec3(0.0f, 0.2f, 0.0f), 0.14f) },
{ "LeftArm", FlowCollisionSettings(QUuid(), FlowCollisionType::CollisionSphere, glm::vec3(0.0f, 0.02f, 0.0f), 0.05f) },
{ "RightArm", FlowCollisionSettings(QUuid(), FlowCollisionType::CollisionSphere, glm::vec3(0.0f, 0.02f, 0.0f), 0.05f) },
{ "HeadTop_End", FlowCollisionSettings(QUuid(), FlowCollisionType::CollisionSphere, glm::vec3(0.0f, -0.15f, 0.0f), 0.09f) }
};
FlowCollisionSphere::FlowCollisionSphere(const int& jointIndex, const FlowCollisionSettings& settings, bool isTouch) {
_jointIndex = jointIndex;
_radius = _initialRadius = settings._radius;
_offset = _initialOffset = settings._offset;
_entityID = settings._entityID;
_isTouch = isTouch;
}
FlowCollisionResult FlowCollisionSphere::computeSphereCollision(const glm::vec3& point, float radius) const {
FlowCollisionResult result;
auto centerToJoint = point - _position;
result._distance = glm::length(centerToJoint) - radius;
result._offset = _radius - result._distance;
result._normal = glm::normalize(centerToJoint);
result._radius = _radius;
result._position = _position;
return result;
}
FlowCollisionResult FlowCollisionSphere::checkSegmentCollision(const glm::vec3& point1, const glm::vec3& point2, const FlowCollisionResult& collisionResult1, const FlowCollisionResult& collisionResult2) {
FlowCollisionResult result;
auto segment = point2 - point1;
auto segmentLength = glm::length(segment);
auto maxDistance = glm::sqrt(powf(collisionResult1._radius, 2.0f) + powf(segmentLength, 2.0f));
if (collisionResult1._distance < maxDistance && collisionResult2._distance < maxDistance) {
float segmentPercentage = collisionResult1._distance / (collisionResult1._distance + collisionResult2._distance);
glm::vec3 collisionPoint = point1 + segment * segmentPercentage;
glm::vec3 centerToSegment = collisionPoint - _position;
float distance = glm::length(centerToSegment);
if (distance < _radius) {
result._offset = _radius - distance;
result._position = _position;
result._radius = _radius;
result._normal = glm::normalize(centerToSegment);
result._distance = distance;
}
}
return result;
}
void FlowCollisionSystem::addCollisionSphere(int jointIndex, const FlowCollisionSettings& settings, const glm::vec3& position, bool isSelfCollision, bool isTouch) {
auto collision = FlowCollisionSphere(jointIndex, settings, isTouch);
collision.setPosition(position);
if (isSelfCollision) {
_selfCollisions.push_back(collision);
} else {
_othersCollisions.push_back(collision);
}
};
void FlowCollisionSystem::resetCollisions() {
_allCollisions.clear();
_othersCollisions.clear();
_selfCollisions.clear();
}
FlowCollisionResult FlowCollisionSystem::computeCollision(const std::vector<FlowCollisionResult> collisions) {
FlowCollisionResult result;
if (collisions.size() > 1) {
for (size_t i = 0; i < collisions.size(); i++) {
result._offset += collisions[i]._offset;
result._normal = result._normal + collisions[i]._normal * collisions[i]._distance;
result._position = result._position + collisions[i]._position;
result._radius += collisions[i]._radius;
result._distance += collisions[i]._distance;
}
result._offset = result._offset / collisions.size();
result._radius = 0.5f * glm::length(result._normal);
result._normal = glm::normalize(result._normal);
result._position = result._position / (float)collisions.size();
result._distance = result._distance / collisions.size();
} else if (collisions.size() == 1) {
result = collisions[0];
}
result._count = (int)collisions.size();
return result;
};
void FlowCollisionSystem::setScale(float scale) {
_scale = scale;
for (size_t j = 0; j < _selfCollisions.size(); j++) {
_selfCollisions[j]._radius = _selfCollisions[j]._initialRadius * scale;
_selfCollisions[j]._offset = _selfCollisions[j]._initialOffset * scale;
}
};
std::vector<FlowCollisionResult> FlowCollisionSystem::checkFlowThreadCollisions(FlowThread* flowThread) {
std::vector<std::vector<FlowCollisionResult>> FlowThreadResults;
FlowThreadResults.resize(flowThread->_joints.size());
for (size_t j = 0; j < _allCollisions.size(); j++) {
FlowCollisionSphere &sphere = _allCollisions[j];
FlowCollisionResult rootCollision = sphere.computeSphereCollision(flowThread->_positions[0], flowThread->_radius);
std::vector<FlowCollisionResult> collisionData = { rootCollision };
bool tooFar = rootCollision._distance >(flowThread->_length + rootCollision._radius);
FlowCollisionResult nextCollision;
if (!tooFar) {
if (sphere._isTouch) {
for (size_t i = 1; i < flowThread->_joints.size(); i++) {
auto prevCollision = collisionData[i - 1];
nextCollision = _allCollisions[j].computeSphereCollision(flowThread->_positions[i], flowThread->_radius);
collisionData.push_back(nextCollision);
if (prevCollision._offset > 0.0f) {
if (i == 1) {
FlowThreadResults[i - 1].push_back(prevCollision);
}
} else if (nextCollision._offset > 0.0f) {
FlowThreadResults[i].push_back(nextCollision);
} else {
FlowCollisionResult segmentCollision = _allCollisions[j].checkSegmentCollision(flowThread->_positions[i - 1], flowThread->_positions[i], prevCollision, nextCollision);
if (segmentCollision._offset > 0) {
FlowThreadResults[i - 1].push_back(segmentCollision);
FlowThreadResults[i].push_back(segmentCollision);
}
}
}
} else {
if (rootCollision._offset > 0.0f) {
FlowThreadResults[0].push_back(rootCollision);
}
for (size_t i = 1; i < flowThread->_joints.size(); i++) {
nextCollision = _allCollisions[j].computeSphereCollision(flowThread->_positions[i], flowThread->_radius);
if (nextCollision._offset > 0.0f) {
FlowThreadResults[i].push_back(nextCollision);
}
}
}
}
}
std::vector<FlowCollisionResult> results;
for (size_t i = 0; i < flowThread->_joints.size(); i++) {
results.push_back(computeCollision(FlowThreadResults[i]));
}
return results;
};
FlowCollisionSettings FlowCollisionSystem::getCollisionSettingsByJoint(int jointIndex) {
for (auto &collision : _selfCollisions) {
if (collision._jointIndex == jointIndex) {
return FlowCollisionSettings(collision._entityID, FlowCollisionType::CollisionSphere, collision._initialOffset, collision._initialRadius);
}
}
return FlowCollisionSettings();
}
void FlowCollisionSystem::setCollisionSettingsByJoint(int jointIndex, const FlowCollisionSettings& settings) {
for (auto &collision : _selfCollisions) {
if (collision._jointIndex == jointIndex) {
collision._initialRadius = settings._radius;
collision._initialOffset = settings._offset;
collision._radius = _scale * settings._radius;
collision._offset = _scale * settings._offset;
}
}
}
void FlowCollisionSystem::prepareCollisions() {
_allCollisions.clear();
_allCollisions.resize(_selfCollisions.size() + _othersCollisions.size());
std::copy(_selfCollisions.begin(), _selfCollisions.begin() + _selfCollisions.size(), _allCollisions.begin());
std::copy(_othersCollisions.begin(), _othersCollisions.begin() + _othersCollisions.size(), _allCollisions.begin() + _selfCollisions.size());
_othersCollisions.clear();
}
FlowNode::FlowNode(const glm::vec3& initialPosition, FlowPhysicsSettings settings) {
_initialPosition = _previousPosition = _currentPosition = initialPosition;
_initialRadius = settings._radius;
}
void FlowNode::update(float deltaTime, const glm::vec3& accelerationOffset) {
_acceleration = glm::vec3(0.0f, _settings._gravity, 0.0f);
_previousVelocity = _currentVelocity;
_currentVelocity = _currentPosition - _previousPosition;
_previousPosition = _currentPosition;
if (!_anchored) {
// Add inertia
const float FPS = 60.0f;
float timeRatio = _scale * (FPS * deltaTime);
float invertedTimeRatio = timeRatio > 0.0f ? 1.0f / timeRatio : 1.0f;
auto deltaVelocity = _previousVelocity - _currentVelocity;
auto centrifugeVector = glm::length(deltaVelocity) != 0.0f ? glm::normalize(deltaVelocity) : glm::vec3();
_acceleration = _acceleration + centrifugeVector * _settings._inertia * glm::length(_currentVelocity) * invertedTimeRatio;
// Add offset
_acceleration += accelerationOffset;
float accelerationFactor = powf(_settings._delta, 2.0f) * timeRatio;
glm::vec3 deltaAcceleration = _acceleration * accelerationFactor;
// Calculate new position
_currentPosition = _currentPosition + (_currentVelocity * _settings._damping) + deltaAcceleration;
} else {
_acceleration = glm::vec3(0.0f);
_currentVelocity = glm::vec3(0.0f);
}
};
void FlowNode::solve(const glm::vec3& constrainPoint, float maxDistance, const FlowCollisionResult& collision) {
solveConstraints(constrainPoint, maxDistance);
solveCollisions(collision);
};
void FlowNode::solveConstraints(const glm::vec3& constrainPoint, float maxDistance) {
glm::vec3 constrainVector = _currentPosition - constrainPoint;
float difference = maxDistance / glm::length(constrainVector);
_currentPosition = difference < 1.0f ? constrainPoint + constrainVector * difference : _currentPosition;
};
void FlowNode::solveCollisions(const FlowCollisionResult& collision) {
_colliding = collision._offset > 0.0f;
_collision = collision;
if (_colliding) {
_currentPosition = _currentPosition + collision._normal * collision._offset;
_previousCollision = collision;
} else {
_previousCollision = FlowCollisionResult();
}
};
FlowJoint::FlowJoint(int jointIndex, int parentIndex, int childIndex, const QString& name, const QString& group, const FlowPhysicsSettings& settings) {
_index = jointIndex;
_name = name;
_group = group;
_childIndex = childIndex;
_parentIndex = parentIndex;
FlowNode(glm::vec3(), settings);
};
void FlowJoint::setInitialData(const glm::vec3& initialPosition, const glm::vec3& initialTranslation, const glm::quat& initialRotation, const glm::vec3& parentPosition) {
_initialPosition = initialPosition;
_previousPosition = initialPosition;
_currentPosition = initialPosition;
_initialTranslation = initialTranslation;
_currentRotation = initialRotation;
_initialRotation = initialRotation;
_translationDirection = glm::normalize(_initialTranslation);
_parentPosition = parentPosition;
_initialLength = _length = glm::length(_initialPosition - parentPosition);
}
void FlowJoint::setUpdatedData(const glm::vec3& updatedPosition, const glm::vec3& updatedTranslation, const glm::quat& updatedRotation, const glm::vec3& parentPosition, const glm::quat& parentWorldRotation) {
_updatedPosition = updatedPosition;
_updatedRotation = updatedRotation;
_updatedTranslation = updatedTranslation;
_parentPosition = parentPosition;
_parentWorldRotation = parentWorldRotation;
}
void FlowJoint::setRecoveryPosition(const glm::vec3& recoveryPosition) {
_recoveryPosition = recoveryPosition;
_applyRecovery = true;
}
void FlowJoint::update(float deltaTime) {
glm::vec3 accelerationOffset = glm::vec3(0.0f);
if (_settings._stiffness > 0.0f) {
glm::vec3 recoveryVector = _recoveryPosition - _currentPosition;
float recoveryFactor = powf(_settings._stiffness, 3.0f);
accelerationOffset = recoveryVector * recoveryFactor;
}
FlowNode::update(deltaTime, accelerationOffset);
if (_anchored) {
if (!_isHelper) {
_currentPosition = _updatedPosition;
} else {
_currentPosition = _parentPosition;
}
}
};
void FlowJoint::setScale(float scale, bool initScale) {
if (initScale) {
_initialLength = _length / scale;
}
_settings._radius = _initialRadius * scale;
_length = _initialLength * scale;
_scale = scale;
}
void FlowJoint::solve(const FlowCollisionResult& collision) {
FlowNode::solve(_parentPosition, _length, collision);
};
void FlowJoint::toHelperJoint(const glm::vec3& initialPosition, float length) {
_initialPosition = initialPosition;
_isHelper = true;
_length = length;
}
FlowThread::FlowThread(int rootIndex, std::map<int, FlowJoint>* joints) {
_jointsPointer = joints;
computeFlowThread(rootIndex);
}
void FlowThread::resetLength() {
_length = 0.0f;
for (size_t i = 1; i < _joints.size(); i++) {
int index = _joints[i];
_length += _jointsPointer->at(index)._length;
}
}
void FlowThread::computeFlowThread(int rootIndex) {
int parentIndex = rootIndex;
if (_jointsPointer->size() == 0) {
return;
}
int childIndex = _jointsPointer->at(parentIndex)._childIndex;
std::vector<int> indexes = { parentIndex };
for (size_t i = 0; i < _jointsPointer->size(); i++) {
if (childIndex > -1) {
indexes.push_back(childIndex);
childIndex = _jointsPointer->at(childIndex)._childIndex;
} else {
break;
}
}
_length = 0.0f;
for (size_t i = 0; i < indexes.size(); i++) {
int index = indexes[i];
_joints.push_back(index);
if (i > 0) {
_length += _jointsPointer->at(index)._length;
}
}
};
void FlowThread::computeRecovery() {
int parentIndex = _joints[0];
auto parentJoint = _jointsPointer->at(parentIndex);
_jointsPointer->at(parentIndex)._recoveryPosition = parentJoint._recoveryPosition = parentJoint._currentPosition;
glm::quat parentRotation = parentJoint._parentWorldRotation * parentJoint._initialRotation;
for (size_t i = 1; i < _joints.size(); i++) {
auto joint = _jointsPointer->at(_joints[i]);
_jointsPointer->at(_joints[i])._recoveryPosition = joint._recoveryPosition = parentJoint._recoveryPosition + (parentRotation * (joint._initialTranslation * 0.01f));
parentJoint = joint;
}
};
void FlowThread::update(float deltaTime) {
_positions.clear();
auto &firstJoint = _jointsPointer->at(_joints[0]);
_radius = firstJoint._settings._radius;
computeRecovery();
for (size_t i = 0; i < _joints.size(); i++) {
auto &joint = _jointsPointer->at(_joints[i]);
joint.update(deltaTime);
_positions.push_back(joint._currentPosition);
}
};
void FlowThread::solve(FlowCollisionSystem& collisionSystem) {
if (collisionSystem.getActive()) {
auto bodyCollisions = collisionSystem.checkFlowThreadCollisions(this);
for (size_t i = 0; i < _joints.size(); i++) {
int index = _joints[i];
_jointsPointer->at(index).solve(bodyCollisions[i]);
}
} else {
for (size_t i = 0; i < _joints.size(); i++) {
int index = _joints[i];
_jointsPointer->at(index).solve(FlowCollisionResult());
}
}
};
void FlowThread::computeJointRotations() {
auto pos0 = _rootFramePositions[0];
auto pos1 = _rootFramePositions[1];
auto joint0 = _jointsPointer->at(_joints[0]);
auto joint1 = _jointsPointer->at(_joints[1]);
auto initial_pos1 = pos0 + (joint0._initialRotation * (joint1._initialTranslation * 0.01f));
auto vec0 = initial_pos1 - pos0;
auto vec1 = pos1 - pos0;
auto delta = rotationBetween(vec0, vec1);
joint0._currentRotation = _jointsPointer->at(_joints[0])._currentRotation = delta * joint0._initialRotation;
for (size_t i = 1; i < _joints.size() - 1; i++) {
auto nextJoint = _jointsPointer->at(_joints[i + 1]);
for (size_t j = i; j < _joints.size(); j++) {
_rootFramePositions[j] = glm::inverse(joint0._currentRotation) * _rootFramePositions[j] - (joint0._initialTranslation * 0.01f);
}
pos0 = _rootFramePositions[i];
pos1 = _rootFramePositions[i + 1];
initial_pos1 = pos0 + joint1._initialRotation * (nextJoint._initialTranslation * 0.01f);
vec0 = initial_pos1 - pos0;
vec1 = pos1 - pos0;
delta = rotationBetween(vec0, vec1);
joint1._currentRotation = _jointsPointer->at(joint1._index)._currentRotation = delta * joint1._initialRotation;
joint0 = joint1;
joint1 = nextJoint;
}
}
void FlowThread::setScale(float scale, bool initScale) {
for (size_t i = 0; i < _joints.size(); i++) {
auto &joint = _jointsPointer->at(_joints[i]);
joint.setScale(scale, initScale);
}
resetLength();
}
FlowThread& FlowThread::operator=(const FlowThread& otherFlowThread) {
for (int jointIndex: otherFlowThread._joints) {
auto& joint = otherFlowThread._jointsPointer->at(jointIndex);
auto& myJoint = _jointsPointer->at(jointIndex);
myJoint._acceleration = joint._acceleration;
myJoint._currentPosition = joint._currentPosition;
myJoint._currentRotation = joint._currentRotation;
myJoint._currentVelocity = joint._currentVelocity;
myJoint._length = joint._length;
myJoint._parentPosition = joint._parentPosition;
myJoint._parentWorldRotation = joint._parentWorldRotation;
myJoint._previousPosition = joint._previousPosition;
myJoint._previousVelocity = joint._previousVelocity;
myJoint._scale = joint._scale;
myJoint._translationDirection = joint._translationDirection;
myJoint._updatedPosition = joint._updatedPosition;
myJoint._updatedRotation = joint._updatedRotation;
myJoint._updatedTranslation = joint._updatedTranslation;
myJoint._isHelper = joint._isHelper;
}
return *this;
}
void Flow::calculateConstraints(const std::shared_ptr<AnimSkeleton>& skeleton,
AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses) {
cleanUp();
if (!skeleton) {
return;
}
auto flowPrefix = FLOW_JOINT_PREFIX.toUpper();
auto simPrefix = SIM_JOINT_PREFIX.toUpper();
std::vector<int> handsIndices;
for (int i = 0; i < skeleton->getNumJoints(); i++) {
auto name = skeleton->getJointName(i);
if (std::find(HAND_COLLISION_JOINTS.begin(), HAND_COLLISION_JOINTS.end(), name) != HAND_COLLISION_JOINTS.end()) {
handsIndices.push_back(i);
}
auto parentIndex = skeleton->getParentIndex(i);
if (parentIndex == -1) {
continue;
}
auto jointChildren = skeleton->getChildrenOfJoint(i);
// auto childIndex = jointChildren.size() > 0 ? jointChildren[0] : -1;
auto group = QStringRef(&name, 0, 3).toString().toUpper();
auto split = name.split("_");
bool isSimJoint = (group == simPrefix);
bool isFlowJoint = split.size() > 2 && split[0].toUpper() == flowPrefix;
if (isFlowJoint || isSimJoint) {
group = "";
if (isSimJoint) {
for (int j = 1; j < name.size() - 1; j++) {
bool toFloatSuccess;
QStringRef(&name, (int)(name.size() - j), 1).toString().toFloat(&toFloatSuccess);
if (!toFloatSuccess && (name.size() - j) > (int)simPrefix.size()) {
group = QStringRef(&name, (int)simPrefix.size(), (int)(name.size() - j + 1)).toString();
break;
}
}
if (group.isEmpty()) {
group = QStringRef(&name, (int)simPrefix.size(), name.size() - 1).toString();
}
qCDebug(animation) << "Sim joint added to flow: " << name;
} else {
group = split[1];
}
if (!group.isEmpty()) {
_flowJointKeywords.push_back(group);
FlowPhysicsSettings jointSettings;
if (PRESET_FLOW_DATA.find(group) != PRESET_FLOW_DATA.end()) {
jointSettings = PRESET_FLOW_DATA.at(group);
} else {
jointSettings = DEFAULT_JOINT_SETTINGS;
}
if (_flowJointData.find(i) == _flowJointData.end()) {
auto flowJoint = FlowJoint(i, parentIndex, -1, name, group, jointSettings);
_flowJointData.insert(std::pair<int, FlowJoint>(i, flowJoint));
}
}
} else {
if (PRESET_COLLISION_DATA.find(name) != PRESET_COLLISION_DATA.end()) {
_collisionSystem.addCollisionSphere(i, PRESET_COLLISION_DATA.at(name));
}
}
}
for (auto &jointData : _flowJointData) {
int jointIndex = jointData.first;
glm::vec3 jointPosition, parentPosition, jointTranslation;
glm::quat jointRotation;
getJointPositionInWorldFrame(absolutePoses, jointIndex, jointPosition, _entityPosition, _entityRotation);
getJointTranslation(relativePoses, jointIndex, jointTranslation);
getJointRotation(relativePoses, jointIndex, jointRotation);
getJointPositionInWorldFrame(absolutePoses, jointData.second.getParentIndex(), parentPosition, _entityPosition, _entityRotation);
jointData.second.setInitialData(jointPosition, jointTranslation, jointRotation, parentPosition);
}
std::vector<int> roots;
for (auto &joint :_flowJointData) {
if (_flowJointData.find(joint.second.getParentIndex()) == _flowJointData.end()) {
joint.second.setAnchored(true);
roots.push_back(joint.first);
} else {
_flowJointData[joint.second.getParentIndex()].setChildIndex(joint.first);
}
}
int extraIndex = -1;
for (size_t i = 0; i < roots.size(); i++) {
FlowThread thread = FlowThread(roots[i], &_flowJointData);
// add threads with at least 2 joints
if (thread._joints.size() > 0) {
if (thread._joints.size() == 1) {
int jointIndex = roots[i];
auto &joint = _flowJointData[jointIndex];
auto &jointPosition = joint.getUpdatedPosition();
auto newSettings = joint.getSettings();
extraIndex = extraIndex > -1 ? extraIndex + 1 : skeleton->getNumJoints();
joint.setChildIndex(extraIndex);
auto newJoint = FlowJoint(extraIndex, jointIndex, -1, joint.getName(), joint.getGroup(), newSettings);
newJoint.toHelperJoint(jointPosition, HELPER_JOINT_LENGTH);
glm::vec3 translation = glm::vec3(0.0f, HELPER_JOINT_LENGTH, 0.0f);
newJoint.setInitialData(jointPosition + translation, 100.0f * translation , Quaternions::IDENTITY, jointPosition);
_flowJointData.insert(std::pair<int, FlowJoint>(extraIndex, newJoint));
FlowThread newThread = FlowThread(jointIndex, &_flowJointData);
if (newThread._joints.size() > 1) {
_jointThreads.push_back(newThread);
}
} else {
_jointThreads.push_back(thread);
}
}
}
if (_jointThreads.size() == 0) {
onCleanup();
}
if (handsIndices.size() > 0) {
FlowCollisionSettings handSettings;
handSettings._radius = HAND_COLLISION_RADIUS;
for (size_t i = 0; i < handsIndices.size(); i++) {
_collisionSystem.addCollisionSphere(handsIndices[i], handSettings, glm::vec3(), true, true);
}
}
_initialized = _jointThreads.size() > 0;
}
void Flow::cleanUp() {
_flowJointData.clear();
_jointThreads.clear();
_flowJointKeywords.clear();
_collisionSystem.resetCollisions();
_initialized = false;
_isScaleSet = false;
onCleanup();
}
void Flow::setTransform(float scale, const glm::vec3& position, const glm::quat& rotation) {
_scale = scale;
_entityPosition = position;
_entityRotation = rotation;
}
void Flow::setScale(float scale) {
_collisionSystem.setScale(_scale);
for (size_t i = 0; i < _jointThreads.size(); i++) {
_jointThreads[i].setScale(_scale, !_isScaleSet);
}
if (_lastScale != _scale) {
_lastScale = _scale;
_isScaleSet = true;
}
}
void Flow::update(float deltaTime, AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses, const std::vector<bool>& overrideFlags) {
if (_initialized && _active) {
uint64_t startTime = usecTimestampNow();
uint64_t updateExpiry = startTime + MAX_UPDATE_FLOW_TIME_BUDGET;
if (_scale != _lastScale) {
setScale(_scale);
}
for (size_t i = 0; i < _jointThreads.size(); i++) {
size_t index = _invertThreadLoop ? _jointThreads.size() - 1 - i : i;
auto &thread = _jointThreads[index];
thread.update(deltaTime);
thread.solve(_collisionSystem);
if (!updateRootFramePositions(absolutePoses, index)) {
return;
}
thread.computeJointRotations();
if (usecTimestampNow() > updateExpiry) {
break;
qWarning(animation) << "Flow Bones ran out of time while updating threads";
}
}
setJoints(relativePoses, overrideFlags);
updateJoints(relativePoses, absolutePoses);
_invertThreadLoop = !_invertThreadLoop;
}
}
void Flow::updateAbsolutePoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses) {
for (auto &joint : _flowJointData) {
int index = joint.second.getIndex();
int parentIndex = joint.second.getParentIndex();
if (index >= 0 && index < (int)relativePoses.size() &&
parentIndex >= 0 && parentIndex < (int)absolutePoses.size()) {
absolutePoses[index] = absolutePoses[parentIndex] * relativePoses[index];
}
}
}
bool Flow::worldToJointPoint(const AnimPoseVec& absolutePoses, const glm::vec3& position, const int jointIndex, glm::vec3& jointSpacePosition) const {
glm::vec3 jointPos;
glm::quat jointRot;
if (getJointPositionInWorldFrame(absolutePoses, jointIndex, jointPos, _entityPosition, _entityRotation) &&
getJointRotationInWorldFrame(absolutePoses, jointIndex, jointRot, _entityRotation)) {
glm::vec3 modelOffset = position - jointPos;
jointSpacePosition = glm::inverse(jointRot) * modelOffset;
return true;
}
return false;
}
bool Flow::updateRootFramePositions(const AnimPoseVec& absolutePoses, size_t threadIndex) {
auto &joints = _jointThreads[threadIndex]._joints;
int rootIndex = _flowJointData[joints[0]].getParentIndex();
_jointThreads[threadIndex]._rootFramePositions.clear();
for (size_t j = 0; j < joints.size(); j++) {
glm::vec3 jointPos;
if (worldToJointPoint(absolutePoses, _flowJointData[joints[j]].getCurrentPosition(), rootIndex, jointPos)) {
_jointThreads[threadIndex]._rootFramePositions.push_back(jointPos);
} else {
return false;
}
}
return true;
}
void Flow::updateJoints(AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses) {
updateAbsolutePoses(relativePoses, absolutePoses);
for (auto &jointData : _flowJointData) {
int jointIndex = jointData.first;
glm::vec3 jointPosition, parentPosition, jointTranslation;
glm::quat jointRotation, parentWorldRotation;
if (!jointData.second.isHelper()) {
getJointPositionInWorldFrame(absolutePoses, jointIndex, jointPosition, _entityPosition, _entityRotation);
getJointTranslation(relativePoses, jointIndex, jointTranslation);
getJointRotation(relativePoses, jointIndex, jointRotation);
} else {
jointPosition = jointData.second.getCurrentPosition();
jointTranslation = jointData.second.getCurrentTranslation();
jointRotation = jointData.second.getCurrentRotation();
}
getJointPositionInWorldFrame(absolutePoses, jointData.second.getParentIndex(), parentPosition, _entityPosition, _entityRotation);
getJointRotationInWorldFrame(absolutePoses, jointData.second.getParentIndex(), parentWorldRotation, _entityRotation);
jointData.second.setUpdatedData(jointPosition, jointTranslation, jointRotation, parentPosition, parentWorldRotation);
}
auto &selfCollisions = _collisionSystem.getSelfCollisions();
for (auto &collision : selfCollisions) {
glm::quat jointRotation;
getJointPositionInWorldFrame(absolutePoses, collision._jointIndex, collision._position, _entityPosition, _entityRotation);
getJointRotationInWorldFrame(absolutePoses, collision._jointIndex, jointRotation, _entityRotation);
glm::vec3 worldOffset = jointRotation * collision._offset;
collision._position = collision._position + worldOffset;
}
_collisionSystem.prepareCollisions();
}
void Flow::setJoints(AnimPoseVec& relativePoses, const std::vector<bool>& overrideFlags) {
for (auto &thread : _jointThreads) {
auto &joints = thread._joints;
for (int jointIndex : joints) {
auto &joint = _flowJointData[jointIndex];
if (jointIndex >= 0 && jointIndex < (int)relativePoses.size() && !overrideFlags[jointIndex]) {
relativePoses[jointIndex].rot() = joint.getCurrentRotation();
}
}
}
}
void Flow::setOthersCollision(const QUuid& otherId, int jointIndex, const glm::vec3& position) {
FlowCollisionSettings settings;
settings._entityID = otherId;
settings._radius = HAND_COLLISION_RADIUS;
_collisionSystem.addCollisionSphere(jointIndex, settings, position, false, true);
}
void Flow::setPhysicsSettingsForGroup(const QString& group, const FlowPhysicsSettings& settings) {
for (auto &joint : _flowJointData) {
if (joint.second.getGroup().toUpper() == group.toUpper()) {
joint.second.setSettings(settings);
}
}
}
bool Flow::getJointPositionInWorldFrame(const AnimPoseVec& absolutePoses, int jointIndex, glm::vec3& position, glm::vec3 translation, glm::quat rotation) const {
if (jointIndex >= 0 && jointIndex < (int)absolutePoses.size()) {
glm::vec3 poseSetTrans = absolutePoses[jointIndex].trans();
position = (rotation * poseSetTrans) + translation;
if (!isNaN(position)) {
return true;
} else {
position = glm::vec3(0.0f);
}
}
return false;
}
bool Flow::getJointRotationInWorldFrame(const AnimPoseVec& absolutePoses, int jointIndex, glm::quat& result, const glm::quat& rotation) const {
if (jointIndex >= 0 && jointIndex < (int)absolutePoses.size()) {
result = rotation * absolutePoses[jointIndex].rot();
return true;
} else {
return false;
}
}
bool Flow::getJointRotation(const AnimPoseVec& relativePoses, int jointIndex, glm::quat& rotation) const {
if (jointIndex >= 0 && jointIndex < (int)relativePoses.size()) {
rotation = relativePoses[jointIndex].rot();
return true;
} else {
return false;
}
}
bool Flow::getJointTranslation(const AnimPoseVec& relativePoses, int jointIndex, glm::vec3& translation) const {
if (jointIndex >= 0 && jointIndex < (int)relativePoses.size()) {
translation = relativePoses[jointIndex].trans();
return true;
} else {
return false;
}
}
Flow& Flow::operator=(const Flow& otherFlow) {
_active = otherFlow.getActive();
_scale = otherFlow.getScale();
_isScaleSet = true;
auto &threads = otherFlow.getThreads();
if (threads.size() == _jointThreads.size()) {
for (size_t i = 0; i < _jointThreads.size(); i++) {
_jointThreads[i] = threads[i];
}
}
return *this;
}

View file

@ -0,0 +1,328 @@
//
// Flow.h
//
// Created by Luis Cuenca on 1/21/2019.
// Copyright 2019 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_Flow_h
#define hifi_Flow_h
#include <memory>
#include <qstring.h>
#include <glm/glm.hpp>
#include <glm/gtx/quaternion.hpp>
#include <vector>
#include <map>
#include <quuid.h>
#include "AnimPose.h"
class Rig;
class AnimSkeleton;
const float HAPTIC_TOUCH_STRENGTH = 0.25f;
const float HAPTIC_TOUCH_DURATION = 10.0f;
const float HAPTIC_SLOPE = 0.18f;
const float HAPTIC_THRESHOLD = 40.0f;
const QString FLOW_JOINT_PREFIX = "flow";
const QString SIM_JOINT_PREFIX = "sim";
const std::vector<QString> HAND_COLLISION_JOINTS = { "RightHandMiddle1", "RightHandThumb3", "LeftHandMiddle1", "LeftHandThumb3", "RightHandMiddle3", "LeftHandMiddle3" };
const float HAND_COLLISION_RADIUS = 0.03f;
const float HELPER_JOINT_LENGTH = 0.05f;
const float DEFAULT_STIFFNESS = 0.0f;
const float DEFAULT_GRAVITY = -0.0096f;
const float DEFAULT_DAMPING = 0.85f;
const float DEFAULT_INERTIA = 0.8f;
const float DEFAULT_DELTA = 0.55f;
const float DEFAULT_RADIUS = 0.01f;
const uint64_t MAX_UPDATE_FLOW_TIME_BUDGET = 2000;
struct FlowPhysicsSettings {
FlowPhysicsSettings() {};
FlowPhysicsSettings(bool active, float stiffness, float gravity, float damping, float inertia, float delta, float radius) {
_active = active;
_stiffness = stiffness;
_gravity = gravity;
_damping = damping;
_inertia = inertia;
_delta = delta;
_radius = radius;
}
bool _active{ true };
float _stiffness{ DEFAULT_STIFFNESS };
float _gravity{ DEFAULT_GRAVITY };
float _damping{ DEFAULT_DAMPING };
float _inertia{ DEFAULT_INERTIA };
float _delta{ DEFAULT_DELTA };
float _radius{ DEFAULT_RADIUS };
};
enum FlowCollisionType {
CollisionSphere = 0
};
struct FlowCollisionSettings {
FlowCollisionSettings() {};
FlowCollisionSettings(const QUuid& id, const FlowCollisionType& type, const glm::vec3& offset, float radius) {
_entityID = id;
_type = type;
_offset = offset;
_radius = radius;
};
QUuid _entityID;
FlowCollisionType _type { FlowCollisionType::CollisionSphere };
float _radius { 0.05f };
glm::vec3 _offset;
};
const FlowPhysicsSettings DEFAULT_JOINT_SETTINGS;
struct FlowJointInfo {
FlowJointInfo() {};
FlowJointInfo(int index, int parentIndex, int childIndex, const QString& name) {
_index = index;
_parentIndex = parentIndex;
_childIndex = childIndex;
_name = name;
}
int _index { -1 };
QString _name;
int _parentIndex { -1 };
int _childIndex { -1 };
};
struct FlowCollisionResult {
int _count { 0 };
float _offset { 0.0f };
glm::vec3 _position;
float _radius { 0.0f };
glm::vec3 _normal;
float _distance { 0.0f };
};
class FlowCollisionSphere {
public:
FlowCollisionSphere() {};
FlowCollisionSphere(const int& jointIndex, const FlowCollisionSettings& settings, bool isTouch = false);
void setPosition(const glm::vec3& position) { _position = position; }
FlowCollisionResult computeSphereCollision(const glm::vec3& point, float radius) const;
FlowCollisionResult checkSegmentCollision(const glm::vec3& point1, const glm::vec3& point2, const FlowCollisionResult& collisionResult1, const FlowCollisionResult& collisionResult2);
QUuid _entityID;
glm::vec3 _offset;
glm::vec3 _initialOffset;
glm::vec3 _position;
bool _isTouch { false };
int _jointIndex { -1 };
int collisionIndex { -1 };
float _radius { 0.0f };
float _initialRadius{ 0.0f };
};
class FlowThread;
class FlowCollisionSystem {
public:
FlowCollisionSystem() {};
void addCollisionSphere(int jointIndex, const FlowCollisionSettings& settings, const glm::vec3& position = { 0.0f, 0.0f, 0.0f }, bool isSelfCollision = true, bool isTouch = false);
FlowCollisionResult computeCollision(const std::vector<FlowCollisionResult> collisions);
std::vector<FlowCollisionResult> checkFlowThreadCollisions(FlowThread* flowThread);
std::vector<FlowCollisionSphere>& getSelfCollisions() { return _selfCollisions; };
void setOthersCollisions(const std::vector<FlowCollisionSphere>& othersCollisions) { _othersCollisions = othersCollisions; }
void prepareCollisions();
void resetCollisions();
void resetOthersCollisions() { _othersCollisions.clear(); }
void setScale(float scale);
FlowCollisionSettings getCollisionSettingsByJoint(int jointIndex);
void setCollisionSettingsByJoint(int jointIndex, const FlowCollisionSettings& settings);
void setActive(bool active) { _active = active; }
bool getActive() const { return _active; }
protected:
std::vector<FlowCollisionSphere> _selfCollisions;
std::vector<FlowCollisionSphere> _othersCollisions;
std::vector<FlowCollisionSphere> _allCollisions;
float _scale { 1.0f };
bool _active { false };
};
class FlowNode {
public:
FlowNode() {};
FlowNode(const glm::vec3& initialPosition, FlowPhysicsSettings settings);
void update(float deltaTime, const glm::vec3& accelerationOffset);
void solve(const glm::vec3& constrainPoint, float maxDistance, const FlowCollisionResult& collision);
void solveConstraints(const glm::vec3& constrainPoint, float maxDistance);
void solveCollisions(const FlowCollisionResult& collision);
protected:
FlowPhysicsSettings _settings;
glm::vec3 _initialPosition;
glm::vec3 _previousPosition;
glm::vec3 _currentPosition;
glm::vec3 _currentVelocity;
glm::vec3 _previousVelocity;
glm::vec3 _acceleration;
FlowCollisionResult _collision;
FlowCollisionResult _previousCollision;
float _initialRadius { 0.0f };
bool _anchored { false };
bool _colliding { false };
bool _active { true };
float _scale{ 1.0f };
};
class FlowJoint : public FlowNode {
public:
friend class FlowThread;
FlowJoint(): FlowNode() {};
FlowJoint(int jointIndex, int parentIndex, int childIndex, const QString& name, const QString& group, const FlowPhysicsSettings& settings);
void toHelperJoint(const glm::vec3& initialPosition, float length);
void setInitialData(const glm::vec3& initialPosition, const glm::vec3& initialTranslation, const glm::quat& initialRotation, const glm::vec3& parentPosition);
void setUpdatedData(const glm::vec3& updatedPosition, const glm::vec3& updatedTranslation, const glm::quat& updatedRotation, const glm::vec3& parentPosition, const glm::quat& parentWorldRotation);
void setRecoveryPosition(const glm::vec3& recoveryPosition);
void update(float deltaTime);
void solve(const FlowCollisionResult& collision);
void setScale(float scale, bool initScale);
bool isAnchored() const { return _anchored; }
void setAnchored(bool anchored) { _anchored = anchored; }
bool isHelper() const { return _isHelper; }
const FlowPhysicsSettings& getSettings() { return _settings; }
void setSettings(const FlowPhysicsSettings& settings) { _settings = settings; }
const glm::vec3& getCurrentPosition() const { return _currentPosition; }
int getIndex() const { return _index; }
int getParentIndex() const { return _parentIndex; }
void setChildIndex(int index) { _childIndex = index; }
const glm::vec3& getUpdatedPosition() const { return _updatedPosition; }
const QString& getGroup() const { return _group; }
const QString& getName() const { return _name; }
const glm::quat& getCurrentRotation() const { return _currentRotation; }
const glm::vec3& getCurrentTranslation() const { return _initialTranslation; }
const glm::vec3& getInitialPosition() const { return _initialPosition; }
protected:
int _index{ -1 };
int _parentIndex{ -1 };
int _childIndex{ -1 };
QString _name;
QString _group;
bool _isHelper{ false };
glm::vec3 _initialTranslation;
glm::quat _initialRotation;
glm::vec3 _updatedPosition;
glm::vec3 _updatedTranslation;
glm::quat _updatedRotation;
glm::quat _currentRotation;
glm::vec3 _recoveryPosition;
glm::vec3 _parentPosition;
glm::quat _parentWorldRotation;
glm::vec3 _translationDirection;
float _length { 0.0f };
float _initialLength { 0.0f };
bool _applyRecovery { false };
};
class FlowThread {
public:
FlowThread() {};
FlowThread& operator=(const FlowThread& otherFlowThread);
FlowThread(int rootIndex, std::map<int, FlowJoint>* joints);
void resetLength();
void computeFlowThread(int rootIndex);
void computeRecovery();
void update(float deltaTime);
void solve(FlowCollisionSystem& collisionSystem);
void computeJointRotations();
void setRootFramePositions(const std::vector<glm::vec3>& rootFramePositions) { _rootFramePositions = rootFramePositions; }
void setScale(float scale, bool initScale = false);
std::vector<int> _joints;
std::vector<glm::vec3> _positions;
float _radius{ 0.0f };
float _length{ 0.0f };
std::map<int, FlowJoint>* _jointsPointer;
std::vector<glm::vec3> _rootFramePositions;
};
class Flow : public QObject{
Q_OBJECT
public:
Flow() { }
Flow& operator=(const Flow& otherFlow);
bool getActive() const { return _active; }
void setActive(bool active) { _active = active; }
bool isInitialized() const { return _initialized; }
float getScale() const { return _scale; }
void calculateConstraints(const std::shared_ptr<AnimSkeleton>& skeleton, AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses);
void update(float deltaTime, AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses, const std::vector<bool>& overrideFlags);
void setTransform(float scale, const glm::vec3& position, const glm::quat& rotation);
const std::map<int, FlowJoint>& getJoints() const { return _flowJointData; }
const std::vector<FlowThread>& getThreads() const { return _jointThreads; }
void setOthersCollision(const QUuid& otherId, int jointIndex, const glm::vec3& position);
FlowCollisionSystem& getCollisionSystem() { return _collisionSystem; }
void setPhysicsSettingsForGroup(const QString& group, const FlowPhysicsSettings& settings);
void cleanUp();
signals:
void onCleanup();
private:
void updateAbsolutePoses(const AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses);
bool getJointPositionInWorldFrame(const AnimPoseVec& absolutePoses, int jointIndex, glm::vec3& position, glm::vec3 translation, glm::quat rotation) const;
bool getJointRotationInWorldFrame(const AnimPoseVec& absolutePoses, int jointIndex, glm::quat& result, const glm::quat& rotation) const;
bool getJointRotation(const AnimPoseVec& relativePoses, int jointIndex, glm::quat& rotation) const;
bool getJointTranslation(const AnimPoseVec& relativePoses, int jointIndex, glm::vec3& translation) const;
bool worldToJointPoint(const AnimPoseVec& absolutePoses, const glm::vec3& position, const int jointIndex, glm::vec3& jointSpacePosition) const;
void setJoints(AnimPoseVec& relativePoses, const std::vector<bool>& overrideFlags);
void updateJoints(AnimPoseVec& relativePoses, AnimPoseVec& absolutePoses);
bool updateRootFramePositions(const AnimPoseVec& absolutePoses, size_t threadIndex);
void setScale(float scale);
float _scale { 1.0f };
float _lastScale{ 1.0f };
glm::vec3 _entityPosition;
glm::quat _entityRotation;
std::map<int, FlowJoint> _flowJointData;
std::vector<FlowThread> _jointThreads;
std::vector<QString> _flowJointKeywords;
FlowCollisionSystem _collisionSystem;
bool _initialized { false };
bool _active { false };
bool _isScaleSet { false };
bool _invertThreadLoop { false };
};
#endif // hifi_Flow_h

View file

@ -375,7 +375,6 @@ void Rig::reset(const HFMModel& hfmModel) {
_animSkeleton = std::make_shared<AnimSkeleton>(hfmModel); _animSkeleton = std::make_shared<AnimSkeleton>(hfmModel);
_internalPoseSet._relativePoses.clear(); _internalPoseSet._relativePoses.clear();
_internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses(); _internalPoseSet._relativePoses = _animSkeleton->getRelativeDefaultPoses();
@ -759,7 +758,8 @@ void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPos
glm::vec3 forward = worldRotation * IDENTITY_FORWARD; glm::vec3 forward = worldRotation * IDENTITY_FORWARD;
glm::vec3 workingVelocity = worldVelocity; glm::vec3 workingVelocity = worldVelocity;
_internalFlow.setTransform(sensorToWorldScale, worldPosition, worldRotation * Quaternions::Y_180);
_networkFlow.setTransform(sensorToWorldScale, worldPosition, worldRotation * Quaternions::Y_180);
{ {
glm::vec3 localVel = glm::inverse(worldRotation) * workingVelocity; glm::vec3 localVel = glm::inverse(worldRotation) * workingVelocity;
@ -1234,12 +1234,26 @@ void Rig::updateAnimations(float deltaTime, const glm::mat4& rootTransform, cons
_networkVars = networkTriggersOut; _networkVars = networkTriggersOut;
_lastContext = context; _lastContext = context;
} }
applyOverridePoses(); applyOverridePoses();
buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses); buildAbsoluteRigPoses(_internalPoseSet._relativePoses, _internalPoseSet._absolutePoses);
_internalFlow.update(deltaTime, _internalPoseSet._relativePoses, _internalPoseSet._absolutePoses, _internalPoseSet._overrideFlags);
if (_sendNetworkNode) {
if (_internalFlow.getActive() && !_networkFlow.getActive()) {
_networkFlow = _internalFlow;
}
buildAbsoluteRigPoses(_networkPoseSet._relativePoses, _networkPoseSet._absolutePoses); buildAbsoluteRigPoses(_networkPoseSet._relativePoses, _networkPoseSet._absolutePoses);
_networkFlow.update(deltaTime, _networkPoseSet._relativePoses, _networkPoseSet._absolutePoses, _internalPoseSet._overrideFlags);
} else if (_networkFlow.getActive()) {
_networkFlow.setActive(false);
}
// copy internal poses to external poses // copy internal poses to external poses
{ {
QWriteLocker writeLock(&_externalPoseSetLock); QWriteLocker writeLock(&_externalPoseSetLock);
_externalPoseSet = _internalPoseSet; _externalPoseSet = _internalPoseSet;
} }
} }
@ -1920,7 +1934,6 @@ void Rig::initAnimGraph(const QUrl& url) {
auto roleState = roleAnimState.second; auto roleState = roleAnimState.second;
overrideRoleAnimation(roleState.role, roleState.url, roleState.fps, roleState.loop, roleState.firstFrame, roleState.lastFrame); overrideRoleAnimation(roleState.role, roleState.url, roleState.fps, roleState.loop, roleState.firstFrame, roleState.lastFrame);
} }
emit onLoadComplete(); emit onLoadComplete();
}); });
connect(_animLoader.get(), &AnimNodeLoader::error, [url](int error, QString str) { connect(_animLoader.get(), &AnimNodeLoader::error, [url](int error, QString str) {
@ -2159,3 +2172,16 @@ void Rig::computeAvatarBoundingCapsule(
glm::vec3 capsuleCenter = transformPoint(_geometryToRigTransform, (0.5f * (totalExtents.maximum + totalExtents.minimum))); glm::vec3 capsuleCenter = transformPoint(_geometryToRigTransform, (0.5f * (totalExtents.maximum + totalExtents.minimum)));
localOffsetOut = capsuleCenter - hipsPosition; localOffsetOut = capsuleCenter - hipsPosition;
} }
void Rig::initFlow(bool isActive) {
_internalFlow.setActive(isActive);
if (isActive) {
if (!_internalFlow.isInitialized()) {
_internalFlow.calculateConstraints(_animSkeleton, _internalPoseSet._relativePoses, _internalPoseSet._absolutePoses);
_networkFlow.calculateConstraints(_animSkeleton, _internalPoseSet._relativePoses, _internalPoseSet._absolutePoses);
}
} else {
_internalFlow.cleanUp();
_networkFlow.cleanUp();
}
}

View file

@ -25,6 +25,7 @@
#include "AnimNodeLoader.h" #include "AnimNodeLoader.h"
#include "SimpleMovingAverage.h" #include "SimpleMovingAverage.h"
#include "AnimUtil.h" #include "AnimUtil.h"
#include "Flow.h"
class Rig; class Rig;
class AnimInverseKinematics; class AnimInverseKinematics;
@ -233,6 +234,9 @@ public:
const AnimContext::DebugAlphaMap& getDebugAlphaMap() const { return _lastContext.getDebugAlphaMap(); } const AnimContext::DebugAlphaMap& getDebugAlphaMap() const { return _lastContext.getDebugAlphaMap(); }
const AnimVariantMap& getAnimVars() const { return _lastAnimVars; } const AnimVariantMap& getAnimVars() const { return _lastAnimVars; }
const AnimContext::DebugStateMachineMap& getStateMachineMap() const { return _lastContext.getStateMachineMap(); } const AnimContext::DebugStateMachineMap& getStateMachineMap() const { return _lastContext.getStateMachineMap(); }
void initFlow(bool isActive);
Flow& getFlow() { return _internalFlow; }
signals: signals:
void onLoadComplete(); void onLoadComplete();
@ -424,6 +428,8 @@ protected:
SnapshotBlendPoseHelper _hipsBlendHelper; SnapshotBlendPoseHelper _hipsBlendHelper;
ControllerParameters _previousControllerParameters; ControllerParameters _previousControllerParameters;
Flow _internalFlow;
Flow _networkFlow;
}; };
#endif /* defined(__hifi__Rig__) */ #endif /* defined(__hifi__Rig__) */

View file

@ -175,7 +175,7 @@ static float computeLoudness(int16_t* samples, int numSamples, int numChannels,
const int32_t CLIPPING_THRESHOLD = 32392; // -0.1 dBFS const int32_t CLIPPING_THRESHOLD = 32392; // -0.1 dBFS
const int32_t CLIPPING_DETECTION = 3; // consecutive samples over threshold const int32_t CLIPPING_DETECTION = 3; // consecutive samples over threshold
float scale = numSamples ? 1.0f / (numSamples * 32768.0f) : 0.0f; float scale = numSamples ? 1.0f / numSamples : 0.0f;
int32_t loudness = 0; int32_t loudness = 0;
isClipping = false; isClipping = false;
@ -249,6 +249,8 @@ AudioClient::AudioClient() :
_outputBufferSizeFrames("audioOutputBufferFrames", DEFAULT_BUFFER_FRAMES), _outputBufferSizeFrames("audioOutputBufferFrames", DEFAULT_BUFFER_FRAMES),
_sessionOutputBufferSizeFrames(_outputBufferSizeFrames.get()), _sessionOutputBufferSizeFrames(_outputBufferSizeFrames.get()),
_outputStarveDetectionEnabled("audioOutputStarveDetectionEnabled", DEFAULT_STARVE_DETECTION_ENABLED), _outputStarveDetectionEnabled("audioOutputStarveDetectionEnabled", DEFAULT_STARVE_DETECTION_ENABLED),
_lastRawInputLoudness(0.0f),
_lastSmoothedRawInputLoudness(0.0f),
_lastInputLoudness(0.0f), _lastInputLoudness(0.0f),
_timeSinceLastClip(-1.0f), _timeSinceLastClip(-1.0f),
_muted(false), _muted(false),
@ -1144,6 +1146,9 @@ void AudioClient::handleAudioInput(QByteArray& audioBuffer) {
emit inputReceived(audioBuffer); emit inputReceived(audioBuffer);
} }
// loudness after mute/gate
_lastInputLoudness = (_muted || !audioGateOpen) ? 0.0f : _lastRawInputLoudness;
// detect gate opening and closing // detect gate opening and closing
bool openedInLastBlock = !_audioGateOpen && audioGateOpen; // the gate just opened bool openedInLastBlock = !_audioGateOpen && audioGateOpen; // the gate just opened
bool closedInLastBlock = _audioGateOpen && !audioGateOpen; // the gate just closed bool closedInLastBlock = _audioGateOpen && !audioGateOpen; // the gate just closed
@ -1222,12 +1227,15 @@ void AudioClient::handleMicAudioInput() {
// detect loudness and clipping on the raw input // detect loudness and clipping on the raw input
bool isClipping = false; bool isClipping = false;
float inputLoudness = computeLoudness(inputAudioSamples.get(), inputSamplesRequired, _inputFormat.channelCount(), isClipping); float loudness = computeLoudness(inputAudioSamples.get(), inputSamplesRequired, _inputFormat.channelCount(), isClipping);
_lastRawInputLoudness = loudness;
float tc = (inputLoudness > _lastInputLoudness) ? 0.378f : 0.967f; // 10ms attack, 300ms release @ 100Hz // envelope detection
inputLoudness += tc * (_lastInputLoudness - inputLoudness); float tc = (loudness > _lastSmoothedRawInputLoudness) ? 0.378f : 0.967f; // 10ms attack, 300ms release @ 100Hz
_lastInputLoudness = inputLoudness; loudness += tc * (_lastSmoothedRawInputLoudness - loudness);
_lastSmoothedRawInputLoudness = loudness;
// clipping indicator
if (isClipping) { if (isClipping) {
_timeSinceLastClip = 0.0f; _timeSinceLastClip = 0.0f;
} else if (_timeSinceLastClip >= 0.0f) { } else if (_timeSinceLastClip >= 0.0f) {
@ -1235,7 +1243,7 @@ void AudioClient::handleMicAudioInput() {
} }
isClipping = (_timeSinceLastClip >= 0.0f) && (_timeSinceLastClip < 2.0f); // 2 second hold time isClipping = (_timeSinceLastClip >= 0.0f) && (_timeSinceLastClip < 2.0f); // 2 second hold time
emit inputLoudnessChanged(_lastInputLoudness, isClipping); emit inputLoudnessChanged(_lastSmoothedRawInputLoudness, isClipping);
if (!_muted) { if (!_muted) {
possibleResampling(_inputToNetworkResampler, possibleResampling(_inputToNetworkResampler,

View file

@ -127,7 +127,7 @@ public:
const QAudioFormat& getOutputFormat() const { return _outputFormat; } const QAudioFormat& getOutputFormat() const { return _outputFormat; }
float getLastInputLoudness() const { return _lastInputLoudness; } // TODO: relative to noise floor? float getLastInputLoudness() const { return _lastInputLoudness; }
float getTimeSinceLastClip() const { return _timeSinceLastClip; } float getTimeSinceLastClip() const { return _timeSinceLastClip; }
float getAudioAverageInputLoudness() const { return _lastInputLoudness; } float getAudioAverageInputLoudness() const { return _lastInputLoudness; }
@ -355,7 +355,9 @@ private:
StDev _stdev; StDev _stdev;
QElapsedTimer _timeSinceLastReceived; QElapsedTimer _timeSinceLastReceived;
float _lastInputLoudness; float _lastRawInputLoudness; // before mute/gate
float _lastSmoothedRawInputLoudness;
float _lastInputLoudness; // after mute/gate
float _timeSinceLastClip; float _timeSinceLastClip;
int _totalInputAudioSamples; int _totalInputAudioSamples;

View file

@ -1535,6 +1535,7 @@ void Avatar::setModelURLFinished(bool success) {
// rig is ready // rig is ready
void Avatar::rigReady() { void Avatar::rigReady() {
buildUnscaledEyeHeightCache(); buildUnscaledEyeHeightCache();
buildSpine2SplineRatioCache();
computeMultiSphereShapes(); computeMultiSphereShapes();
buildSpine2SplineRatioCache(); buildSpine2SplineRatioCache();
} }

View file

@ -235,6 +235,8 @@ public:
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override; virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override;
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; } virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; }
virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; } virtual bool setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) override { return false; }
virtual glm::vec3 getSpine2SplineOffset() const { return _spine2SplineOffset; }
virtual float getSpine2SplineRatio() const { return _spine2SplineRatio; }
// world-space to avatar-space rigconversion functions // world-space to avatar-space rigconversion functions
/**jsdoc /**jsdoc

View file

@ -219,7 +219,6 @@ void EntityTreeRenderer::clearNonLocalEntities() {
std::unordered_map<EntityItemID, EntityRendererPointer> savedEntities; std::unordered_map<EntityItemID, EntityRendererPointer> savedEntities;
// remove all entities from the scene // remove all entities from the scene
_space->clear();
auto scene = _viewState->getMain3DScene(); auto scene = _viewState->getMain3DScene();
if (scene) { if (scene) {
render::Transaction transaction; render::Transaction transaction;
@ -259,8 +258,6 @@ void EntityTreeRenderer::clear() {
resetEntitiesScriptEngine(); resetEntitiesScriptEngine();
} }
// remove all entities from the scene // remove all entities from the scene
_space->clear();
auto scene = _viewState->getMain3DScene(); auto scene = _viewState->getMain3DScene();
if (scene) { if (scene) {
render::Transaction transaction; render::Transaction transaction;

View file

@ -170,7 +170,7 @@ void ImageEntityRenderer::doRender(RenderArgs* args) {
Q_ASSERT(args->_batch); Q_ASSERT(args->_batch);
gpu::Batch* batch = args->_batch; gpu::Batch* batch = args->_batch;
transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode)); transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, args->getViewFrustum().getPosition()));
transform.postScale(dimensions); transform.postScale(dimensions);
batch->setModelTransform(transform); batch->setModelTransform(transform);

View file

@ -60,7 +60,7 @@ bool ShapeEntityRenderer::needsRenderUpdate() const {
} }
auto mat = _materials.find("0"); auto mat = _materials.find("0");
if (mat != _materials.end() && (mat->second.needsUpdate() || mat->second.areTexturesLoading())) { if (mat != _materials.end() && mat->second.shouldUpdate()) {
return true; return true;
} }
@ -195,7 +195,7 @@ bool ShapeEntityRenderer::useMaterialPipeline(const graphics::MultiMaterial& mat
ShapeKey ShapeEntityRenderer::getShapeKey() { ShapeKey ShapeEntityRenderer::getShapeKey() {
auto mat = _materials.find("0"); auto mat = _materials.find("0");
if (mat != _materials.end() && (mat->second.needsUpdate() || mat->second.areTexturesLoading())) { if (mat != _materials.end() && mat->second.shouldUpdate()) {
RenderPipelines::updateMultiMaterial(mat->second); RenderPipelines::updateMultiMaterial(mat->second);
} }

View file

@ -181,7 +181,7 @@ void TextEntityRenderer::doRender(RenderArgs* args) {
gpu::Batch& batch = *args->_batch; gpu::Batch& batch = *args->_batch;
auto transformToTopLeft = modelTransform; auto transformToTopLeft = modelTransform;
transformToTopLeft.setRotation(EntityItem::getBillboardRotation(transformToTopLeft.getTranslation(), transformToTopLeft.getRotation(), _billboardMode)); transformToTopLeft.setRotation(EntityItem::getBillboardRotation(transformToTopLeft.getTranslation(), transformToTopLeft.getRotation(), _billboardMode, args->getViewFrustum().getPosition()));
transformToTopLeft.postTranslate(dimensions * glm::vec3(-0.5f, 0.5f, 0.0f)); // Go to the top left transformToTopLeft.postTranslate(dimensions * glm::vec3(-0.5f, 0.5f, 0.0f)); // Go to the top left
transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed transformToTopLeft.setScale(1.0f); // Use a scale of one so that the text is not deformed

View file

@ -101,21 +101,15 @@ bool WebEntityRenderer::isTransparent() const {
} }
bool WebEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { bool WebEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
if (resultWithReadLock<bool>([&] {
if (_webSurface && uvec2(getWindowSize(entity)) != toGlm(_webSurface->size())) {
return true;
}
if (_contextPosition != entity->getWorldPosition()) { if (_contextPosition != entity->getWorldPosition()) {
return true; return true;
} }
{
QSharedPointer<OffscreenQmlSurface> webSurface;
withReadLock([&] {
webSurface = _webSurface;
});
if (webSurface && uvec2(getWindowSize(entity)) != toGlm(webSurface->size())) {
return true;
}
}
if(resultWithReadLock<bool>([&] {
if (_color != entity->getColor()) { if (_color != entity->getColor()) {
return true; return true;
} }
@ -194,7 +188,7 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
auto newContentType = getContentType(newSourceURL); auto newContentType = getContentType(newSourceURL);
ContentType currentContentType; ContentType currentContentType;
withReadLock([&] { withReadLock([&] {
urlChanged = _sourceURL != newSourceURL; urlChanged = newSourceURL.isEmpty() || newSourceURL != _tryingToBuildURL;
}); });
currentContentType = _contentType; currentContentType = _contentType;
@ -206,7 +200,6 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
} }
} }
withWriteLock([&] { withWriteLock([&] {
_inputMode = entity->getInputMode(); _inputMode = entity->getInputMode();
_dpi = entity->getDPI(); _dpi = entity->getDPI();
@ -216,6 +209,8 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
_billboardMode = entity->getBillboardMode(); _billboardMode = entity->getBillboardMode();
if (_contentType == ContentType::NoContent) { if (_contentType == ContentType::NoContent) {
_tryingToBuildURL = newSourceURL;
_sourceURL = newSourceURL;
return; return;
} }
@ -226,10 +221,12 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene
if (_webSurface) { if (_webSurface) {
if (_webSurface->getRootItem()) { if (_webSurface->getRootItem()) {
if (_contentType == ContentType::HtmlContent && urlChanged) { if (_contentType == ContentType::HtmlContent && _sourceURL != newSourceURL) {
_webSurface->getRootItem()->setProperty(URL_PROPERTY, newSourceURL); _webSurface->getRootItem()->setProperty(URL_PROPERTY, newSourceURL);
}
_sourceURL = newSourceURL; _sourceURL = newSourceURL;
} else if (_contentType != ContentType::HtmlContent) {
_sourceURL = newSourceURL;
}
{ {
auto scriptURL = entity->getScriptURL(); auto scriptURL = entity->getScriptURL();
@ -294,21 +291,22 @@ void WebEntityRenderer::doRender(RenderArgs* args) {
}); });
// Try to update the texture // Try to update the texture
{ OffscreenQmlSurface::TextureAndFence newTextureAndFence;
QSharedPointer<OffscreenQmlSurface> webSurface; bool newTextureAvailable = false;
withReadLock([&] { if (!resultWithReadLock<bool>([&] {
webSurface = _webSurface; if (!_webSurface) {
}); return false;
if (!webSurface) { }
newTextureAvailable = _webSurface->fetchTexture(newTextureAndFence);
return true;
})) {
return; return;
} }
OffscreenQmlSurface::TextureAndFence newTextureAndFence;
bool newTextureAvailable = webSurface->fetchTexture(newTextureAndFence);
if (newTextureAvailable) { if (newTextureAvailable) {
_texture->setExternalTexture(newTextureAndFence.first, newTextureAndFence.second); _texture->setExternalTexture(newTextureAndFence.first, newTextureAndFence.second);
} }
}
static const glm::vec2 texMin(0.0f), texMax(1.0f), topLeft(-0.5f), bottomRight(0.5f); static const glm::vec2 texMin(0.0f), texMax(1.0f), topLeft(-0.5f), bottomRight(0.5f);
@ -323,7 +321,7 @@ void WebEntityRenderer::doRender(RenderArgs* args) {
}); });
batch.setResourceTexture(0, _texture); batch.setResourceTexture(0, _texture);
transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode)); transform.setRotation(EntityItem::getBillboardRotation(transform.getTranslation(), transform.getRotation(), _billboardMode, args->getViewFrustum().getPosition()));
batch.setModelTransform(transform); batch.setModelTransform(transform);
// Turn off jitter for these entities // Turn off jitter for these entities
@ -351,6 +349,8 @@ void WebEntityRenderer::buildWebSurface(const EntityItemPointer& entity, const Q
_connections.push_back(QObject::connect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, [entityItemID](const QVariant& message) { _connections.push_back(QObject::connect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, [entityItemID](const QVariant& message) {
emit DependencyManager::get<EntityScriptingInterface>()->webEventReceived(entityItemID, message); emit DependencyManager::get<EntityScriptingInterface>()->webEventReceived(entityItemID, message);
})); }));
_tryingToBuildURL = newSourceURL;
} }
void WebEntityRenderer::destroyWebSurface() { void WebEntityRenderer::destroyWebSurface() {
@ -383,11 +383,16 @@ glm::vec2 WebEntityRenderer::getWindowSize(const TypedEntityPointer& entity) con
void WebEntityRenderer::hoverEnterEntity(const PointerEvent& event) { void WebEntityRenderer::hoverEnterEntity(const PointerEvent& event) {
if (_inputMode == WebInputMode::MOUSE) { if (_inputMode == WebInputMode::MOUSE) {
handlePointerEvent(event); handlePointerEvent(event);
} else if (_webSurface) { return;
}
withReadLock([&] {
if (_webSurface) {
PointerEvent webEvent = event; PointerEvent webEvent = event;
webEvent.setPos2D(event.getPos2D() * (METERS_TO_INCHES * _dpi)); webEvent.setPos2D(event.getPos2D() * (METERS_TO_INCHES * _dpi));
_webSurface->hoverBeginEvent(webEvent, _touchDevice); _webSurface->hoverBeginEvent(webEvent, _touchDevice);
} }
});
} }
void WebEntityRenderer::hoverLeaveEntity(const PointerEvent& event) { void WebEntityRenderer::hoverLeaveEntity(const PointerEvent& event) {
@ -398,34 +403,39 @@ void WebEntityRenderer::hoverLeaveEntity(const PointerEvent& event) {
// QML onReleased is only triggered if a click has happened first. We need to send this "fake" mouse move event to properly trigger an onExited. // QML onReleased is only triggered if a click has happened first. We need to send this "fake" mouse move event to properly trigger an onExited.
PointerEvent endMoveEvent(PointerEvent::Move, event.getID()); PointerEvent endMoveEvent(PointerEvent::Move, event.getID());
handlePointerEvent(endMoveEvent); handlePointerEvent(endMoveEvent);
} else if (_webSurface) { return;
}
withReadLock([&] {
if (_webSurface) {
PointerEvent webEvent = event; PointerEvent webEvent = event;
webEvent.setPos2D(event.getPos2D() * (METERS_TO_INCHES * _dpi)); webEvent.setPos2D(event.getPos2D() * (METERS_TO_INCHES * _dpi));
_webSurface->hoverEndEvent(webEvent, _touchDevice); _webSurface->hoverEndEvent(webEvent, _touchDevice);
} }
});
} }
void WebEntityRenderer::handlePointerEvent(const PointerEvent& event) { void WebEntityRenderer::handlePointerEvent(const PointerEvent& event) {
withReadLock([&] {
if (!_webSurface) {
return;
}
if (_inputMode == WebInputMode::TOUCH) { if (_inputMode == WebInputMode::TOUCH) {
handlePointerEventAsTouch(event); handlePointerEventAsTouch(event);
} else { } else {
handlePointerEventAsMouse(event); handlePointerEventAsMouse(event);
} }
});
} }
void WebEntityRenderer::handlePointerEventAsTouch(const PointerEvent& event) { void WebEntityRenderer::handlePointerEventAsTouch(const PointerEvent& event) {
if (_webSurface) {
PointerEvent webEvent = event; PointerEvent webEvent = event;
webEvent.setPos2D(event.getPos2D() * (METERS_TO_INCHES * _dpi)); webEvent.setPos2D(event.getPos2D() * (METERS_TO_INCHES * _dpi));
_webSurface->handlePointerEvent(webEvent, _touchDevice); _webSurface->handlePointerEvent(webEvent, _touchDevice);
}
} }
void WebEntityRenderer::handlePointerEventAsMouse(const PointerEvent& event) { void WebEntityRenderer::handlePointerEventAsMouse(const PointerEvent& event) {
if (!_webSurface) {
return;
}
glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _dpi); glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _dpi);
QPointF windowPoint(windowPos.x, windowPos.y); QPointF windowPoint(windowPos.x, windowPos.y);
@ -459,16 +469,20 @@ void WebEntityRenderer::handlePointerEventAsMouse(const PointerEvent& event) {
} }
void WebEntityRenderer::setProxyWindow(QWindow* proxyWindow) { void WebEntityRenderer::setProxyWindow(QWindow* proxyWindow) {
withReadLock([&] {
if (_webSurface) { if (_webSurface) {
_webSurface->setProxyWindow(proxyWindow); _webSurface->setProxyWindow(proxyWindow);
} }
});
} }
QObject* WebEntityRenderer::getEventHandler() { QObject* WebEntityRenderer::getEventHandler() {
return resultWithReadLock<QObject*>([&]() -> QObject* {
if (!_webSurface) { if (!_webSurface) {
return nullptr; return nullptr;
} }
return _webSurface->getEventHandler(); return _webSurface->getEventHandler();
});
} }
void WebEntityRenderer::emitScriptEvent(const QVariant& message) { void WebEntityRenderer::emitScriptEvent(const QVariant& message) {

View file

@ -82,6 +82,7 @@ private:
QSharedPointer<OffscreenQmlSurface> _webSurface { nullptr }; QSharedPointer<OffscreenQmlSurface> _webSurface { nullptr };
bool _cachedWebSurface { false }; bool _cachedWebSurface { false };
gpu::TexturePointer _texture; gpu::TexturePointer _texture;
QString _tryingToBuildURL;
glm::u8vec3 _color; glm::u8vec3 _color;
float _alpha { 1.0f }; float _alpha { 1.0f };

View file

@ -49,7 +49,8 @@ int EntityItem::_maxActionsDataSize = 800;
quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND; quint64 EntityItem::_rememberDeletedActionTime = 20 * USECS_PER_SECOND;
QString EntityItem::_marketplacePublicKey; QString EntityItem::_marketplacePublicKey;
std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode)> EntityItem::_getBillboardRotationOperator = [](const glm::vec3&, const glm::quat& rotation, BillboardMode) { return rotation; }; std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode, const glm::vec3&)> EntityItem::_getBillboardRotationOperator = [](const glm::vec3&, const glm::quat& rotation, BillboardMode, const glm::vec3&) { return rotation; };
std::function<glm::vec3()> EntityItem::_getPrimaryViewFrustumPositionOperator = []() { return glm::vec3(0.0f); };
EntityItem::EntityItem(const EntityItemID& entityItemID) : EntityItem::EntityItem(const EntityItemID& entityItemID) :
SpatiallyNestable(NestableType::Entity, entityItemID) SpatiallyNestable(NestableType::Entity, entityItemID)
@ -266,7 +267,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet
APPEND_ENTITY_PROPERTY(PROP_HREF, getHref()); APPEND_ENTITY_PROPERTY(PROP_HREF, getHref());
APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, getDescription()); APPEND_ENTITY_PROPERTY(PROP_DESCRIPTION, getDescription());
APPEND_ENTITY_PROPERTY(PROP_POSITION, getLocalPosition()); APPEND_ENTITY_PROPERTY(PROP_POSITION, getLocalPosition());
APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, getUnscaledDimensions()); APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, getScaledDimensions());
APPEND_ENTITY_PROPERTY(PROP_ROTATION, getLocalOrientation()); APPEND_ENTITY_PROPERTY(PROP_ROTATION, getLocalOrientation());
APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, getRegistrationPoint()); APPEND_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, getRegistrationPoint());
APPEND_ENTITY_PROPERTY(PROP_CREATED, getCreated()); APPEND_ENTITY_PROPERTY(PROP_CREATED, getCreated());
@ -818,7 +819,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
}; };
READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, customUpdatePositionFromNetwork); READ_ENTITY_PROPERTY(PROP_POSITION, glm::vec3, customUpdatePositionFromNetwork);
} }
READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, setUnscaledDimensions); READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, setScaledDimensions);
{ // See comment above { // See comment above
auto customUpdateRotationFromNetwork = [this, shouldUpdate, lastEdited](glm::quat value) { auto customUpdateRotationFromNetwork = [this, shouldUpdate, lastEdited](glm::quat value) {
if (shouldUpdate(_lastUpdatedRotationTimestamp, value != _lastUpdatedRotationValue)) { if (shouldUpdate(_lastUpdatedRotationTimestamp, value != _lastUpdatedRotationValue)) {
@ -1315,7 +1316,7 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire
COPY_ENTITY_PROPERTY_TO_PROPERTIES(href, getHref); COPY_ENTITY_PROPERTY_TO_PROPERTIES(href, getHref);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(description, getDescription); COPY_ENTITY_PROPERTY_TO_PROPERTIES(description, getDescription);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getLocalPosition); COPY_ENTITY_PROPERTY_TO_PROPERTIES(position, getLocalPosition);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(dimensions, getUnscaledDimensions); COPY_ENTITY_PROPERTY_TO_PROPERTIES(dimensions, getScaledDimensions);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotation, getLocalOrientation); COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotation, getLocalOrientation);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(registrationPoint, getRegistrationPoint); COPY_ENTITY_PROPERTY_TO_PROPERTIES(registrationPoint, getRegistrationPoint);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(created, getCreated); COPY_ENTITY_PROPERTY_TO_PROPERTIES(created, getCreated);
@ -1462,7 +1463,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(href, setHref); SET_ENTITY_PROPERTY_FROM_PROPERTIES(href, setHref);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(description, setDescription); SET_ENTITY_PROPERTY_FROM_PROPERTIES(description, setDescription);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, setPosition); SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, setPosition);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, setUnscaledDimensions); SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, setScaledDimensions);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, setRotation); SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, setRotation);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint); SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, setCreated); SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, setCreated);
@ -1872,7 +1873,7 @@ glm::vec3 EntityItem::getScaledDimensions() const {
void EntityItem::setScaledDimensions(const glm::vec3& value) { void EntityItem::setScaledDimensions(const glm::vec3& value) {
glm::vec3 parentScale = getSNScale(); glm::vec3 parentScale = getSNScale();
setUnscaledDimensions(value * parentScale); setUnscaledDimensions(value / parentScale);
} }
void EntityItem::setUnscaledDimensions(const glm::vec3& value) { void EntityItem::setUnscaledDimensions(const glm::vec3& value) {

View file

@ -557,8 +557,10 @@ public:
virtual void removeGrab(GrabPointer grab) override; virtual void removeGrab(GrabPointer grab) override;
virtual void disableGrab(GrabPointer grab) override; virtual void disableGrab(GrabPointer grab) override;
static void setBillboardRotationOperator(std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode)> getBillboardRotationOperator) { _getBillboardRotationOperator = getBillboardRotationOperator; } static void setBillboardRotationOperator(std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode, const glm::vec3&)> getBillboardRotationOperator) { _getBillboardRotationOperator = getBillboardRotationOperator; }
static glm::quat getBillboardRotation(const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode) { return _getBillboardRotationOperator(position, rotation, billboardMode); } static glm::quat getBillboardRotation(const glm::vec3& position, const glm::quat& rotation, BillboardMode billboardMode, const glm::vec3& frustumPos) { return _getBillboardRotationOperator(position, rotation, billboardMode, frustumPos); }
static void setPrimaryViewFrustumPositionOperator(std::function<glm::vec3()> getPrimaryViewFrustumPositionOperator) { _getPrimaryViewFrustumPositionOperator = getPrimaryViewFrustumPositionOperator; }
static glm::vec3 getPrimaryViewFrustumPosition() { return _getPrimaryViewFrustumPositionOperator(); }
signals: signals:
void requestRenderUpdate(); void requestRenderUpdate();
@ -748,7 +750,8 @@ protected:
QHash<QUuid, EntityDynamicPointer> _grabActions; QHash<QUuid, EntityDynamicPointer> _grabActions;
private: private:
static std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode)> _getBillboardRotationOperator; static std::function<glm::quat(const glm::vec3&, const glm::quat&, BillboardMode, const glm::vec3&)> _getBillboardRotationOperator;
static std::function<glm::vec3()> _getPrimaryViewFrustumPositionOperator;
}; };
#endif // hifi_EntityItem_h #endif // hifi_EntityItem_h

View file

@ -580,6 +580,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
// Model // Model
CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL); CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL);
CHECK_PROPERTY_CHANGE(PROP_MODEL_SCALE, modelScale);
CHECK_PROPERTY_CHANGE(PROP_JOINT_ROTATIONS_SET, jointRotationsSet); CHECK_PROPERTY_CHANGE(PROP_JOINT_ROTATIONS_SET, jointRotationsSet);
CHECK_PROPERTY_CHANGE(PROP_JOINT_ROTATIONS, jointRotations); CHECK_PROPERTY_CHANGE(PROP_JOINT_ROTATIONS, jointRotations);
CHECK_PROPERTY_CHANGE(PROP_JOINT_TRANSLATIONS_SET, jointTranslationsSet); CHECK_PROPERTY_CHANGE(PROP_JOINT_TRANSLATIONS_SET, jointTranslationsSet);
@ -1012,6 +1013,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
* @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity. When adding an entity, if no <code>dimensions</code> * @property {Vec3} dimensions=0.1,0.1,0.1 - The dimensions of the entity. When adding an entity, if no <code>dimensions</code>
* value is specified then the model is automatically sized to its * value is specified then the model is automatically sized to its
* <code>{@link Entities.EntityProperties|naturalDimensions}</code>. * <code>{@link Entities.EntityProperties|naturalDimensions}</code>.
* @property {Vec3} modelScale - The scale factor applied to the model's dimensions. Deprecated.
* @property {Color} color=255,255,255 - <em>Currently not used.</em> * @property {Color} color=255,255,255 - <em>Currently not used.</em>
* @property {string} modelURL="" - The URL of the FBX of OBJ model. Baked FBX models' URLs end in ".baked.fbx".<br /> * @property {string} modelURL="" - The URL of the FBX of OBJ model. Baked FBX models' URLs end in ".baked.fbx".<br />
* @property {string} textures="" - A JSON string of texture name, URL pairs used when rendering the model in place of the * @property {string} textures="" - A JSON string of texture name, URL pairs used when rendering the model in place of the
@ -1683,6 +1685,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_TEXTURES, textures);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MODEL_URL, modelURL); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MODEL_URL, modelURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MODEL_SCALE, modelScale);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_ROTATIONS_SET, jointRotationsSet); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_ROTATIONS_SET, jointRotationsSet);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_ROTATIONS, jointRotations); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_ROTATIONS, jointRotations);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_TRANSLATIONS_SET, jointTranslationsSet); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_JOINT_TRANSLATIONS_SET, jointTranslationsSet);
@ -2078,6 +2081,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
// Model // Model
COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL); COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(modelScale, vec3, setModelScale);
COPY_PROPERTY_FROM_QSCRIPTVALUE(jointRotationsSet, qVectorBool, setJointRotationsSet); COPY_PROPERTY_FROM_QSCRIPTVALUE(jointRotationsSet, qVectorBool, setJointRotationsSet);
COPY_PROPERTY_FROM_QSCRIPTVALUE(jointRotations, qVectorQuat, setJointRotations); COPY_PROPERTY_FROM_QSCRIPTVALUE(jointRotations, qVectorQuat, setJointRotations);
COPY_PROPERTY_FROM_QSCRIPTVALUE(jointTranslationsSet, qVectorBool, setJointTranslationsSet); COPY_PROPERTY_FROM_QSCRIPTVALUE(jointTranslationsSet, qVectorBool, setJointTranslationsSet);
@ -2357,6 +2361,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
// Model // Model
COPY_PROPERTY_IF_CHANGED(modelURL); COPY_PROPERTY_IF_CHANGED(modelURL);
COPY_PROPERTY_IF_CHANGED(modelScale);
COPY_PROPERTY_IF_CHANGED(jointRotationsSet); COPY_PROPERTY_IF_CHANGED(jointRotationsSet);
COPY_PROPERTY_IF_CHANGED(jointRotations); COPY_PROPERTY_IF_CHANGED(jointRotations);
COPY_PROPERTY_IF_CHANGED(jointTranslationsSet); COPY_PROPERTY_IF_CHANGED(jointTranslationsSet);
@ -2700,6 +2705,7 @@ bool EntityItemProperties::getPropertyInfo(const QString& propertyName, EntityPr
// Model // Model
ADD_PROPERTY_TO_MAP(PROP_MODEL_URL, ModelURL, modelURL, QString); ADD_PROPERTY_TO_MAP(PROP_MODEL_URL, ModelURL, modelURL, QString);
ADD_PROPERTY_TO_MAP(PROP_MODEL_SCALE, ModelScale, modelScale, vec3);
ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS_SET, JointRotationsSet, jointRotationsSet, QVector<bool>); ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS_SET, JointRotationsSet, jointRotationsSet, QVector<bool>);
ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector<quat>); ADD_PROPERTY_TO_MAP(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector<quat>);
ADD_PROPERTY_TO_MAP(PROP_JOINT_TRANSLATIONS_SET, JointTranslationsSet, jointTranslationsSet, QVector<bool>); ADD_PROPERTY_TO_MAP(PROP_JOINT_TRANSLATIONS_SET, JointTranslationsSet, jointTranslationsSet, QVector<bool>);
@ -3989,6 +3995,7 @@ void EntityItemProperties::markAllChanged() {
// Model // Model
_modelURLChanged = true; _modelURLChanged = true;
_modelScaleChanged = true;
_jointRotationsSetChanged = true; _jointRotationsSetChanged = true;
_jointRotationsChanged = true; _jointRotationsChanged = true;
_jointTranslationsSetChanged = true; _jointTranslationsSetChanged = true;
@ -4526,6 +4533,9 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (modelURLChanged()) { if (modelURLChanged()) {
out += "modelURL"; out += "modelURL";
} }
if (modelScaleChanged()) {
out += "scale";
}
if (jointRotationsSetChanged()) { if (jointRotationsSetChanged()) {
out += "jointRotationsSet"; out += "jointRotationsSet";
} }

View file

@ -279,6 +279,7 @@ public:
// Model // Model
DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString, ""); DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString, "");
DEFINE_PROPERTY_REF(PROP_MODEL_SCALE, ModelScale, modelScale, glm::vec3, glm::vec3(1.0f));
DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS_SET, JointRotationsSet, jointRotationsSet, QVector<bool>, QVector<bool>()); DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS_SET, JointRotationsSet, jointRotationsSet, QVector<bool>, QVector<bool>());
DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector<glm::quat>, QVector<glm::quat>()); DEFINE_PROPERTY_REF(PROP_JOINT_ROTATIONS, JointRotations, jointRotations, QVector<glm::quat>, QVector<glm::quat>());
DEFINE_PROPERTY_REF(PROP_JOINT_TRANSLATIONS_SET, JointTranslationsSet, jointTranslationsSet, QVector<bool>, QVector<bool>()); DEFINE_PROPERTY_REF(PROP_JOINT_TRANSLATIONS_SET, JointTranslationsSet, jointTranslationsSet, QVector<bool>, QVector<bool>());

View file

@ -202,22 +202,23 @@ enum EntityPropertyList {
// Model // Model
PROP_MODEL_URL = PROP_DERIVED_0, PROP_MODEL_URL = PROP_DERIVED_0,
PROP_JOINT_ROTATIONS_SET = PROP_DERIVED_1, PROP_MODEL_SCALE = PROP_DERIVED_1,
PROP_JOINT_ROTATIONS = PROP_DERIVED_2, PROP_JOINT_ROTATIONS_SET = PROP_DERIVED_2,
PROP_JOINT_TRANSLATIONS_SET = PROP_DERIVED_3, PROP_JOINT_ROTATIONS = PROP_DERIVED_3,
PROP_JOINT_TRANSLATIONS = PROP_DERIVED_4, PROP_JOINT_TRANSLATIONS_SET = PROP_DERIVED_4,
PROP_RELAY_PARENT_JOINTS = PROP_DERIVED_5, PROP_JOINT_TRANSLATIONS = PROP_DERIVED_5,
PROP_GROUP_CULLED = PROP_DERIVED_6, PROP_RELAY_PARENT_JOINTS = PROP_DERIVED_6,
PROP_GROUP_CULLED = PROP_DERIVED_7,
// Animation // Animation
PROP_ANIMATION_URL = PROP_DERIVED_7, PROP_ANIMATION_URL = PROP_DERIVED_8,
PROP_ANIMATION_ALLOW_TRANSLATION = PROP_DERIVED_8, PROP_ANIMATION_ALLOW_TRANSLATION = PROP_DERIVED_9,
PROP_ANIMATION_FPS = PROP_DERIVED_9, PROP_ANIMATION_FPS = PROP_DERIVED_10,
PROP_ANIMATION_FRAME_INDEX = PROP_DERIVED_10, PROP_ANIMATION_FRAME_INDEX = PROP_DERIVED_11,
PROP_ANIMATION_PLAYING = PROP_DERIVED_11, PROP_ANIMATION_PLAYING = PROP_DERIVED_12,
PROP_ANIMATION_LOOP = PROP_DERIVED_12, PROP_ANIMATION_LOOP = PROP_DERIVED_13,
PROP_ANIMATION_FIRST_FRAME = PROP_DERIVED_13, PROP_ANIMATION_FIRST_FRAME = PROP_DERIVED_14,
PROP_ANIMATION_LAST_FRAME = PROP_DERIVED_14, PROP_ANIMATION_LAST_FRAME = PROP_DERIVED_15,
PROP_ANIMATION_HOLD = PROP_DERIVED_15, PROP_ANIMATION_HOLD = PROP_DERIVED_16,
// Light // Light
PROP_IS_SPOTLIGHT = PROP_DERIVED_0, PROP_IS_SPOTLIGHT = PROP_DERIVED_0,

View file

@ -159,7 +159,7 @@ bool ImageEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
glm::vec2 xyDimensions(dimensions.x, dimensions.y); glm::vec2 xyDimensions(dimensions.x, dimensions.y);
glm::quat rotation = getWorldOrientation(); glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode); rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode, EntityItem::getPrimaryViewFrustumPosition());
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) { if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
glm::vec3 forward = rotation * Vectors::FRONT; glm::vec3 forward = rotation * Vectors::FRONT;

View file

@ -63,6 +63,7 @@ EntityItemProperties ModelEntityItem::getProperties(const EntityPropertyFlags& d
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures); COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelURL, getModelURL); COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelURL, getModelURL);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelScale, getModelScale);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointRotationsSet, getJointRotationsSet); COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointRotationsSet, getJointRotationsSet);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointRotations, getJointRotations); COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointRotations, getJointRotations);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointTranslationsSet, getJointTranslationsSet); COPY_ENTITY_PROPERTY_TO_PROPERTIES(jointTranslationsSet, getJointTranslationsSet);
@ -85,6 +86,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) {
SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures); SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelURL, setModelURL); SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelURL, setModelURL);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelScale, setModelScale);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointRotationsSet, setJointRotationsSet); SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointRotationsSet, setJointRotationsSet);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointRotations, setJointRotations); SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointRotations, setJointRotations);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointTranslationsSet, setJointTranslationsSet); SET_ENTITY_PROPERTY_FROM_PROPERTIES(jointTranslationsSet, setJointTranslationsSet);
@ -128,6 +130,7 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures); READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures);
READ_ENTITY_PROPERTY(PROP_MODEL_URL, QString, setModelURL); READ_ENTITY_PROPERTY(PROP_MODEL_URL, QString, setModelURL);
READ_ENTITY_PROPERTY(PROP_MODEL_SCALE, glm::vec3, setModelScale);
READ_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, QVector<bool>, setJointRotationsSet); READ_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, QVector<bool>, setJointRotationsSet);
READ_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, QVector<glm::quat>, setJointRotations); READ_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, QVector<glm::quat>, setJointRotations);
READ_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, QVector<bool>, setJointTranslationsSet); READ_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, QVector<bool>, setJointTranslationsSet);
@ -165,6 +168,7 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams&
requestedProperties += PROP_TEXTURES; requestedProperties += PROP_TEXTURES;
requestedProperties += PROP_MODEL_URL; requestedProperties += PROP_MODEL_URL;
requestedProperties += PROP_MODEL_SCALE;
requestedProperties += PROP_JOINT_ROTATIONS_SET; requestedProperties += PROP_JOINT_ROTATIONS_SET;
requestedProperties += PROP_JOINT_ROTATIONS; requestedProperties += PROP_JOINT_ROTATIONS;
requestedProperties += PROP_JOINT_TRANSLATIONS_SET; requestedProperties += PROP_JOINT_TRANSLATIONS_SET;
@ -192,6 +196,7 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures()); APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures());
APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, getModelURL()); APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, getModelURL());
APPEND_ENTITY_PROPERTY(PROP_MODEL_SCALE, getModelScale());
APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, getJointRotationsSet()); APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS_SET, getJointRotationsSet());
APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, getJointRotations()); APPEND_ENTITY_PROPERTY(PROP_JOINT_ROTATIONS, getJointRotations());
APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, getJointTranslationsSet()); APPEND_ENTITY_PROPERTY(PROP_JOINT_TRANSLATIONS_SET, getJointTranslationsSet());
@ -708,3 +713,15 @@ bool ModelEntityItem::applyNewAnimationProperties(AnimationPropertyGroup newProp
} }
return somethingChanged; return somethingChanged;
} }
glm::vec3 ModelEntityItem::getModelScale() const {
return _modelScaleLock.resultWithReadLock<glm::vec3>([&] {
return getSNScale();
});
}
void ModelEntityItem::setModelScale(const glm::vec3& modelScale) {
_modelScaleLock.withWriteLock([&] {
setSNScale(modelScale);
});
}

View file

@ -126,6 +126,9 @@ public:
QVector<glm::vec3> getJointTranslations() const; QVector<glm::vec3> getJointTranslations() const;
QVector<bool> getJointTranslationsSet() const; QVector<bool> getJointTranslationsSet() const;
glm::vec3 getModelScale() const;
void setModelScale(const glm::vec3& modelScale);
private: private:
void setAnimationSettings(const QString& value); // only called for old bitstream format void setAnimationSettings(const QString& value); // only called for old bitstream format
bool applyNewAnimationProperties(AnimationPropertyGroup newProperties); bool applyNewAnimationProperties(AnimationPropertyGroup newProperties);
@ -141,6 +144,7 @@ protected:
// they aren't currently updated from data in the model/rig, and they don't have a direct effect // they aren't currently updated from data in the model/rig, and they don't have a direct effect
// on what's rendered. // on what's rendered.
ReadWriteLockable _jointDataLock; ReadWriteLockable _jointDataLock;
ReadWriteLockable _modelScaleLock;
bool _jointRotationsExplicitlySet { false }; // were the joints set as a property or just side effect of animations bool _jointRotationsExplicitlySet { false }; // were the joints set as a property or just side effect of animations
bool _jointTranslationsExplicitlySet{ false }; // were the joints set as a property or just side effect of animations bool _jointTranslationsExplicitlySet{ false }; // were the joints set as a property or just side effect of animations

View file

@ -55,13 +55,11 @@ void MovingEntitiesOperator::addEntityToMoveList(EntityItemPointer entity, const
qCDebug(entities) << " oldContainingElement->bestFitBounds(newCubeClamped):" qCDebug(entities) << " oldContainingElement->bestFitBounds(newCubeClamped):"
<< oldContainingElement->bestFitBounds(newCubeClamped); << oldContainingElement->bestFitBounds(newCubeClamped);
} else { } else {
qCDebug(entities) << " WARNING NO OLD CONTAINING ELEMENT!!!"; qCDebug(entities) << " WARNING NO OLD CONTAINING ELEMENT for entity" << entity->getEntityItemID();
} }
} }
if (!oldContainingElement) { if (!oldContainingElement) {
qCDebug(entities) << "UNEXPECTED!!!! attempting to move entity "<< entity->getEntityItemID()
<< "that has no containing element. ";
return; // bail without adding. return; // bail without adding.
} }

View file

@ -199,7 +199,7 @@ bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const
glm::vec2 xyDimensions(dimensions.x, dimensions.y); glm::vec2 xyDimensions(dimensions.x, dimensions.y);
glm::quat rotation = getWorldOrientation(); glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode); rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode, EntityItem::getPrimaryViewFrustumPosition());
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) { if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
glm::vec3 forward = rotation * Vectors::FRONT; glm::vec3 forward = rotation * Vectors::FRONT;

View file

@ -180,7 +180,7 @@ bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const g
glm::vec2 xyDimensions(dimensions.x, dimensions.y); glm::vec2 xyDimensions(dimensions.x, dimensions.y);
glm::quat rotation = getWorldOrientation(); glm::quat rotation = getWorldOrientation();
glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()));
rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode); rotation = EntityItem::getBillboardRotation(position, rotation, _billboardMode, EntityItem::getPrimaryViewFrustumPosition());
if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) { if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) {
glm::vec3 forward = rotation * Vectors::FRONT; glm::vec3 forward = rotation * Vectors::FRONT;

View file

@ -456,11 +456,11 @@ public:
graphics::MaterialKey getMaterialKey() const { return graphics::MaterialKey(_schemaBuffer.get<graphics::MultiMaterial::Schema>()._key); } graphics::MaterialKey getMaterialKey() const { return graphics::MaterialKey(_schemaBuffer.get<graphics::MultiMaterial::Schema>()._key); }
const gpu::TextureTablePointer& getTextureTable() const { return _textureTable; } const gpu::TextureTablePointer& getTextureTable() const { return _textureTable; }
bool needsUpdate() const { return _needsUpdate; }
void setNeedsUpdate(bool needsUpdate) { _needsUpdate = needsUpdate; } void setNeedsUpdate(bool needsUpdate) { _needsUpdate = needsUpdate; }
void setTexturesLoading(bool value) { _texturesLoading = value; } void setTexturesLoading(bool value) { _texturesLoading = value; }
bool areTexturesLoading() const { return _texturesLoading; } void setInitialized() { _initialized = true; }
bool shouldUpdate() const { return !_initialized || _needsUpdate || _texturesLoading; }
int getTextureCount() const { calculateMaterialInfo(); return _textureCount; } int getTextureCount() const { calculateMaterialInfo(); return _textureCount; }
size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; } size_t getTextureSize() const { calculateMaterialInfo(); return _textureSize; }
@ -471,6 +471,7 @@ private:
gpu::TextureTablePointer _textureTable { std::make_shared<gpu::TextureTable>() }; gpu::TextureTablePointer _textureTable { std::make_shared<gpu::TextureTable>() };
bool _needsUpdate { false }; bool _needsUpdate { false };
bool _texturesLoading { false }; bool _texturesLoading { false };
bool _initialized { false };
mutable size_t _textureSize { 0 }; mutable size_t _textureSize { 0 };
mutable int _textureCount { 0 }; mutable int _textureCount { 0 };

View file

@ -315,9 +315,11 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
// wasn't an address - lookup the place name // wasn't an address - lookup the place name
// we may have a path that defines a relative viewpoint - pass that through the lookup so we can go to it after // we may have a path that defines a relative viewpoint - pass that through the lookup so we can go to it after
if (!lookupUrl.host().isNull() && !lookupUrl.host().isEmpty()) {
attemptPlaceNameLookup(lookupUrl.host(), lookupUrl.path(), trigger); attemptPlaceNameLookup(lookupUrl.host(), lookupUrl.path(), trigger);
} }
} }
}
return true; return true;

View file

@ -645,6 +645,7 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket, const HifiSockAddr& publicSocket, const HifiSockAddr& localSocket,
Node::LocalID localID, bool isReplicated, bool isUpstream, Node::LocalID localID, bool isReplicated, bool isUpstream,
const QUuid& connectionSecret, const NodePermissions& permissions) { const QUuid& connectionSecret, const NodePermissions& permissions) {
{
QReadLocker readLocker(&_nodeMutex); QReadLocker readLocker(&_nodeMutex);
NodeHash::const_iterator it = _nodeHash.find(uuid); NodeHash::const_iterator it = _nodeHash.find(uuid);
@ -660,7 +661,26 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
matchingNode->setLocalID(localID); matchingNode->setLocalID(localID);
return matchingNode; return matchingNode;
} else { }
}
auto removeOldNode = [&](auto node) {
if (node) {
QWriteLocker writeLocker(&_nodeMutex);
_localIDMap.unsafe_erase(node->getLocalID());
_nodeHash.unsafe_erase(node->getUUID());
handleNodeKill(node);
}
};
// if this is a solo node type, we assume that the DS has replaced its assignment and we should kill the previous node
if (SOLO_NODE_TYPES.count(nodeType)) {
removeOldNode(soloNodeOfType(nodeType));
}
// If there is a new node with the same socket, this is a reconnection, kill the old node
removeOldNode(findNodeWithAddr(publicSocket));
removeOldNode(findNodeWithAddr(localSocket));
auto it = _connectionIDs.find(uuid); auto it = _connectionIDs.find(uuid);
if (it == _connectionIDs.end()) { if (it == _connectionIDs.end()) {
_connectionIDs[uuid] = INITIAL_CONNECTION_ID; _connectionIDs[uuid] = INITIAL_CONNECTION_ID;
@ -683,40 +703,13 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
SharedNodePointer newNodePointer(newNode, &QObject::deleteLater); SharedNodePointer newNodePointer(newNode, &QObject::deleteLater);
// if this is a solo node type, we assume that the DS has replaced its assignment and we should kill the previous node
if (SOLO_NODE_TYPES.count(newNode->getType())) {
// while we still have the read lock, see if there is a previous solo node we'll need to remove
auto previousSoloIt = std::find_if(_nodeHash.cbegin(), _nodeHash.cend(), [newNode](const UUIDNodePair& nodePair){
return nodePair.second->getType() == newNode->getType();
});
if (previousSoloIt != _nodeHash.cend()) {
// we have a previous solo node, switch to a write lock so we can remove it
readLocker.unlock();
QWriteLocker writeLocker(&_nodeMutex);
auto oldSoloNode = previousSoloIt->second;
_localIDMap.unsafe_erase(oldSoloNode->getLocalID());
_nodeHash.unsafe_erase(previousSoloIt);
handleNodeKill(oldSoloNode);
// convert the current lock back to a read lock for insertion of new node
writeLocker.unlock();
readLocker.relock();
}
}
{
QReadLocker readLocker(&_nodeMutex);
// insert the new node and release our read lock // insert the new node and release our read lock
#if defined(Q_OS_ANDROID) || (defined(__clang__) && defined(Q_OS_LINUX)) _nodeHash.insert({ newNode->getUUID(), newNodePointer });
_nodeHash.insert(UUIDNodePair(newNode->getUUID(), newNodePointer)); _localIDMap.insert({ localID, newNodePointer });
_localIDMap.insert(std::pair<Node::LocalID, SharedNodePointer>(localID, newNodePointer)); }
#else
_nodeHash.emplace(newNode->getUUID(), newNodePointer);
_localIDMap.emplace(localID, newNodePointer);
#endif
readLocker.unlock();
qCDebug(networking) << "Added" << *newNode; qCDebug(networking) << "Added" << *newNode;
@ -741,7 +734,6 @@ SharedNodePointer LimitedNodeList::addOrUpdateNode(const QUuid& uuid, NodeType_t
}); });
return newNodePointer; return newNodePointer;
}
} }
std::unique_ptr<NLPacket> LimitedNodeList::constructPingPacket(const QUuid& nodeId, PingType_t pingType) { std::unique_ptr<NLPacket> LimitedNodeList::constructPingPacket(const QUuid& nodeId, PingType_t pingType) {

View file

@ -262,6 +262,7 @@ enum class EntityVersion : PacketVersion {
RingGizmoEntities, RingGizmoEntities,
ShowKeyboardFocusHighlight, ShowKeyboardFocusHighlight,
WebBillboardMode, WebBillboardMode,
ModelScale,
// Add new versions above here // Add new versions above here
NUM_PACKET_TYPE, NUM_PACKET_TYPE,

View file

@ -781,18 +781,18 @@ void CharacterController::updateState() {
const float jumpSpeed = sqrtf(2.0f * -DEFAULT_AVATAR_GRAVITY * jumpHeight); const float jumpSpeed = sqrtf(2.0f * -DEFAULT_AVATAR_GRAVITY * jumpHeight);
if ((velocity.dot(_currentUp) <= (jumpSpeed / 2.0f)) && ((_floorDistance < FLY_TO_GROUND_THRESHOLD) || _hasSupport)) { if ((velocity.dot(_currentUp) <= (jumpSpeed / 2.0f)) && ((_floorDistance < FLY_TO_GROUND_THRESHOLD) || _hasSupport)) {
SET_STATE(State::Ground, "hit ground"); SET_STATE(State::Ground, "hit ground");
} else if (_flyingAllowed) { } else if (_zoneFlyingAllowed) {
btVector3 desiredVelocity = _targetVelocity; btVector3 desiredVelocity = _targetVelocity;
if (desiredVelocity.length2() < MIN_TARGET_SPEED_SQUARED) { if (desiredVelocity.length2() < MIN_TARGET_SPEED_SQUARED) {
desiredVelocity = btVector3(0.0f, 0.0f, 0.0f); desiredVelocity = btVector3(0.0f, 0.0f, 0.0f);
} }
bool vertTargetSpeedIsNonZero = desiredVelocity.dot(_currentUp) > MIN_TARGET_SPEED; bool vertTargetSpeedIsNonZero = desiredVelocity.dot(_currentUp) > MIN_TARGET_SPEED;
if ((jumpButtonHeld || vertTargetSpeedIsNonZero) && (_takeoffJumpButtonID != _jumpButtonDownCount)) { if (_comfortFlyingAllowed && (jumpButtonHeld || vertTargetSpeedIsNonZero) && (_takeoffJumpButtonID != _jumpButtonDownCount)) {
SET_STATE(State::Hover, "double jump button"); SET_STATE(State::Hover, "double jump button");
} else if ((jumpButtonHeld || vertTargetSpeedIsNonZero) && (now - _jumpButtonDownStartTime) > JUMP_TO_HOVER_PERIOD) { } else if (_comfortFlyingAllowed && (jumpButtonHeld || vertTargetSpeedIsNonZero) && (now - _jumpButtonDownStartTime) > JUMP_TO_HOVER_PERIOD) {
SET_STATE(State::Hover, "jump button held"); SET_STATE(State::Hover, "jump button held");
} else if (_floorDistance > _scaleFactor * DEFAULT_AVATAR_FALL_HEIGHT) { } else if ((!rayHasHit && !_hasSupport) || _floorDistance > _scaleFactor * DEFAULT_AVATAR_FALL_HEIGHT) {
// Transition to hover if we are above the fall threshold // Transition to hover if there's no ground beneath us or we are above the fall threshold, regardless of _comfortFlyingAllowed
SET_STATE(State::Hover, "above fall threshold"); SET_STATE(State::Hover, "above fall threshold");
} }
} }
@ -801,8 +801,10 @@ void CharacterController::updateState() {
case State::Hover: case State::Hover:
btScalar horizontalSpeed = (velocity - velocity.dot(_currentUp) * _currentUp).length(); btScalar horizontalSpeed = (velocity - velocity.dot(_currentUp) * _currentUp).length();
bool flyingFast = horizontalSpeed > (MAX_WALKING_SPEED * 0.75f); bool flyingFast = horizontalSpeed > (MAX_WALKING_SPEED * 0.75f);
if (!_flyingAllowed) { if (!_zoneFlyingAllowed) {
SET_STATE(State::InAir, "flying not allowed"); SET_STATE(State::InAir, "zone flying not allowed");
} else if (!_comfortFlyingAllowed && (rayHasHit || _hasSupport || _floorDistance < FLY_TO_GROUND_THRESHOLD)) {
SET_STATE(State::InAir, "comfort flying not allowed");
} else if ((_floorDistance < MIN_HOVER_HEIGHT) && !jumpButtonHeld && !flyingFast) { } else if ((_floorDistance < MIN_HOVER_HEIGHT) && !jumpButtonHeld && !flyingFast) {
SET_STATE(State::InAir, "near ground"); SET_STATE(State::InAir, "near ground");
} else if (((_floorDistance < FLY_TO_GROUND_THRESHOLD) || _hasSupport) && !flyingFast) { } else if (((_floorDistance < FLY_TO_GROUND_THRESHOLD) || _hasSupport) && !flyingFast) {
@ -847,12 +849,6 @@ bool CharacterController::getRigidBodyLocation(glm::vec3& avatarRigidBodyPositio
return true; return true;
} }
void CharacterController::setFlyingAllowed(bool value) {
if (value != _flyingAllowed) {
_flyingAllowed = value;
}
}
void CharacterController::setCollisionlessAllowed(bool value) { void CharacterController::setCollisionlessAllowed(bool value) {
if (value != _collisionlessAllowed) { if (value != _collisionlessAllowed) {
_collisionlessAllowed = value; _collisionlessAllowed = value;

View file

@ -65,10 +65,10 @@ public:
// overrides from btCharacterControllerInterface // overrides from btCharacterControllerInterface
virtual void setWalkDirection(const btVector3 &walkDirection) override { assert(false); } virtual void setWalkDirection(const btVector3 &walkDirection) override { assert(false); }
virtual void setVelocityForTimeInterval(const btVector3 &velocity, btScalar timeInterval) override { assert(false); } virtual void setVelocityForTimeInterval(const btVector3 &velocity, btScalar timeInterval) override { assert(false); }
virtual void reset(btCollisionWorld* collisionWorld) override { } virtual void reset(btCollisionWorld* collisionWorld) override {}
virtual void warp(const btVector3& origin) override { } virtual void warp(const btVector3& origin) override {}
virtual void debugDraw(btIDebugDraw* debugDrawer) override { } virtual void debugDraw(btIDebugDraw* debugDrawer) override {}
virtual void setUpInterpolate(bool value) override { } virtual void setUpInterpolate(bool value) override {}
virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTime) override; virtual void updateAction(btCollisionWorld* collisionWorld, btScalar deltaTime) override;
virtual void preStep(btCollisionWorld *collisionWorld) override; virtual void preStep(btCollisionWorld *collisionWorld) override;
virtual void playerStep(btCollisionWorld *collisionWorld, btScalar dt) override; virtual void playerStep(btCollisionWorld *collisionWorld, btScalar dt) override;
@ -90,7 +90,7 @@ public:
void preSimulation(); void preSimulation();
void postSimulation(); void postSimulation();
void setPositionAndOrientation( const glm::vec3& position, const glm::quat& orientation); void setPositionAndOrientation(const glm::vec3& position, const glm::quat& orientation);
void getPositionAndOrientation(glm::vec3& position, glm::quat& rotation) const; void getPositionAndOrientation(glm::vec3& position, glm::quat& rotation) const;
void setParentVelocity(const glm::vec3& parentVelocity); void setParentVelocity(const glm::vec3& parentVelocity);
@ -129,7 +129,8 @@ public:
bool getRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation); bool getRigidBodyLocation(glm::vec3& avatarRigidBodyPosition, glm::quat& avatarRigidBodyRotation);
void setFlyingAllowed(bool value); void setZoneFlyingAllowed(bool value) { _zoneFlyingAllowed = value; }
void setComfortFlyingAllowed(bool value) { _comfortFlyingAllowed = value; }
void setCollisionlessAllowed(bool value); void setCollisionlessAllowed(bool value);
void setPendingFlagsUpdateCollisionMask(){ _pendingFlags |= PENDING_FLAG_UPDATE_COLLISION_MASK; } void setPendingFlagsUpdateCollisionMask(){ _pendingFlags |= PENDING_FLAG_UPDATE_COLLISION_MASK; }
@ -212,7 +213,8 @@ protected:
uint32_t _pendingFlags { 0 }; uint32_t _pendingFlags { 0 };
uint32_t _previousFlags { 0 }; uint32_t _previousFlags { 0 };
bool _flyingAllowed { true }; bool _zoneFlyingAllowed { true };
bool _comfortFlyingAllowed { true };
bool _collisionlessAllowed { true }; bool _collisionlessAllowed { true };
bool _collisionless { false }; bool _collisionless { false };

View file

@ -178,6 +178,7 @@ void CauterizedModel::updateClusterMatrices() {
} }
} }
} }
computeMeshPartLocalBounds();
// post the blender if we're not currently waiting for one to finish // post the blender if we're not currently waiting for one to finish
auto modelBlender = DependencyManager::get<ModelBlender>(); auto modelBlender = DependencyManager::get<ModelBlender>();

View file

@ -83,7 +83,7 @@ void MeshPartPayload::updateKey(const render::ItemKey& key) {
ItemKey::Builder builder(key); ItemKey::Builder builder(key);
builder.withTypeShape(); builder.withTypeShape();
if (_drawMaterials.needsUpdate() || _drawMaterials.areTexturesLoading()) { if (_drawMaterials.shouldUpdate()) {
RenderPipelines::updateMultiMaterial(_drawMaterials); RenderPipelines::updateMultiMaterial(_drawMaterials);
} }
@ -329,7 +329,7 @@ void ModelMeshPartPayload::updateKey(const render::ItemKey& key) {
builder.withDeformed(); builder.withDeformed();
} }
if (_drawMaterials.needsUpdate() || _drawMaterials.areTexturesLoading()) { if (_drawMaterials.shouldUpdate()) {
RenderPipelines::updateMultiMaterial(_drawMaterials); RenderPipelines::updateMultiMaterial(_drawMaterials);
} }
@ -347,7 +347,7 @@ void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, PrimitiveMode pr
return; return;
} }
if (_drawMaterials.needsUpdate() || _drawMaterials.areTexturesLoading()) { if (_drawMaterials.shouldUpdate()) {
RenderPipelines::updateMultiMaterial(_drawMaterials); RenderPipelines::updateMultiMaterial(_drawMaterials);
} }

View file

@ -1169,6 +1169,7 @@ void Model::setURL(const QUrl& url) {
resource->setLoadPriority(this, _loadingPriority); resource->setLoadPriority(this, _loadingPriority);
_renderWatcher.setResource(resource); _renderWatcher.setResource(resource);
} }
_rig.initFlow(false);
onInvalidate(); onInvalidate();
} }
@ -1385,6 +1386,7 @@ void Model::updateClusterMatrices() {
} }
} }
} }
computeMeshPartLocalBounds();
// post the blender if we're not currently waiting for one to finish // post the blender if we're not currently waiting for one to finish
auto modelBlender = DependencyManager::get<ModelBlender>(); auto modelBlender = DependencyManager::get<ModelBlender>();

View file

@ -382,11 +382,6 @@ void RenderPipelines::bindMaterial(graphics::MaterialPointer& material, gpu::Bat
void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial) { void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial) {
auto& schemaBuffer = multiMaterial.getSchemaBuffer(); auto& schemaBuffer = multiMaterial.getSchemaBuffer();
if (multiMaterial.size() == 0) {
schemaBuffer.edit<graphics::MultiMaterial::Schema>() = graphics::MultiMaterial::Schema();
return;
}
auto& drawMaterialTextures = multiMaterial.getTextureTable(); auto& drawMaterialTextures = multiMaterial.getTextureTable();
multiMaterial.setTexturesLoading(false); multiMaterial.setTexturesLoading(false);
@ -732,14 +727,11 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial
schema._key = (uint32_t)schemaKey._flags.to_ulong(); schema._key = (uint32_t)schemaKey._flags.to_ulong();
schemaBuffer.edit<graphics::MultiMaterial::Schema>() = schema; schemaBuffer.edit<graphics::MultiMaterial::Schema>() = schema;
multiMaterial.setNeedsUpdate(false); multiMaterial.setNeedsUpdate(false);
multiMaterial.setInitialized();
} }
void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu::Batch& batch, bool enableTextures) { void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu::Batch& batch, bool enableTextures) {
if (multiMaterial.size() == 0) { if (multiMaterial.shouldUpdate()) {
return;
}
if (multiMaterial.needsUpdate() || multiMaterial.areTexturesLoading()) {
updateMultiMaterial(multiMaterial); updateMultiMaterial(multiMaterial);
} }

View file

@ -861,7 +861,7 @@ void SpatiallyNestable::setSNScale(const glm::vec3& scale, bool& success) {
} }
}); });
if (success && changed) { if (success && changed) {
locationChanged(); dimensionsChanged();
} }
} }
@ -1420,11 +1420,16 @@ QUuid SpatiallyNestable::getEditSenderID() {
return editSenderID; return editSenderID;
} }
void SpatiallyNestable::bumpAncestorChainRenderableVersion() const { void SpatiallyNestable::bumpAncestorChainRenderableVersion(int depth) const {
if (depth > MAX_PARENTING_CHAIN_SIZE) {
// can't break the parent chain here, because it will call setParentID, which calls this
return;
}
_ancestorChainRenderableVersion++; _ancestorChainRenderableVersion++;
bool success = false; bool success = false;
auto parent = getParentPointer(success); auto parent = getParentPointer(success);
if (success && parent) { if (success && parent) {
parent->bumpAncestorChainRenderableVersion(); parent->bumpAncestorChainRenderableVersion(depth + 1);
} }
} }

View file

@ -221,7 +221,7 @@ public:
bool hasGrabs(); bool hasGrabs();
virtual QUuid getEditSenderID(); virtual QUuid getEditSenderID();
void bumpAncestorChainRenderableVersion() const; void bumpAncestorChainRenderableVersion(int depth = 0) const;
protected: protected:
QUuid _id; QUuid _id;

View file

@ -325,6 +325,11 @@
leftMargin: domainNameLeftMargin leftMargin: domainNameLeftMargin
}; };
// check to be sure we are going to look for an actual domain
if (!domain) {
doRequest = false;
}
if (doRequest) { if (doRequest) {
var url = Account.metaverseServerURL + '/api/v1/places/' + domain; var url = Account.metaverseServerURL + '/api/v1/places/' + domain;
request({ request({

View file

@ -708,7 +708,7 @@ SelectionDisplay = (function() {
shape: "Cone", shape: "Cone",
solid: true, solid: true,
visible: false, visible: false,
ignoreRayIntersection: false, ignorePickIntersection: true,
drawInFront: true drawInFront: true
}; };
var handlePropertiesTranslateArrowCylinders = { var handlePropertiesTranslateArrowCylinders = {
@ -716,7 +716,7 @@ SelectionDisplay = (function() {
shape: "Cylinder", shape: "Cylinder",
solid: true, solid: true,
visible: false, visible: false,
ignoreRayIntersection: false, ignorePickIntersection: true,
drawInFront: true drawInFront: true
}; };
var handleTranslateXCone = Overlays.addOverlay("shape", handlePropertiesTranslateArrowCones); var handleTranslateXCone = Overlays.addOverlay("shape", handlePropertiesTranslateArrowCones);
@ -741,7 +741,7 @@ SelectionDisplay = (function() {
majorTickMarksAngle: ROTATE_DEFAULT_TICK_MARKS_ANGLE, majorTickMarksAngle: ROTATE_DEFAULT_TICK_MARKS_ANGLE,
majorTickMarksLength: 0.1, majorTickMarksLength: 0.1,
visible: false, visible: false,
ignoreRayIntersection: false, ignorePickIntersection: true,
drawInFront: true drawInFront: true
}; };
var handleRotatePitchRing = Overlays.addOverlay("circle3d", handlePropertiesRotateRings); var handleRotatePitchRing = Overlays.addOverlay("circle3d", handlePropertiesRotateRings);
@ -766,7 +766,7 @@ SelectionDisplay = (function() {
solid: true, solid: true,
innerRadius: 0.9, innerRadius: 0.9,
visible: false, visible: false,
ignoreRayIntersection: true, ignorePickIntersection: true,
drawInFront: true drawInFront: true
}); });
@ -779,7 +779,7 @@ SelectionDisplay = (function() {
visible: false, visible: false,
isFacingAvatar: true, isFacingAvatar: true,
drawInFront: true, drawInFront: true,
ignoreRayIntersection: true, ignorePickIntersection: true,
dimensions: { x: 0, y: 0 }, dimensions: { x: 0, y: 0 },
lineHeight: 0.0, lineHeight: 0.0,
topMargin: 0, topMargin: 0,
@ -791,7 +791,7 @@ SelectionDisplay = (function() {
var handlePropertiesStretchCubes = { var handlePropertiesStretchCubes = {
solid: true, solid: true,
visible: false, visible: false,
ignoreRayIntersection: false, ignorePickIntersection: true,
drawInFront: true drawInFront: true
}; };
var handleStretchXCube = Overlays.addOverlay("cube", handlePropertiesStretchCubes); var handleStretchXCube = Overlays.addOverlay("cube", handlePropertiesStretchCubes);
@ -802,18 +802,17 @@ SelectionDisplay = (function() {
Overlays.editOverlay(handleStretchZCube, { color: COLOR_BLUE }); Overlays.editOverlay(handleStretchZCube, { color: COLOR_BLUE });
var handlePropertiesStretchPanel = { var handlePropertiesStretchPanel = {
shape: "Quad",
alpha: 0.5, alpha: 0.5,
solid: true, solid: true,
visible: false, visible: false,
ignoreRayIntersection: true, ignorePickIntersection: true,
drawInFront: true drawInFront: true
}; };
var handleStretchXPanel = Overlays.addOverlay("shape", handlePropertiesStretchPanel); var handleStretchXPanel = Overlays.addOverlay("cube", handlePropertiesStretchPanel);
Overlays.editOverlay(handleStretchXPanel, { color: COLOR_RED }); Overlays.editOverlay(handleStretchXPanel, { color: COLOR_RED });
var handleStretchYPanel = Overlays.addOverlay("shape", handlePropertiesStretchPanel); var handleStretchYPanel = Overlays.addOverlay("cube", handlePropertiesStretchPanel);
Overlays.editOverlay(handleStretchYPanel, { color: COLOR_GREEN }); Overlays.editOverlay(handleStretchYPanel, { color: COLOR_GREEN });
var handleStretchZPanel = Overlays.addOverlay("shape", handlePropertiesStretchPanel); var handleStretchZPanel = Overlays.addOverlay("cube", handlePropertiesStretchPanel);
Overlays.editOverlay(handleStretchZPanel, { color: COLOR_BLUE }); Overlays.editOverlay(handleStretchZPanel, { color: COLOR_BLUE });
var handleScaleCube = Overlays.addOverlay("cube", { var handleScaleCube = Overlays.addOverlay("cube", {
@ -821,7 +820,7 @@ SelectionDisplay = (function() {
color: COLOR_SCALE_CUBE, color: COLOR_SCALE_CUBE,
solid: true, solid: true,
visible: false, visible: false,
ignoreRayIntersection: false, ignorePickIntersection: true,
drawInFront: true, drawInFront: true,
borderSize: 1.4 borderSize: 1.4
}); });
@ -841,7 +840,7 @@ SelectionDisplay = (function() {
color: COLOR_GREEN, color: COLOR_GREEN,
solid: true, solid: true,
visible: false, visible: false,
ignoreRayIntersection: false, ignorePickIntersection: true,
drawInFront: true, drawInFront: true,
borderSize: 1.4 borderSize: 1.4
}); });
@ -854,6 +853,7 @@ SelectionDisplay = (function() {
alpha: 0, alpha: 0,
solid: false, solid: false,
visible: false, visible: false,
ignorePickIntersection: true,
dashed: false dashed: false
}); });
@ -865,6 +865,7 @@ SelectionDisplay = (function() {
alpha: 0, alpha: 0,
solid: false, solid: false,
visible: false, visible: false,
ignorePickIntersection: true,
dashed: false dashed: false
}); });
@ -877,7 +878,7 @@ SelectionDisplay = (function() {
green: 0, green: 0,
blue: 0 blue: 0
}, },
ignoreRayIntersection: true // always ignore this ignorePickIntersection: true // always ignore this
}); });
var yRailOverlay = Overlays.addOverlay("line3d", { var yRailOverlay = Overlays.addOverlay("line3d", {
visible: false, visible: false,
@ -888,7 +889,7 @@ SelectionDisplay = (function() {
green: 255, green: 255,
blue: 0 blue: 0
}, },
ignoreRayIntersection: true // always ignore this ignorePickIntersection: true // always ignore this
}); });
var zRailOverlay = Overlays.addOverlay("line3d", { var zRailOverlay = Overlays.addOverlay("line3d", {
visible: false, visible: false,
@ -899,7 +900,7 @@ SelectionDisplay = (function() {
green: 0, green: 0,
blue: 255 blue: 255
}, },
ignoreRayIntersection: true // always ignore this ignorePickIntersection: true // always ignore this
}); });
var allOverlays = [ var allOverlays = [
@ -972,7 +973,7 @@ SelectionDisplay = (function() {
color: COLOR_DEBUG_PICK_PLANE, color: COLOR_DEBUG_PICK_PLANE,
solid: true, solid: true,
visible: false, visible: false,
ignoreRayIntersection: true, ignorePickIntersection: true,
drawInFront: false drawInFront: false
}); });
var debugPickPlaneHits = []; var debugPickPlaneHits = [];
@ -1802,6 +1803,7 @@ SelectionDisplay = (function() {
isActiveTool(handleRotateYawRing) || isActiveTool(handleRotateYawRing) ||
isActiveTool(handleRotateRollRing); isActiveTool(handleRotateRollRing);
selectionBoxGeometry.visible = !inModeRotate && !isCameraInsideBox; selectionBoxGeometry.visible = !inModeRotate && !isCameraInsideBox;
selectionBoxGeometry.ignorePickIntersection = !selectionBoxGeometry.visible;
Overlays.editOverlay(selectionBox, selectionBoxGeometry); Overlays.editOverlay(selectionBox, selectionBoxGeometry);
// UPDATE ICON TRANSLATE HANDLE // UPDATE ICON TRANSLATE HANDLE
@ -1811,9 +1813,13 @@ SelectionDisplay = (function() {
rotation: rotation rotation: rotation
}; };
iconSelectionBoxGeometry.visible = !inModeRotate && isCameraInsideBox; iconSelectionBoxGeometry.visible = !inModeRotate && isCameraInsideBox;
iconSelectionBoxGeometry.ignorePickIntersection = !iconSelectionBoxGeometry.visible;
Overlays.editOverlay(iconSelectionBox, iconSelectionBoxGeometry); Overlays.editOverlay(iconSelectionBox, iconSelectionBoxGeometry);
} else { } else {
Overlays.editOverlay(iconSelectionBox, { visible: false }); Overlays.editOverlay(iconSelectionBox, {
visible: false,
ignorePickIntersection: true
});
} }
// UPDATE DUPLICATOR (CURRENTLY HIDDEN FOR NOW) // UPDATE DUPLICATOR (CURRENTLY HIDDEN FOR NOW)
@ -1882,7 +1888,7 @@ SelectionDisplay = (function() {
// FUNCTION: SET OVERLAYS VISIBLE // FUNCTION: SET OVERLAYS VISIBLE
that.setOverlaysVisible = function(isVisible) { that.setOverlaysVisible = function(isVisible) {
for (var i = 0, length = allOverlays.length; i < length; i++) { for (var i = 0, length = allOverlays.length; i < length; i++) {
Overlays.editOverlay(allOverlays[i], { visible: isVisible }); Overlays.editOverlay(allOverlays[i], { visible: isVisible, ignorePickIntersection: !isVisible });
} }
}; };
@ -1894,18 +1900,18 @@ SelectionDisplay = (function() {
}; };
that.setHandleTranslateXVisible = function(isVisible) { that.setHandleTranslateXVisible = function(isVisible) {
Overlays.editOverlay(handleTranslateXCone, { visible: isVisible }); Overlays.editOverlay(handleTranslateXCone, { visible: isVisible, ignorePickIntersection: !isVisible });
Overlays.editOverlay(handleTranslateXCylinder, { visible: isVisible }); Overlays.editOverlay(handleTranslateXCylinder, { visible: isVisible, ignorePickIntersection: !isVisible });
}; };
that.setHandleTranslateYVisible = function(isVisible) { that.setHandleTranslateYVisible = function(isVisible) {
Overlays.editOverlay(handleTranslateYCone, { visible: isVisible }); Overlays.editOverlay(handleTranslateYCone, { visible: isVisible, ignorePickIntersection: !isVisible });
Overlays.editOverlay(handleTranslateYCylinder, { visible: isVisible }); Overlays.editOverlay(handleTranslateYCylinder, { visible: isVisible, ignorePickIntersection: !isVisible });
}; };
that.setHandleTranslateZVisible = function(isVisible) { that.setHandleTranslateZVisible = function(isVisible) {
Overlays.editOverlay(handleTranslateZCone, { visible: isVisible }); Overlays.editOverlay(handleTranslateZCone, { visible: isVisible, ignorePickIntersection: !isVisible });
Overlays.editOverlay(handleTranslateZCylinder, { visible: isVisible }); Overlays.editOverlay(handleTranslateZCylinder, { visible: isVisible, ignorePickIntersection: !isVisible });
}; };
// FUNCTION: SET HANDLE ROTATE VISIBLE // FUNCTION: SET HANDLE ROTATE VISIBLE
@ -1916,15 +1922,15 @@ SelectionDisplay = (function() {
}; };
that.setHandleRotatePitchVisible = function(isVisible) { that.setHandleRotatePitchVisible = function(isVisible) {
Overlays.editOverlay(handleRotatePitchRing, { visible: isVisible }); Overlays.editOverlay(handleRotatePitchRing, { visible: isVisible, ignorePickIntersection: !isVisible });
}; };
that.setHandleRotateYawVisible = function(isVisible) { that.setHandleRotateYawVisible = function(isVisible) {
Overlays.editOverlay(handleRotateYawRing, { visible: isVisible }); Overlays.editOverlay(handleRotateYawRing, { visible: isVisible, ignorePickIntersection: !isVisible });
}; };
that.setHandleRotateRollVisible = function(isVisible) { that.setHandleRotateRollVisible = function(isVisible) {
Overlays.editOverlay(handleRotateRollRing, { visible: isVisible }); Overlays.editOverlay(handleRotateRollRing, { visible: isVisible, ignorePickIntersection: !isVisible });
}; };
// FUNCTION: SET HANDLE STRETCH VISIBLE // FUNCTION: SET HANDLE STRETCH VISIBLE
@ -1935,15 +1941,15 @@ SelectionDisplay = (function() {
}; };
that.setHandleStretchXVisible = function(isVisible) { that.setHandleStretchXVisible = function(isVisible) {
Overlays.editOverlay(handleStretchXCube, { visible: isVisible }); Overlays.editOverlay(handleStretchXCube, { visible: isVisible, ignorePickIntersection: !isVisible });
}; };
that.setHandleStretchYVisible = function(isVisible) { that.setHandleStretchYVisible = function(isVisible) {
Overlays.editOverlay(handleStretchYCube, { visible: isVisible }); Overlays.editOverlay(handleStretchYCube, { visible: isVisible, ignorePickIntersection: !isVisible });
}; };
that.setHandleStretchZVisible = function(isVisible) { that.setHandleStretchZVisible = function(isVisible) {
Overlays.editOverlay(handleStretchZCube, { visible: isVisible }); Overlays.editOverlay(handleStretchZCube, { visible: isVisible, ignorePickIntersection: !isVisible });
}; };
// FUNCTION: SET HANDLE SCALE VISIBLE // FUNCTION: SET HANDLE SCALE VISIBLE
@ -1953,16 +1959,16 @@ SelectionDisplay = (function() {
}; };
that.setHandleScaleVisible = function(isVisible) { that.setHandleScaleVisible = function(isVisible) {
Overlays.editOverlay(handleScaleCube, { visible: isVisible }); Overlays.editOverlay(handleScaleCube, { visible: isVisible, ignorePickIntersection: !isVisible });
}; };
that.setHandleBoundingBoxVisible = function(isVisible) { that.setHandleBoundingBoxVisible = function(isVisible) {
Overlays.editOverlay(handleBoundingBox, { visible: isVisible }); Overlays.editOverlay(handleBoundingBox, { visible: isVisible, ignorePickIntersection: true });
}; };
// FUNCTION: SET HANDLE DUPLICATOR VISIBLE // FUNCTION: SET HANDLE DUPLICATOR VISIBLE
that.setHandleDuplicatorVisible = function(isVisible) { that.setHandleDuplicatorVisible = function(isVisible) {
Overlays.editOverlay(handleDuplicator, { visible: isVisible }); Overlays.editOverlay(handleDuplicator, { visible: isVisible, ignorePickIntersection: !isVisible });
}; };
// FUNCTION: DEBUG PICK PLANE // FUNCTION: DEBUG PICK PLANE
@ -1986,7 +1992,7 @@ SelectionDisplay = (function() {
shape: "Sphere", shape: "Sphere",
solid: true, solid: true,
visible: true, visible: true,
ignoreRayIntersection: true, ignorePickIntersection: true,
drawInFront: false, drawInFront: false,
color: COLOR_DEBUG_PICK_PLANE_HIT, color: COLOR_DEBUG_PICK_PLANE_HIT,
position: pickHitPosition, position: pickHitPosition,
@ -2082,10 +2088,12 @@ SelectionDisplay = (function() {
pushCommandForSelections(duplicatedEntityIDs); pushCommandForSelections(duplicatedEntityIDs);
if (isConstrained) { if (isConstrained) {
Overlays.editOverlay(xRailOverlay, { Overlays.editOverlay(xRailOverlay, {
visible: false visible: false,
ignorePickIntersection: true
}); });
Overlays.editOverlay(zRailOverlay, { Overlays.editOverlay(zRailOverlay, {
visible: false visible: false,
ignorePickIntersection: true
}); });
} }
}, },
@ -2174,22 +2182,26 @@ SelectionDisplay = (function() {
Overlays.editOverlay(xRailOverlay, { Overlays.editOverlay(xRailOverlay, {
start: xStart, start: xStart,
end: xEnd, end: xEnd,
visible: true visible: true,
ignorePickIntersection: true
}); });
Overlays.editOverlay(zRailOverlay, { Overlays.editOverlay(zRailOverlay, {
start: zStart, start: zStart,
end: zEnd, end: zEnd,
visible: true visible: true,
ignorePickIntersection: true
}); });
isConstrained = true; isConstrained = true;
} }
} else { } else {
if (isConstrained) { if (isConstrained) {
Overlays.editOverlay(xRailOverlay, { Overlays.editOverlay(xRailOverlay, {
visible: false visible: false,
ignorePickIntersection: true
}); });
Overlays.editOverlay(zRailOverlay, { Overlays.editOverlay(zRailOverlay, {
visible: false visible: false,
ignorePickIntersection: true
}); });
isConstrained = false; isConstrained = false;
} }
@ -2460,7 +2472,7 @@ SelectionDisplay = (function() {
} }
if (stretchPanel !== null) { if (stretchPanel !== null) {
Overlays.editOverlay(stretchPanel, { visible: true }); Overlays.editOverlay(stretchPanel, { visible: true, ignorePickIntersection: false });
} }
var stretchCubePosition = Overlays.getProperty(handleStretchCube, "position"); var stretchCubePosition = Overlays.getProperty(handleStretchCube, "position");
var stretchPanelPosition = Overlays.getProperty(stretchPanel, "position"); var stretchPanelPosition = Overlays.getProperty(stretchPanel, "position");
@ -2481,7 +2493,7 @@ SelectionDisplay = (function() {
} }
if (stretchPanel !== null) { if (stretchPanel !== null) {
Overlays.editOverlay(stretchPanel, { visible: false }); Overlays.editOverlay(stretchPanel, { visible: false, ignorePickIntersection: true });
} }
activeStretchCubePanelOffset = null; activeStretchCubePanelOffset = null;
@ -2775,7 +2787,8 @@ SelectionDisplay = (function() {
rotation: worldRotation, rotation: worldRotation,
startAt: 0, startAt: 0,
endAt: 0, endAt: 0,
visible: true visible: true,
ignorePickIntersection: false
}); });
// editOverlays may not have committed rotation changes. // editOverlays may not have committed rotation changes.
@ -2805,13 +2818,13 @@ SelectionDisplay = (function() {
if (wantDebug) { if (wantDebug) {
print("================== " + getMode() + "(addHandleRotateTool onEnd) -> ======================="); print("================== " + getMode() + "(addHandleRotateTool onEnd) -> =======================");
} }
Overlays.editOverlay(rotationDegreesDisplay, { visible: false }); Overlays.editOverlay(rotationDegreesDisplay, { visible: false, ignorePickIntersection: true });
Overlays.editOverlay(selectedHandle, { Overlays.editOverlay(selectedHandle, {
hasTickMarks: false, hasTickMarks: false,
solid: true, solid: true,
innerRadius: ROTATE_RING_IDLE_INNER_RADIUS innerRadius: ROTATE_RING_IDLE_INNER_RADIUS
}); });
Overlays.editOverlay(handleRotateCurrentRing, { visible: false }); Overlays.editOverlay(handleRotateCurrentRing, { visible: false, ignorePickIntersection: true });
pushCommandForSelections(); pushCommandForSelections();
if (wantDebug) { if (wantDebug) {
print("================== " + getMode() + "(addHandleRotateTool onEnd) <- ======================="); print("================== " + getMode() + "(addHandleRotateTool onEnd) <- =======================");