mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-05 23:54:50 +02:00
Merge pull request #6093 from sethalves/hold-action-changes
Hold action changes
This commit is contained in:
commit
341bc3666f
23 changed files with 355 additions and 369 deletions
|
@ -34,18 +34,18 @@ var NO_INTERSECT_COLOR = { red: 10, green: 10, blue: 255}; // line color when pi
|
||||||
var INTERSECT_COLOR = { red: 250, green: 10, blue: 10}; // line color when pick hits
|
var INTERSECT_COLOR = { red: 250, green: 10, blue: 10}; // line color when pick hits
|
||||||
var LINE_ENTITY_DIMENSIONS = { x: 1000, y: 1000,z: 1000};
|
var LINE_ENTITY_DIMENSIONS = { x: 1000, y: 1000,z: 1000};
|
||||||
var LINE_LENGTH = 500;
|
var LINE_LENGTH = 500;
|
||||||
|
var PICK_MAX_DISTANCE = 500; // max length of pick-ray
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// near grabbing
|
// near grabbing
|
||||||
//
|
//
|
||||||
|
|
||||||
var GRAB_RADIUS = 0.3; // if the ray misses but an object is this close, it will still be selected
|
|
||||||
var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position
|
var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position
|
||||||
var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable.
|
var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable.
|
||||||
var NEAR_PICK_MAX_DISTANCE = 0.6; // max length of pick-ray for close grabbing to be selected
|
var NEAR_PICK_MAX_DISTANCE = 0.2; // max length of pick-ray for close grabbing to be selected
|
||||||
var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things
|
var RELEASE_VELOCITY_MULTIPLIER = 1.5; // affects throwing things
|
||||||
|
var PICK_BACKOFF_DISTANCE = 0.1; // helps when hand is intersecting the grabble object
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
|
@ -256,12 +256,18 @@ function MyController(hand, triggerAction) {
|
||||||
|
|
||||||
// the trigger is being pressed, do a ray test
|
// the trigger is being pressed, do a ray test
|
||||||
var handPosition = this.getHandPosition();
|
var handPosition = this.getHandPosition();
|
||||||
var pickRay = {
|
var distantPickRay = {
|
||||||
origin: handPosition,
|
origin: handPosition,
|
||||||
direction: Quat.getUp(this.getHandRotation())
|
direction: Quat.getUp(this.getHandRotation()),
|
||||||
|
length: PICK_MAX_DISTANCE
|
||||||
|
};
|
||||||
|
var palmPickRay = {
|
||||||
|
origin: handPosition,
|
||||||
|
direction: Quat.getFront(this.getHandRotation()),
|
||||||
|
length: NEAR_PICK_MAX_DISTANCE
|
||||||
};
|
};
|
||||||
|
|
||||||
this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
|
this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
|
||||||
|
|
||||||
// don't pick 60x per second. do this check after updating the line so it's not jumpy.
|
// don't pick 60x per second. do this check after updating the line so it's not jumpy.
|
||||||
var now = Date.now();
|
var now = Date.now();
|
||||||
|
@ -270,67 +276,54 @@ function MyController(hand, triggerAction) {
|
||||||
}
|
}
|
||||||
this.lastPickTime = now;
|
this.lastPickTime = now;
|
||||||
|
|
||||||
var intersection = Entities.findRayIntersection(pickRay, true);
|
var pickRays = [distantPickRay, palmPickRay];
|
||||||
if (intersection.intersects && intersection.properties.locked === 0) {
|
for (var index=0; index < pickRays.length; ++index) {
|
||||||
// the ray is intersecting something we can move.
|
var pickRay = pickRays[index];
|
||||||
var handControllerPosition = Controller.getSpatialControlPosition(this.palm);
|
var directionNormalized = Vec3.normalize(pickRay.direction);
|
||||||
var intersectionDistance = Vec3.distance(handControllerPosition, intersection.intersection);
|
var directionBacked = Vec3.multiply(directionNormalized, PICK_BACKOFF_DISTANCE);
|
||||||
this.grabbedEntity = intersection.entityID;
|
var pickRayBacked = {
|
||||||
|
origin: Vec3.subtract(pickRay.origin, directionBacked),
|
||||||
|
direction: pickRay.direction
|
||||||
|
};
|
||||||
|
|
||||||
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA);
|
var intersection = Entities.findRayIntersection(pickRayBacked, true);
|
||||||
if (grabbableData.grabbable === false) {
|
if (intersection.intersects && intersection.properties.locked === 0) {
|
||||||
this.grabbedEntity = null;
|
// the ray is intersecting something we can move.
|
||||||
return;
|
var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection);
|
||||||
}
|
this.grabbedEntity = intersection.entityID;
|
||||||
if (intersectionDistance < NEAR_PICK_MAX_DISTANCE) {
|
|
||||||
// the hand is very close to the intersected object. go into close-grabbing mode.
|
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY,
|
||||||
if (intersection.properties.collisionsWillMove === 1) {
|
intersection.entityID,
|
||||||
this.setState(STATE_NEAR_GRABBING);
|
DEFAULT_GRABBABLE_DATA);
|
||||||
} else {
|
if (grabbableData.grabbable === false) {
|
||||||
this.setState(STATE_NEAR_GRABBING_NON_COLLIDING);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// don't allow two people to distance grab the same object
|
|
||||||
if (entityIsGrabbedByOther(intersection.entityID)) {
|
|
||||||
this.grabbedEntity = null;
|
this.grabbedEntity = null;
|
||||||
} else {
|
continue;
|
||||||
// the hand is far from the intersected object. go into distance-holding mode
|
}
|
||||||
|
if (intersectionDistance > pickRay.length) {
|
||||||
|
// too far away for this ray.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (intersectionDistance <= NEAR_PICK_MAX_DISTANCE) {
|
||||||
|
// the hand is very close to the intersected object. go into close-grabbing mode.
|
||||||
if (intersection.properties.collisionsWillMove === 1) {
|
if (intersection.properties.collisionsWillMove === 1) {
|
||||||
this.setState(STATE_DISTANCE_HOLDING);
|
this.setState(STATE_NEAR_GRABBING);
|
||||||
} else {
|
} else {
|
||||||
this.setState(STATE_FAR_GRABBING_NON_COLLIDING);
|
this.setState(STATE_NEAR_GRABBING_NON_COLLIDING);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// don't allow two people to distance grab the same object
|
||||||
|
if (entityIsGrabbedByOther(intersection.entityID)) {
|
||||||
|
this.grabbedEntity = null;
|
||||||
|
} else {
|
||||||
|
// the hand is far from the intersected object. go into distance-holding mode
|
||||||
|
if (intersection.properties.collisionsWillMove === 1) {
|
||||||
|
this.setState(STATE_DISTANCE_HOLDING);
|
||||||
|
} else {
|
||||||
|
this.setState(STATE_FAR_GRABBING_NON_COLLIDING);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// forward ray test failed, try sphere test.
|
|
||||||
var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS);
|
|
||||||
var minDistance = GRAB_RADIUS;
|
|
||||||
var i, props, distance;
|
|
||||||
|
|
||||||
for (i = 0; i < nearbyEntities.length; i++) {
|
|
||||||
|
|
||||||
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, nearbyEntities[i], DEFAULT_GRABBABLE_DATA);
|
|
||||||
if (grabbableData.grabbable === false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
props = Entities.getEntityProperties(nearbyEntities[i], ["position", "name", "collisionsWillMove", "locked"]);
|
|
||||||
|
|
||||||
distance = Vec3.distance(props.position, handPosition);
|
|
||||||
if (distance < minDistance && props.name !== "pointer") {
|
|
||||||
this.grabbedEntity = nearbyEntities[i];
|
|
||||||
minDistance = distance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.grabbedEntity === null) {
|
|
||||||
// this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
|
|
||||||
} else if (props.locked === 0 && props.collisionsWillMove === 1) {
|
|
||||||
this.setState(STATE_NEAR_GRABBING);
|
|
||||||
} else if (props.collisionsWillMove === 0) {
|
|
||||||
// We have grabbed a non-physical object, so we want to trigger a non-colliding event as opposed to a grab event
|
|
||||||
this.setState(STATE_NEAR_GRABBING_NON_COLLIDING);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -393,7 +386,8 @@ function MyController(hand, triggerAction) {
|
||||||
this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR);
|
this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR);
|
||||||
|
|
||||||
// the action was set up on a previous call. update the targets.
|
// the action was set up on a previous call. update the targets.
|
||||||
var radius = Math.max(Vec3.distance(this.currentObjectPosition, handControllerPosition) * DISTANCE_HOLDING_RADIUS_FACTOR, DISTANCE_HOLDING_RADIUS_FACTOR);
|
var radius = Math.max(Vec3.distance(this.currentObjectPosition, handControllerPosition) *
|
||||||
|
DISTANCE_HOLDING_RADIUS_FACTOR, DISTANCE_HOLDING_RADIUS_FACTOR);
|
||||||
|
|
||||||
// how far did avatar move this timestep?
|
// how far did avatar move this timestep?
|
||||||
var currentPosition = MyAvatar.position;
|
var currentPosition = MyAvatar.position;
|
||||||
|
@ -479,12 +473,23 @@ function MyController(hand, triggerAction) {
|
||||||
var handRotation = this.getHandRotation();
|
var handRotation = this.getHandRotation();
|
||||||
var handPosition = this.getHandPosition();
|
var handPosition = this.getHandPosition();
|
||||||
|
|
||||||
var objectRotation = grabbedProperties.rotation;
|
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
|
||||||
this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
|
|
||||||
|
|
||||||
var currentObjectPosition = grabbedProperties.position;
|
if (grabbableData.spatialKey) {
|
||||||
var offset = Vec3.subtract(currentObjectPosition, handPosition);
|
if (grabbableData.spatialKey.relativePosition) {
|
||||||
this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset);
|
this.offsetPosition = grabbableData.spatialKey.relativePosition;
|
||||||
|
}
|
||||||
|
if (grabbableData.spatialKey.relativeRotation) {
|
||||||
|
this.offsetRotation = grabbableData.spatialKey.relativeRotation;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var objectRotation = grabbedProperties.rotation;
|
||||||
|
this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
|
||||||
|
|
||||||
|
var currentObjectPosition = grabbedProperties.position;
|
||||||
|
var offset = Vec3.subtract(currentObjectPosition, handPosition);
|
||||||
|
this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset);
|
||||||
|
}
|
||||||
|
|
||||||
this.actionID = NULL_ACTION_ID;
|
this.actionID = NULL_ACTION_ID;
|
||||||
this.actionID = Entities.addAction("hold", this.grabbedEntity, {
|
this.actionID = Entities.addAction("hold", this.grabbedEntity, {
|
||||||
|
@ -584,7 +589,7 @@ function MyController(hand, triggerAction) {
|
||||||
this.setState(STATE_RELEASE);
|
this.setState(STATE_RELEASE);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entities.callEntityMethod(this.grabbedEntity, "continueNearGrabbingNonColliding");
|
Entities.callEntityMethod(this.grabbedEntity, "continueNearGrabbingNonColliding");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -600,6 +605,16 @@ function MyController(hand, triggerAction) {
|
||||||
direction: Quat.getUp(this.getHandRotation())
|
direction: Quat.getUp(this.getHandRotation())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var now = Date.now();
|
||||||
|
if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) {
|
||||||
|
var intersection = Entities.findRayIntersection(pickRay, true);
|
||||||
|
this.lastPickTime = now;
|
||||||
|
if (intersection.entityID != this.grabbedEntity) {
|
||||||
|
this.setState(STATE_RELEASE);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
|
this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
|
||||||
Entities.callEntityMethod(this.grabbedEntity, "continueFarGrabbingNonColliding");
|
Entities.callEntityMethod(this.grabbedEntity, "continueFarGrabbingNonColliding");
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
|
|
||||||
|
|
||||||
#include <avatar/AvatarActionHold.h>
|
#include <avatar/AvatarActionHold.h>
|
||||||
#include <avatar/AvatarActionKinematicHold.h>
|
|
||||||
#include <ObjectActionOffset.h>
|
#include <ObjectActionOffset.h>
|
||||||
#include <ObjectActionSpring.h>
|
#include <ObjectActionSpring.h>
|
||||||
|
|
||||||
|
@ -29,8 +28,6 @@ EntityActionPointer interfaceActionFactory(EntityActionType type, const QUuid& i
|
||||||
return (EntityActionPointer) new ObjectActionSpring(id, ownerEntity);
|
return (EntityActionPointer) new ObjectActionSpring(id, ownerEntity);
|
||||||
case ACTION_TYPE_HOLD:
|
case ACTION_TYPE_HOLD:
|
||||||
return (EntityActionPointer) new AvatarActionHold(id, ownerEntity);
|
return (EntityActionPointer) new AvatarActionHold(id, ownerEntity);
|
||||||
case ACTION_TYPE_KINEMATIC_HOLD:
|
|
||||||
return (EntityActionPointer) new AvatarActionKinematicHold(id, ownerEntity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(false);
|
assert(false);
|
||||||
|
@ -69,6 +66,7 @@ EntityActionPointer InterfaceActionFactory::factoryBA(EntityItemPointer ownerEnt
|
||||||
if (action) {
|
if (action) {
|
||||||
action->deserialize(data);
|
action->deserialize(data);
|
||||||
if (action->lifetimeIsOver()) {
|
if (action->lifetimeIsOver()) {
|
||||||
|
qDebug() << "InterfaceActionFactory::factoryBA lifetimeIsOver during action creation";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,8 @@ AvatarActionHold::AvatarActionHold(const QUuid& id, EntityItemPointer ownerEntit
|
||||||
ObjectActionSpring(id, ownerEntity),
|
ObjectActionSpring(id, ownerEntity),
|
||||||
_relativePosition(glm::vec3(0.0f)),
|
_relativePosition(glm::vec3(0.0f)),
|
||||||
_relativeRotation(glm::quat()),
|
_relativeRotation(glm::quat()),
|
||||||
_hand("right")
|
_hand("right"),
|
||||||
|
_holderID(QUuid())
|
||||||
{
|
{
|
||||||
_type = ACTION_TYPE_HOLD;
|
_type = ACTION_TYPE_HOLD;
|
||||||
#if WANT_DEBUG
|
#if WANT_DEBUG
|
||||||
|
@ -39,42 +40,92 @@ void AvatarActionHold::updateActionWorker(float deltaTimeStep) {
|
||||||
bool gotLock = false;
|
bool gotLock = false;
|
||||||
glm::quat rotation;
|
glm::quat rotation;
|
||||||
glm::vec3 position;
|
glm::vec3 position;
|
||||||
glm::vec3 offset;
|
std::shared_ptr<Avatar> holdingAvatar = nullptr;
|
||||||
|
|
||||||
gotLock = withTryReadLock([&]{
|
gotLock = withTryReadLock([&]{
|
||||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
QSharedPointer<AvatarManager> avatarManager = DependencyManager::get<AvatarManager>();
|
||||||
glm::vec3 palmPosition;
|
AvatarSharedPointer holdingAvatarData = avatarManager->getAvatarBySessionID(_holderID);
|
||||||
glm::quat palmRotation;
|
holdingAvatar = std::static_pointer_cast<Avatar>(holdingAvatarData);
|
||||||
if (_hand == "right") {
|
|
||||||
palmPosition = myAvatar->getRightPalmPosition();
|
|
||||||
palmRotation = myAvatar->getRightPalmRotation();
|
|
||||||
} else {
|
|
||||||
palmPosition = myAvatar->getLeftPalmPosition();
|
|
||||||
palmRotation = myAvatar->getLeftPalmRotation();
|
|
||||||
}
|
|
||||||
|
|
||||||
rotation = palmRotation * _relativeRotation;
|
if (holdingAvatar) {
|
||||||
offset = rotation * _relativePosition;
|
glm::vec3 offset;
|
||||||
position = palmPosition + offset;
|
glm::vec3 palmPosition;
|
||||||
|
glm::quat palmRotation;
|
||||||
|
if (_hand == "right") {
|
||||||
|
palmPosition = holdingAvatar->getRightPalmPosition();
|
||||||
|
palmRotation = holdingAvatar->getRightPalmRotation();
|
||||||
|
} else {
|
||||||
|
palmPosition = holdingAvatar->getLeftPalmPosition();
|
||||||
|
palmRotation = holdingAvatar->getLeftPalmRotation();
|
||||||
|
}
|
||||||
|
|
||||||
|
rotation = palmRotation * _relativeRotation;
|
||||||
|
offset = rotation * _relativePosition;
|
||||||
|
position = palmPosition + offset;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (gotLock) {
|
if (holdingAvatar) {
|
||||||
gotLock = withTryWriteLock([&]{
|
if (gotLock) {
|
||||||
_positionalTarget = position;
|
gotLock = withTryWriteLock([&]{
|
||||||
_rotationalTarget = rotation;
|
_positionalTarget = position;
|
||||||
_positionalTargetSet = true;
|
_rotationalTarget = rotation;
|
||||||
_rotationalTargetSet = true;
|
_positionalTargetSet = true;
|
||||||
auto ownerEntity = _ownerEntity.lock();
|
_rotationalTargetSet = true;
|
||||||
if (ownerEntity) {
|
_active = true;
|
||||||
ownerEntity->setActionDataDirty(true);
|
});
|
||||||
|
if (gotLock) {
|
||||||
|
if (_kinematic) {
|
||||||
|
doKinematicUpdate(deltaTimeStep);
|
||||||
|
} else {
|
||||||
|
activateBody();
|
||||||
|
ObjectActionSpring::updateActionWorker(deltaTimeStep);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
|
||||||
if (gotLock) {
|
|
||||||
ObjectActionSpring::updateActionWorker(deltaTimeStep);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) {
|
||||||
|
auto ownerEntity = _ownerEntity.lock();
|
||||||
|
if (!ownerEntity) {
|
||||||
|
qDebug() << "AvatarActionHold::doKinematicUpdate -- no owning entity";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
void* physicsInfo = ownerEntity->getPhysicsInfo();
|
||||||
|
if (!physicsInfo) {
|
||||||
|
qDebug() << "AvatarActionHold::doKinematicUpdate -- no owning physics info";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
|
||||||
|
btRigidBody* rigidBody = motionState ? motionState->getRigidBody() : nullptr;
|
||||||
|
if (!rigidBody) {
|
||||||
|
qDebug() << "AvatarActionHold::doKinematicUpdate -- no rigidBody";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
withWriteLock([&]{
|
||||||
|
if (_kinematicSetVelocity) {
|
||||||
|
if (_previousSet) {
|
||||||
|
glm::vec3 positionalVelocity = (_positionalTarget - _previousPositionalTarget) / deltaTimeStep;
|
||||||
|
rigidBody->setLinearVelocity(glmToBullet(positionalVelocity));
|
||||||
|
// back up along velocity a bit in order to smooth out a "vibrating" appearance
|
||||||
|
_positionalTarget -= positionalVelocity * deltaTimeStep / 2.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
btTransform worldTrans = rigidBody->getWorldTransform();
|
||||||
|
worldTrans.setOrigin(glmToBullet(_positionalTarget));
|
||||||
|
worldTrans.setRotation(glmToBullet(_rotationalTarget));
|
||||||
|
rigidBody->setWorldTransform(worldTrans);
|
||||||
|
|
||||||
|
_previousPositionalTarget = _positionalTarget;
|
||||||
|
_previousRotationalTarget = _rotationalTarget;
|
||||||
|
_previousSet = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
activateBody();
|
||||||
|
}
|
||||||
|
|
||||||
bool AvatarActionHold::updateArguments(QVariantMap arguments) {
|
bool AvatarActionHold::updateArguments(QVariantMap arguments) {
|
||||||
glm::vec3 relativePosition;
|
glm::vec3 relativePosition;
|
||||||
|
@ -82,6 +133,8 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) {
|
||||||
float timeScale;
|
float timeScale;
|
||||||
QString hand;
|
QString hand;
|
||||||
QUuid holderID;
|
QUuid holderID;
|
||||||
|
bool kinematic;
|
||||||
|
bool kinematicSetVelocity;
|
||||||
bool needUpdate = false;
|
bool needUpdate = false;
|
||||||
|
|
||||||
bool somethingChanged = ObjectAction::updateArguments(arguments);
|
bool somethingChanged = ObjectAction::updateArguments(arguments);
|
||||||
|
@ -114,11 +167,27 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) {
|
||||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||||
holderID = myAvatar->getSessionUUID();
|
holderID = myAvatar->getSessionUUID();
|
||||||
|
|
||||||
|
ok = true;
|
||||||
|
kinematic = EntityActionInterface::extractBooleanArgument("hold", arguments, "kinematic", ok, false);
|
||||||
|
if (!ok) {
|
||||||
|
_kinematic = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = true;
|
||||||
|
kinematicSetVelocity = EntityActionInterface::extractBooleanArgument("hold", arguments,
|
||||||
|
"kinematicSetVelocity", ok, false);
|
||||||
|
if (!ok) {
|
||||||
|
_kinematicSetVelocity = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (somethingChanged ||
|
if (somethingChanged ||
|
||||||
relativePosition != _relativePosition ||
|
relativePosition != _relativePosition ||
|
||||||
relativeRotation != _relativeRotation ||
|
relativeRotation != _relativeRotation ||
|
||||||
timeScale != _linearTimeScale ||
|
timeScale != _linearTimeScale ||
|
||||||
hand != _hand) {
|
hand != _hand ||
|
||||||
|
holderID != _holderID ||
|
||||||
|
kinematic != _kinematic ||
|
||||||
|
kinematicSetVelocity != _kinematicSetVelocity) {
|
||||||
needUpdate = true;
|
needUpdate = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -131,6 +200,9 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) {
|
||||||
_linearTimeScale = glm::max(MIN_TIMESCALE, timeScale);
|
_linearTimeScale = glm::max(MIN_TIMESCALE, timeScale);
|
||||||
_angularTimeScale = _linearTimeScale;
|
_angularTimeScale = _linearTimeScale;
|
||||||
_hand = hand;
|
_hand = hand;
|
||||||
|
_holderID = holderID;
|
||||||
|
_kinematic = kinematic;
|
||||||
|
_kinematicSetVelocity = kinematicSetVelocity;
|
||||||
_active = true;
|
_active = true;
|
||||||
|
|
||||||
auto ownerEntity = _ownerEntity.lock();
|
auto ownerEntity = _ownerEntity.lock();
|
||||||
|
@ -147,6 +219,7 @@ bool AvatarActionHold::updateArguments(QVariantMap arguments) {
|
||||||
QVariantMap AvatarActionHold::getArguments() {
|
QVariantMap AvatarActionHold::getArguments() {
|
||||||
QVariantMap arguments = ObjectAction::getArguments();
|
QVariantMap arguments = ObjectAction::getArguments();
|
||||||
withReadLock([&]{
|
withReadLock([&]{
|
||||||
|
arguments["holderID"] = _holderID;
|
||||||
arguments["relativePosition"] = glmToQMap(_relativePosition);
|
arguments["relativePosition"] = glmToQMap(_relativePosition);
|
||||||
arguments["relativeRotation"] = glmToQMap(_relativeRotation);
|
arguments["relativeRotation"] = glmToQMap(_relativeRotation);
|
||||||
arguments["timeScale"] = _linearTimeScale;
|
arguments["timeScale"] = _linearTimeScale;
|
||||||
|
@ -156,9 +229,62 @@ QVariantMap AvatarActionHold::getArguments() {
|
||||||
}
|
}
|
||||||
|
|
||||||
QByteArray AvatarActionHold::serialize() const {
|
QByteArray AvatarActionHold::serialize() const {
|
||||||
return ObjectActionSpring::serialize();
|
QByteArray serializedActionArguments;
|
||||||
|
QDataStream dataStream(&serializedActionArguments, QIODevice::WriteOnly);
|
||||||
|
|
||||||
|
withReadLock([&]{
|
||||||
|
dataStream << ACTION_TYPE_HOLD;
|
||||||
|
dataStream << getID();
|
||||||
|
dataStream << AvatarActionHold::holdVersion;
|
||||||
|
|
||||||
|
dataStream << _holderID;
|
||||||
|
dataStream << _relativePosition;
|
||||||
|
dataStream << _relativeRotation;
|
||||||
|
dataStream << _linearTimeScale;
|
||||||
|
dataStream << _hand;
|
||||||
|
|
||||||
|
dataStream << _expires + getEntityServerClockSkew();
|
||||||
|
dataStream << _tag;
|
||||||
|
});
|
||||||
|
|
||||||
|
return serializedActionArguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarActionHold::deserialize(QByteArray serializedArguments) {
|
void AvatarActionHold::deserialize(QByteArray serializedArguments) {
|
||||||
assert(false);
|
QDataStream dataStream(serializedArguments);
|
||||||
|
|
||||||
|
EntityActionType type;
|
||||||
|
dataStream >> type;
|
||||||
|
assert(type == getType());
|
||||||
|
|
||||||
|
QUuid id;
|
||||||
|
dataStream >> id;
|
||||||
|
assert(id == getID());
|
||||||
|
|
||||||
|
uint16_t serializationVersion;
|
||||||
|
dataStream >> serializationVersion;
|
||||||
|
if (serializationVersion != AvatarActionHold::holdVersion) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
withWriteLock([&]{
|
||||||
|
dataStream >> _holderID;
|
||||||
|
dataStream >> _relativePosition;
|
||||||
|
dataStream >> _relativeRotation;
|
||||||
|
dataStream >> _linearTimeScale;
|
||||||
|
_angularTimeScale = _linearTimeScale;
|
||||||
|
dataStream >> _hand;
|
||||||
|
|
||||||
|
dataStream >> _expires;
|
||||||
|
_expires -= getEntityServerClockSkew();
|
||||||
|
dataStream >> _tag;
|
||||||
|
|
||||||
|
#if WANT_DEBUG
|
||||||
|
qDebug() << "deserialize AvatarActionHold: " << _holderID
|
||||||
|
<< _relativePosition.x << _relativePosition.y << _relativePosition.z
|
||||||
|
<< _hand << _expires;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_active = true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ public:
|
||||||
QByteArray serialize() const;
|
QByteArray serialize() const;
|
||||||
virtual void deserialize(QByteArray serializedArguments);
|
virtual void deserialize(QByteArray serializedArguments);
|
||||||
|
|
||||||
virtual bool shouldSuppressLocationEdits() { return false; }
|
virtual bool shouldSuppressLocationEdits() { return true; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const uint16_t holdVersion;
|
static const uint16_t holdVersion;
|
||||||
|
@ -38,6 +38,14 @@ private:
|
||||||
glm::vec3 _relativePosition;
|
glm::vec3 _relativePosition;
|
||||||
glm::quat _relativeRotation;
|
glm::quat _relativeRotation;
|
||||||
QString _hand;
|
QString _hand;
|
||||||
|
QUuid _holderID;
|
||||||
|
|
||||||
|
void doKinematicUpdate(float deltaTimeStep);
|
||||||
|
bool _kinematic { false };
|
||||||
|
bool _kinematicSetVelocity { false };
|
||||||
|
bool _previousSet { false };
|
||||||
|
glm::vec3 _previousPositionalTarget;
|
||||||
|
glm::quat _previousRotationalTarget;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_AvatarActionHold_h
|
#endif // hifi_AvatarActionHold_h
|
||||||
|
|
|
@ -1,188 +0,0 @@
|
||||||
//
|
|
||||||
// AvatarActionKinematicHold.cpp
|
|
||||||
// interface/src/avatar/
|
|
||||||
//
|
|
||||||
// Created by Seth Alves 2015-6-9
|
|
||||||
// Copyright 2015 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 "QVariantGLM.h"
|
|
||||||
#include "avatar/MyAvatar.h"
|
|
||||||
#include "avatar/AvatarManager.h"
|
|
||||||
|
|
||||||
#include "AvatarActionKinematicHold.h"
|
|
||||||
|
|
||||||
const uint16_t AvatarActionKinematicHold::holdVersion = 1;
|
|
||||||
|
|
||||||
AvatarActionKinematicHold::AvatarActionKinematicHold(const QUuid& id, EntityItemPointer ownerEntity) :
|
|
||||||
ObjectActionSpring(id, ownerEntity),
|
|
||||||
_relativePosition(glm::vec3(0.0f)),
|
|
||||||
_relativeRotation(glm::quat()),
|
|
||||||
_hand("right"),
|
|
||||||
_mine(false),
|
|
||||||
_previousPositionalTarget(Vectors::ZERO),
|
|
||||||
_previousRotationalTarget(Quaternions::IDENTITY)
|
|
||||||
{
|
|
||||||
_type = ACTION_TYPE_KINEMATIC_HOLD;
|
|
||||||
#if WANT_DEBUG
|
|
||||||
qDebug() << "AvatarActionKinematicHold::AvatarActionKinematicHold";
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
AvatarActionKinematicHold::~AvatarActionKinematicHold() {
|
|
||||||
#if WANT_DEBUG
|
|
||||||
qDebug() << "AvatarActionKinematicHold::~AvatarActionKinematicHold";
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void AvatarActionKinematicHold::updateActionWorker(float deltaTimeStep) {
|
|
||||||
if (!_mine) {
|
|
||||||
// if a local script isn't updating this, then we are just getting spring-action data over the wire.
|
|
||||||
// let the super-class handle it.
|
|
||||||
ObjectActionSpring::updateActionWorker(deltaTimeStep);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(deltaTimeStep > 0.0f);
|
|
||||||
|
|
||||||
glm::quat rotation;
|
|
||||||
glm::vec3 position;
|
|
||||||
glm::vec3 offset;
|
|
||||||
bool gotLock = withTryReadLock([&]{
|
|
||||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
|
||||||
glm::vec3 palmPosition;
|
|
||||||
glm::quat palmRotation;
|
|
||||||
if (_hand == "right") {
|
|
||||||
palmPosition = myAvatar->getRightPalmPosition();
|
|
||||||
palmRotation = myAvatar->getRightPalmRotation();
|
|
||||||
} else {
|
|
||||||
palmPosition = myAvatar->getLeftPalmPosition();
|
|
||||||
palmRotation = myAvatar->getLeftPalmRotation();
|
|
||||||
}
|
|
||||||
|
|
||||||
rotation = palmRotation * _relativeRotation;
|
|
||||||
offset = rotation * _relativePosition;
|
|
||||||
position = palmPosition + offset;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (gotLock) {
|
|
||||||
gotLock = withTryWriteLock([&]{
|
|
||||||
if (_positionalTarget != position || _rotationalTarget != rotation) {
|
|
||||||
_positionalTarget = position;
|
|
||||||
_rotationalTarget = rotation;
|
|
||||||
auto ownerEntity = _ownerEntity.lock();
|
|
||||||
if (ownerEntity) {
|
|
||||||
ownerEntity->setActionDataDirty(true);
|
|
||||||
void* physicsInfo = ownerEntity->getPhysicsInfo();
|
|
||||||
if (physicsInfo) {
|
|
||||||
ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo);
|
|
||||||
btRigidBody* rigidBody = motionState ? motionState->getRigidBody() : nullptr;
|
|
||||||
if (!rigidBody) {
|
|
||||||
qDebug() << "ObjectActionSpring::updateActionWorker no rigidBody";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_setVelocity) {
|
|
||||||
if (_previousSet) {
|
|
||||||
glm::vec3 positionalVelocity = (_positionalTarget - _previousPositionalTarget) / deltaTimeStep;
|
|
||||||
rigidBody->setLinearVelocity(glmToBullet(positionalVelocity));
|
|
||||||
// back up along velocity a bit in order to smooth out a "vibrating" appearance
|
|
||||||
_positionalTarget -= positionalVelocity * deltaTimeStep / 2.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
btTransform worldTrans = rigidBody->getWorldTransform();
|
|
||||||
worldTrans.setOrigin(glmToBullet(_positionalTarget));
|
|
||||||
worldTrans.setRotation(glmToBullet(_rotationalTarget));
|
|
||||||
rigidBody->setWorldTransform(worldTrans);
|
|
||||||
|
|
||||||
_previousPositionalTarget = _positionalTarget;
|
|
||||||
_previousRotationalTarget = _rotationalTarget;
|
|
||||||
_previousSet = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gotLock) {
|
|
||||||
ObjectActionSpring::updateActionWorker(deltaTimeStep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool AvatarActionKinematicHold::updateArguments(QVariantMap arguments) {
|
|
||||||
if (!ObjectAction::updateArguments(arguments)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool ok = true;
|
|
||||||
glm::vec3 relativePosition =
|
|
||||||
EntityActionInterface::extractVec3Argument("kinematic-hold", arguments, "relativePosition", ok, false);
|
|
||||||
if (!ok) {
|
|
||||||
relativePosition = _relativePosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
ok = true;
|
|
||||||
glm::quat relativeRotation =
|
|
||||||
EntityActionInterface::extractQuatArgument("kinematic-hold", arguments, "relativeRotation", ok, false);
|
|
||||||
if (!ok) {
|
|
||||||
relativeRotation = _relativeRotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
ok = true;
|
|
||||||
QString hand =
|
|
||||||
EntityActionInterface::extractStringArgument("kinematic-hold", arguments, "hand", ok, false);
|
|
||||||
if (!ok || !(hand == "left" || hand == "right")) {
|
|
||||||
hand = _hand;
|
|
||||||
}
|
|
||||||
|
|
||||||
ok = true;
|
|
||||||
int setVelocity =
|
|
||||||
EntityActionInterface::extractIntegerArgument("kinematic-hold", arguments, "setVelocity", ok, false);
|
|
||||||
if (!ok) {
|
|
||||||
setVelocity = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (relativePosition != _relativePosition
|
|
||||||
|| relativeRotation != _relativeRotation
|
|
||||||
|| hand != _hand) {
|
|
||||||
withWriteLock([&] {
|
|
||||||
_relativePosition = relativePosition;
|
|
||||||
_relativeRotation = relativeRotation;
|
|
||||||
_hand = hand;
|
|
||||||
_setVelocity = setVelocity;
|
|
||||||
|
|
||||||
_mine = true;
|
|
||||||
_active = true;
|
|
||||||
activateBody();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QVariantMap AvatarActionKinematicHold::getArguments() {
|
|
||||||
QVariantMap arguments = ObjectAction::getArguments();
|
|
||||||
withReadLock([&]{
|
|
||||||
if (!_mine) {
|
|
||||||
arguments = ObjectActionSpring::getArguments();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
arguments["relativePosition"] = glmToQMap(_relativePosition);
|
|
||||||
arguments["relativeRotation"] = glmToQMap(_relativeRotation);
|
|
||||||
arguments["setVelocity"] = _setVelocity;
|
|
||||||
arguments["hand"] = _hand;
|
|
||||||
});
|
|
||||||
return arguments;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void AvatarActionKinematicHold::deserialize(QByteArray serializedArguments) {
|
|
||||||
if (!_mine) {
|
|
||||||
ObjectActionSpring::deserialize(serializedArguments);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,47 +0,0 @@
|
||||||
//
|
|
||||||
// AvatarActionKinematicHold.h
|
|
||||||
// interface/src/avatar/
|
|
||||||
//
|
|
||||||
// Created by Seth Alves 2015-10-2
|
|
||||||
// Copyright 2015 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_AvatarActionKinematicHold_h
|
|
||||||
#define hifi_AvatarActionKinematicHold_h
|
|
||||||
|
|
||||||
#include <QUuid>
|
|
||||||
|
|
||||||
#include <EntityItem.h>
|
|
||||||
#include <ObjectActionSpring.h>
|
|
||||||
|
|
||||||
class AvatarActionKinematicHold : public ObjectActionSpring {
|
|
||||||
public:
|
|
||||||
AvatarActionKinematicHold(const QUuid& id, EntityItemPointer ownerEntity);
|
|
||||||
virtual ~AvatarActionKinematicHold();
|
|
||||||
|
|
||||||
virtual bool updateArguments(QVariantMap arguments);
|
|
||||||
virtual QVariantMap getArguments();
|
|
||||||
|
|
||||||
virtual void updateActionWorker(float deltaTimeStep);
|
|
||||||
|
|
||||||
virtual void deserialize(QByteArray serializedArguments);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static const uint16_t holdVersion;
|
|
||||||
|
|
||||||
glm::vec3 _relativePosition;
|
|
||||||
glm::quat _relativeRotation;
|
|
||||||
QString _hand;
|
|
||||||
bool _mine = false;
|
|
||||||
|
|
||||||
bool _previousSet = false;
|
|
||||||
glm::vec3 _previousPositionalTarget;
|
|
||||||
glm::quat _previousRotationalTarget;
|
|
||||||
|
|
||||||
bool _setVelocity = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // hifi_AvatarActionKinematicHold_h
|
|
|
@ -229,6 +229,12 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
||||||
|
|
||||||
Model::simulate(deltaTime, fullUpdate);
|
Model::simulate(deltaTime, fullUpdate);
|
||||||
|
|
||||||
|
// let rig compute the model offset
|
||||||
|
glm::vec3 modelOffset;
|
||||||
|
if (_rig->getModelOffset(modelOffset)) {
|
||||||
|
setOffset(modelOffset);
|
||||||
|
}
|
||||||
|
|
||||||
if (!isActive() || !_owningAvatar->isMyAvatar()) {
|
if (!isActive() || !_owningAvatar->isMyAvatar()) {
|
||||||
return; // only simulate for own avatar
|
return; // only simulate for own avatar
|
||||||
}
|
}
|
||||||
|
@ -246,12 +252,6 @@ void SkeletonModel::simulate(float deltaTime, bool fullUpdate) {
|
||||||
Hand* hand = _owningAvatar->getHand();
|
Hand* hand = _owningAvatar->getHand();
|
||||||
hand->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex);
|
hand->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex);
|
||||||
|
|
||||||
// let rig compute the model offset
|
|
||||||
glm::vec3 modelOffset;
|
|
||||||
if (_rig->getModelOffset(modelOffset)) {
|
|
||||||
setOffset(modelOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't Relax toward hand positions when in animGraph mode.
|
// Don't Relax toward hand positions when in animGraph mode.
|
||||||
if (!_rig->getEnableAnimGraph()) {
|
if (!_rig->getEnableAnimGraph()) {
|
||||||
const float HAND_RESTORATION_RATE = 0.25f;
|
const float HAND_RESTORATION_RATE = 0.25f;
|
||||||
|
|
|
@ -1238,12 +1238,18 @@ void Rig::updateFromHandParameters(const HandParameters& params, float dt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Rig::makeAnimSkeleton(const FBXGeometry& fbxGeometry) {
|
||||||
|
if (!_animSkeleton) {
|
||||||
|
_animSkeleton = std::make_shared<AnimSkeleton>(fbxGeometry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Rig::initAnimGraph(const QUrl& url, const FBXGeometry& fbxGeometry) {
|
void Rig::initAnimGraph(const QUrl& url, const FBXGeometry& fbxGeometry) {
|
||||||
if (!_enableAnimGraph) {
|
if (!_enableAnimGraph) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_animSkeleton = std::make_shared<AnimSkeleton>(fbxGeometry);
|
makeAnimSkeleton(fbxGeometry);
|
||||||
|
|
||||||
// load the anim graph
|
// load the anim graph
|
||||||
_animLoader.reset(new AnimNodeLoader(url));
|
_animLoader.reset(new AnimNodeLoader(url));
|
||||||
|
|
|
@ -193,6 +193,7 @@ public:
|
||||||
virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation,
|
virtual void setHandPosition(int jointIndex, const glm::vec3& position, const glm::quat& rotation,
|
||||||
float scale, float priority) = 0;
|
float scale, float priority) = 0;
|
||||||
|
|
||||||
|
void makeAnimSkeleton(const FBXGeometry& fbxGeometry);
|
||||||
void initAnimGraph(const QUrl& url, const FBXGeometry& fbxGeometry);
|
void initAnimGraph(const QUrl& url, const FBXGeometry& fbxGeometry);
|
||||||
|
|
||||||
AnimNode::ConstPointer getAnimNode() const { return _animNode; }
|
AnimNode::ConstPointer getAnimNode() const { return _animNode; }
|
||||||
|
|
|
@ -298,18 +298,23 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool movingOrAnimating = isMoving() || isAnimatingSomething();
|
bool movingOrAnimating = isMoving() || isAnimatingSomething();
|
||||||
if ((movingOrAnimating || _needsInitialSimulation) && _model->isActive() && _dimensionsInitialized) {
|
if ((movingOrAnimating ||
|
||||||
|
_needsInitialSimulation ||
|
||||||
|
_model->getTranslation() != getPosition() ||
|
||||||
|
_model->getRotation() != getRotation() ||
|
||||||
|
_model->getRegistrationPoint() != getRegistrationPoint())
|
||||||
|
&& _model->isActive() && _dimensionsInitialized) {
|
||||||
_model->setScaleToFit(true, getDimensions());
|
_model->setScaleToFit(true, getDimensions());
|
||||||
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
|
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
|
||||||
_model->setRotation(getRotation());
|
_model->setRotation(getRotation());
|
||||||
_model->setTranslation(getPosition());
|
_model->setTranslation(getPosition());
|
||||||
|
|
||||||
// make sure to simulate so everything gets set up correctly for rendering
|
// make sure to simulate so everything gets set up correctly for rendering
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("_model->simulate");
|
PerformanceTimer perfTimer("_model->simulate");
|
||||||
_model->simulate(0.0f);
|
_model->simulate(0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
_needsInitialSimulation = false;
|
_needsInitialSimulation = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,9 +100,6 @@ EntityActionType EntityActionInterface::actionTypeFromString(QString actionTypeS
|
||||||
if (normalizedActionTypeString == "hold") {
|
if (normalizedActionTypeString == "hold") {
|
||||||
return ACTION_TYPE_HOLD;
|
return ACTION_TYPE_HOLD;
|
||||||
}
|
}
|
||||||
if (normalizedActionTypeString == "kinematichold") {
|
|
||||||
return ACTION_TYPE_KINEMATIC_HOLD;
|
|
||||||
}
|
|
||||||
|
|
||||||
qDebug() << "Warning -- EntityActionInterface::actionTypeFromString got unknown action-type name" << actionTypeString;
|
qDebug() << "Warning -- EntityActionInterface::actionTypeFromString got unknown action-type name" << actionTypeString;
|
||||||
return ACTION_TYPE_NONE;
|
return ACTION_TYPE_NONE;
|
||||||
|
@ -118,8 +115,6 @@ QString EntityActionInterface::actionTypeToString(EntityActionType actionType) {
|
||||||
return "spring";
|
return "spring";
|
||||||
case ACTION_TYPE_HOLD:
|
case ACTION_TYPE_HOLD:
|
||||||
return "hold";
|
return "hold";
|
||||||
case ACTION_TYPE_KINEMATIC_HOLD:
|
|
||||||
return "kinematic-hold";
|
|
||||||
}
|
}
|
||||||
assert(false);
|
assert(false);
|
||||||
return "none";
|
return "none";
|
||||||
|
@ -280,12 +275,23 @@ QString EntityActionInterface::extractStringArgument(QString objectName, QVarian
|
||||||
ok = false;
|
ok = false;
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
return arguments[argumentName].toString();
|
||||||
QVariant vV = arguments[argumentName];
|
|
||||||
QString v = vV.toString();
|
|
||||||
return v;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool EntityActionInterface::extractBooleanArgument(QString objectName, QVariantMap arguments,
|
||||||
|
QString argumentName, bool& ok, bool required) {
|
||||||
|
if (!arguments.contains(argumentName)) {
|
||||||
|
if (required) {
|
||||||
|
qDebug() << objectName << "requires argument:" << argumentName;
|
||||||
|
}
|
||||||
|
ok = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return arguments[argumentName].toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
QDataStream& operator<<(QDataStream& stream, const EntityActionType& entityActionType)
|
QDataStream& operator<<(QDataStream& stream, const EntityActionType& entityActionType)
|
||||||
{
|
{
|
||||||
return stream << (quint16)entityActionType;
|
return stream << (quint16)entityActionType;
|
||||||
|
|
|
@ -23,8 +23,7 @@ enum EntityActionType {
|
||||||
ACTION_TYPE_NONE = 0,
|
ACTION_TYPE_NONE = 0,
|
||||||
ACTION_TYPE_OFFSET = 1000,
|
ACTION_TYPE_OFFSET = 1000,
|
||||||
ACTION_TYPE_SPRING = 2000,
|
ACTION_TYPE_SPRING = 2000,
|
||||||
ACTION_TYPE_HOLD = 3000,
|
ACTION_TYPE_HOLD = 3000
|
||||||
ACTION_TYPE_KINEMATIC_HOLD = 4000
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,6 +65,8 @@ public:
|
||||||
QString argumentName, bool& ok, bool required = true);
|
QString argumentName, bool& ok, bool required = true);
|
||||||
static QString extractStringArgument(QString objectName, QVariantMap arguments,
|
static QString extractStringArgument(QString objectName, QVariantMap arguments,
|
||||||
QString argumentName, bool& ok, bool required = true);
|
QString argumentName, bool& ok, bool required = true);
|
||||||
|
static bool extractBooleanArgument(QString objectName, QVariantMap arguments,
|
||||||
|
QString argumentName, bool& ok, bool required = true);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual glm::vec3 getPosition() = 0;
|
virtual glm::vec3 getPosition() = 0;
|
||||||
|
|
|
@ -342,6 +342,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
||||||
"ERROR CASE...args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU";
|
"ERROR CASE...args.bitstreamVersion < VERSION_ENTITIES_SUPPORT_SPLIT_MTU";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
setSourceUUID(args.sourceUUID);
|
||||||
|
|
||||||
args.entitiesPerPacket++;
|
args.entitiesPerPacket++;
|
||||||
|
|
||||||
|
@ -1300,6 +1301,9 @@ void EntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::updatePosition(const glm::vec3& value) {
|
void EntityItem::updatePosition(const glm::vec3& value) {
|
||||||
|
if (shouldSuppressLocationEdits()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto delta = glm::distance(getPosition(), value);
|
auto delta = glm::distance(getPosition(), value);
|
||||||
if (delta > IGNORE_POSITION_DELTA) {
|
if (delta > IGNORE_POSITION_DELTA) {
|
||||||
_dirtyFlags |= Simulation::DIRTY_POSITION;
|
_dirtyFlags |= Simulation::DIRTY_POSITION;
|
||||||
|
@ -1322,6 +1326,9 @@ void EntityItem::updateDimensions(const glm::vec3& value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::updateRotation(const glm::quat& rotation) {
|
void EntityItem::updateRotation(const glm::quat& rotation) {
|
||||||
|
if (shouldSuppressLocationEdits()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (getRotation() != rotation) {
|
if (getRotation() != rotation) {
|
||||||
setRotation(rotation);
|
setRotation(rotation);
|
||||||
|
|
||||||
|
@ -1362,6 +1369,9 @@ void EntityItem::updateMass(float mass) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::updateVelocity(const glm::vec3& value) {
|
void EntityItem::updateVelocity(const glm::vec3& value) {
|
||||||
|
if (shouldSuppressLocationEdits()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto delta = glm::distance(_velocity, value);
|
auto delta = glm::distance(_velocity, value);
|
||||||
if (delta > IGNORE_LINEAR_VELOCITY_DELTA) {
|
if (delta > IGNORE_LINEAR_VELOCITY_DELTA) {
|
||||||
_dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY;
|
_dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY;
|
||||||
|
@ -1398,6 +1408,9 @@ void EntityItem::updateGravity(const glm::vec3& value) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::updateAngularVelocity(const glm::vec3& value) {
|
void EntityItem::updateAngularVelocity(const glm::vec3& value) {
|
||||||
|
if (shouldSuppressLocationEdits()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
auto delta = glm::distance(_angularVelocity, value);
|
auto delta = glm::distance(_angularVelocity, value);
|
||||||
if (delta > IGNORE_ANGULAR_VELOCITY_DELTA) {
|
if (delta > IGNORE_ANGULAR_VELOCITY_DELTA) {
|
||||||
_dirtyFlags |= Simulation::DIRTY_ANGULAR_VELOCITY;
|
_dirtyFlags |= Simulation::DIRTY_ANGULAR_VELOCITY;
|
||||||
|
@ -1534,6 +1547,8 @@ bool EntityItem::addActionInternal(EntitySimulation* simulation, EntityActionPoi
|
||||||
if (success) {
|
if (success) {
|
||||||
_allActionsDataCache = newDataCache;
|
_allActionsDataCache = newDataCache;
|
||||||
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
|
_dirtyFlags |= Simulation::DIRTY_PHYSICS_ACTIVATION;
|
||||||
|
} else {
|
||||||
|
qDebug() << "EntityItem::addActionInternal -- serializeActions failed";
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
@ -1628,6 +1643,7 @@ void EntityItem::deserializeActionsInternal() {
|
||||||
quint64 now = usecTimestampNow();
|
quint64 now = usecTimestampNow();
|
||||||
|
|
||||||
if (!_element) {
|
if (!_element) {
|
||||||
|
qDebug() << "EntityItem::deserializeActionsInternal -- no _element";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1670,6 +1686,8 @@ void EntityItem::deserializeActionsInternal() {
|
||||||
if (action) {
|
if (action) {
|
||||||
entity->addActionInternal(simulation, action);
|
entity->addActionInternal(simulation, action);
|
||||||
action->locallyAddedButNotYetReceived = false;
|
action->locallyAddedButNotYetReceived = false;
|
||||||
|
} else {
|
||||||
|
qDebug() << "EntityItem::deserializeActionsInternal -- action creation failed";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -409,6 +409,10 @@ public:
|
||||||
void setActionDataDirty(bool value) const { _actionDataDirty = value; }
|
void setActionDataDirty(bool value) const { _actionDataDirty = value; }
|
||||||
bool shouldSuppressLocationEdits() const;
|
bool shouldSuppressLocationEdits() const;
|
||||||
|
|
||||||
|
void setSourceUUID(const QUuid& sourceUUID) { _sourceUUID = sourceUUID; }
|
||||||
|
const QUuid& getSourceUUID() const { return _sourceUUID; }
|
||||||
|
bool matchesSourceUUID(const QUuid& sourceUUID) const { return _sourceUUID == sourceUUID; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
const QByteArray getActionDataInternal() const;
|
const QByteArray getActionDataInternal() const;
|
||||||
|
@ -509,6 +513,8 @@ protected:
|
||||||
// _previouslyDeletedActions is used to avoid an action being re-added due to server round-trip lag
|
// _previouslyDeletedActions is used to avoid an action being re-added due to server round-trip lag
|
||||||
static quint64 _rememberDeletedActionTime;
|
static quint64 _rememberDeletedActionTime;
|
||||||
mutable QHash<QUuid, quint64> _previouslyDeletedActions;
|
mutable QHash<QUuid, quint64> _previouslyDeletedActions;
|
||||||
|
|
||||||
|
QUuid _sourceUUID; /// the server node UUID we came from
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_EntityItem_h
|
#endif // hifi_EntityItem_h
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <glm/gtx/norm.hpp>
|
||||||
|
|
||||||
#include <EntityItem.h>
|
#include <EntityItem.h>
|
||||||
#include <EntityItemProperties.h>
|
#include <EntityItemProperties.h>
|
||||||
#include <EntityEditPacketSender.h>
|
#include <EntityEditPacketSender.h>
|
||||||
|
@ -186,10 +188,8 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) {
|
||||||
measureBodyAcceleration();
|
measureBodyAcceleration();
|
||||||
_entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset());
|
_entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset());
|
||||||
_entity->setRotation(bulletToGLM(worldTrans.getRotation()));
|
_entity->setRotation(bulletToGLM(worldTrans.getRotation()));
|
||||||
|
|
||||||
_entity->setVelocity(getBodyLinearVelocity());
|
_entity->setVelocity(getBodyLinearVelocity());
|
||||||
_entity->setAngularVelocity(getBodyAngularVelocity());
|
_entity->setAngularVelocity(getBodyAngularVelocity());
|
||||||
|
|
||||||
_entity->setLastSimulated(usecTimestampNow());
|
_entity->setLastSimulated(usecTimestampNow());
|
||||||
|
|
||||||
if (_entity->getSimulatorID().isNull()) {
|
if (_entity->getSimulatorID().isNull()) {
|
||||||
|
@ -248,7 +248,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
|
||||||
btTransform xform = _body->getWorldTransform();
|
btTransform xform = _body->getWorldTransform();
|
||||||
_serverPosition = bulletToGLM(xform.getOrigin());
|
_serverPosition = bulletToGLM(xform.getOrigin());
|
||||||
_serverRotation = bulletToGLM(xform.getRotation());
|
_serverRotation = bulletToGLM(xform.getRotation());
|
||||||
_serverVelocity = getBodyLinearVelocity();
|
_serverVelocity = getBodyLinearVelocityGTSigma();
|
||||||
_serverAngularVelocity = bulletToGLM(_body->getAngularVelocity());
|
_serverAngularVelocity = bulletToGLM(_body->getAngularVelocity());
|
||||||
_lastStep = simulationStep;
|
_lastStep = simulationStep;
|
||||||
_serverActionData = _entity->getActionData();
|
_serverActionData = _entity->getActionData();
|
||||||
|
@ -547,7 +547,7 @@ void EntityMotionState::bump(quint8 priority) {
|
||||||
void EntityMotionState::resetMeasuredBodyAcceleration() {
|
void EntityMotionState::resetMeasuredBodyAcceleration() {
|
||||||
_lastMeasureStep = ObjectMotionState::getWorldSimulationStep();
|
_lastMeasureStep = ObjectMotionState::getWorldSimulationStep();
|
||||||
if (_body) {
|
if (_body) {
|
||||||
_lastVelocity = getBodyLinearVelocity();
|
_lastVelocity = getBodyLinearVelocityGTSigma();
|
||||||
} else {
|
} else {
|
||||||
_lastVelocity = glm::vec3(0.0f);
|
_lastVelocity = glm::vec3(0.0f);
|
||||||
}
|
}
|
||||||
|
@ -566,7 +566,8 @@ void EntityMotionState::measureBodyAcceleration() {
|
||||||
|
|
||||||
// Note: the integration equation for velocity uses damping: v1 = (v0 + a * dt) * (1 - D)^dt
|
// Note: the integration equation for velocity uses damping: v1 = (v0 + a * dt) * (1 - D)^dt
|
||||||
// hence the equation for acceleration is: a = (v1 / (1 - D)^dt - v0) / dt
|
// hence the equation for acceleration is: a = (v1 / (1 - D)^dt - v0) / dt
|
||||||
glm::vec3 velocity = getBodyLinearVelocity();
|
glm::vec3 velocity = getBodyLinearVelocityGTSigma();
|
||||||
|
|
||||||
_measuredAcceleration = (velocity / powf(1.0f - _body->getLinearDamping(), dt) - _lastVelocity) * invDt;
|
_measuredAcceleration = (velocity / powf(1.0f - _body->getLinearDamping(), dt) - _lastVelocity) * invDt;
|
||||||
_lastVelocity = velocity;
|
_lastVelocity = velocity;
|
||||||
if (numSubsteps > PHYSICS_ENGINE_MAX_NUM_SUBSTEPS) {
|
if (numSubsteps > PHYSICS_ENGINE_MAX_NUM_SUBSTEPS) {
|
||||||
|
|
|
@ -62,6 +62,22 @@ void ObjectAction::updateAction(btCollisionWorld* collisionWorld, btScalar delta
|
||||||
updateActionWorker(deltaTimeStep);
|
updateActionWorker(deltaTimeStep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ObjectAction::getEntityServerClockSkew() const {
|
||||||
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
|
|
||||||
|
auto ownerEntity = _ownerEntity.lock();
|
||||||
|
if (!ownerEntity) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QUuid& entityServerNodeID = ownerEntity->getSourceUUID();
|
||||||
|
auto entityServerNode = nodeList->nodeWithUUID(entityServerNodeID);
|
||||||
|
if (entityServerNode) {
|
||||||
|
return entityServerNode->getClockSkewUsec();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool ObjectAction::updateArguments(QVariantMap arguments) {
|
bool ObjectAction::updateArguments(QVariantMap arguments) {
|
||||||
bool somethingChanged = false;
|
bool somethingChanged = false;
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,8 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
int getEntityServerClockSkew() const;
|
||||||
|
|
||||||
virtual btRigidBody* getRigidBody();
|
virtual btRigidBody* getRigidBody();
|
||||||
virtual glm::vec3 getPosition();
|
virtual glm::vec3 getPosition();
|
||||||
virtual void setPosition(glm::vec3 position);
|
virtual void setPosition(glm::vec3 position);
|
||||||
|
|
|
@ -160,7 +160,7 @@ QByteArray ObjectActionOffset::serialize() const {
|
||||||
dataStream << _linearDistance;
|
dataStream << _linearDistance;
|
||||||
dataStream << _linearTimeScale;
|
dataStream << _linearTimeScale;
|
||||||
dataStream << _positionalTargetSet;
|
dataStream << _positionalTargetSet;
|
||||||
dataStream << _expires;
|
dataStream << _expires + getEntityServerClockSkew();
|
||||||
dataStream << _tag;
|
dataStream << _tag;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -190,6 +190,7 @@ void ObjectActionOffset::deserialize(QByteArray serializedArguments) {
|
||||||
dataStream >> _linearTimeScale;
|
dataStream >> _linearTimeScale;
|
||||||
dataStream >> _positionalTargetSet;
|
dataStream >> _positionalTargetSet;
|
||||||
dataStream >> _expires;
|
dataStream >> _expires;
|
||||||
|
_expires -= getEntityServerClockSkew();
|
||||||
dataStream >> _tag;
|
dataStream >> _tag;
|
||||||
_active = true;
|
_active = true;
|
||||||
});
|
});
|
||||||
|
|
|
@ -198,7 +198,7 @@ QByteArray ObjectActionSpring::serialize() const {
|
||||||
dataStream << _rotationalTarget;
|
dataStream << _rotationalTarget;
|
||||||
dataStream << _angularTimeScale;
|
dataStream << _angularTimeScale;
|
||||||
dataStream << _rotationalTargetSet;
|
dataStream << _rotationalTargetSet;
|
||||||
dataStream << _expires;
|
dataStream << _expires + getEntityServerClockSkew();
|
||||||
dataStream << _tag;
|
dataStream << _tag;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -233,6 +233,7 @@ void ObjectActionSpring::deserialize(QByteArray serializedArguments) {
|
||||||
dataStream >> _rotationalTargetSet;
|
dataStream >> _rotationalTargetSet;
|
||||||
|
|
||||||
dataStream >> _expires;
|
dataStream >> _expires;
|
||||||
|
_expires -= getEntityServerClockSkew();
|
||||||
dataStream >> _tag;
|
dataStream >> _tag;
|
||||||
|
|
||||||
_active = true;
|
_active = true;
|
||||||
|
|
|
@ -80,17 +80,20 @@ void ObjectMotionState::setBodyGravity(const glm::vec3& gravity) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 ObjectMotionState::getBodyLinearVelocity() const {
|
glm::vec3 ObjectMotionState::getBodyLinearVelocity() const {
|
||||||
// returns the body's velocity unless it is moving too slow in which case returns zero
|
return bulletToGLM(_body->getLinearVelocity());
|
||||||
btVector3 velocity = _body->getLinearVelocity();
|
}
|
||||||
|
|
||||||
|
glm::vec3 ObjectMotionState::getBodyLinearVelocityGTSigma() const {
|
||||||
// NOTE: the threshold to use here relates to the linear displacement threshold (dX) for sending updates
|
// NOTE: the threshold to use here relates to the linear displacement threshold (dX) for sending updates
|
||||||
// to objects that are tracked server-side (e.g. entities which use dX = 2mm). Hence an object moving
|
// to objects that are tracked server-side (e.g. entities which use dX = 2mm). Hence an object moving
|
||||||
// just under this velocity threshold would trigger an update about V/dX times per second.
|
// just under this velocity threshold would trigger an update about V/dX times per second.
|
||||||
const float MIN_LINEAR_SPEED_SQUARED = 0.0036f; // 6 mm/sec
|
const float MIN_LINEAR_SPEED_SQUARED = 0.0036f; // 6 mm/sec
|
||||||
if (velocity.length2() < MIN_LINEAR_SPEED_SQUARED) {
|
|
||||||
|
glm::vec3 velocity = bulletToGLM(_body->getLinearVelocity());
|
||||||
|
if (glm::length2(velocity) < MIN_LINEAR_SPEED_SQUARED) {
|
||||||
velocity *= 0.0f;
|
velocity *= 0.0f;
|
||||||
}
|
}
|
||||||
return bulletToGLM(velocity);
|
return velocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 ObjectMotionState::getObjectLinearVelocityChange() const {
|
glm::vec3 ObjectMotionState::getObjectLinearVelocityChange() const {
|
||||||
|
|
|
@ -89,6 +89,7 @@ public:
|
||||||
void setBodyGravity(const glm::vec3& gravity) const;
|
void setBodyGravity(const glm::vec3& gravity) const;
|
||||||
|
|
||||||
glm::vec3 getBodyLinearVelocity() const;
|
glm::vec3 getBodyLinearVelocity() const;
|
||||||
|
glm::vec3 getBodyLinearVelocityGTSigma() const;
|
||||||
glm::vec3 getBodyAngularVelocity() const;
|
glm::vec3 getBodyAngularVelocity() const;
|
||||||
virtual glm::vec3 getObjectLinearVelocityChange() const;
|
virtual glm::vec3 getObjectLinearVelocityChange() const;
|
||||||
|
|
||||||
|
|
|
@ -1147,6 +1147,8 @@ void Model::segregateMeshGroups() {
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = _geometry->getMeshes();
|
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = _geometry->getMeshes();
|
||||||
|
|
||||||
|
_rig->makeAnimSkeleton(geometry);
|
||||||
|
|
||||||
// all of our mesh vectors must match in size
|
// all of our mesh vectors must match in size
|
||||||
if ((int)networkMeshes.size() != geometry.meshes.size() ||
|
if ((int)networkMeshes.size() != geometry.meshes.size() ||
|
||||||
geometry.meshes.size() != _meshStates.size()) {
|
geometry.meshes.size() != _meshStates.size()) {
|
||||||
|
|
|
@ -198,6 +198,10 @@ public:
|
||||||
return ((index < 0) && (index >= _blendshapeCoefficients.size())) ? 0.0f : _blendshapeCoefficients.at(index);
|
return ((index < 0) && (index >= _blendshapeCoefficients.size())) ? 0.0f : _blendshapeCoefficients.at(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual RigPointer getRig() const { return _rig; }
|
||||||
|
|
||||||
|
const glm::vec3& getRegistrationPoint() const { return _registrationPoint; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void setPupilDilation(float dilation) { _pupilDilation = dilation; }
|
void setPupilDilation(float dilation) { _pupilDilation = dilation; }
|
||||||
|
|
Loading…
Reference in a new issue