Merge pull request #11950 from hyperlogic/bug-fix/hand-scaling

Fix for hand controller avatar scaling.
This commit is contained in:
Seth Alves 2017-12-08 07:17:59 -08:00 committed by GitHub
commit a7a6dee8e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 61 additions and 15 deletions

View file

@ -114,7 +114,8 @@ MyAvatar::MyAvatar(QThread* thread) :
_skeletonModel = std::make_shared<MySkeletonModel>(this, nullptr);
connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished);
connect(_skeletonModel.get(), &Model::rigReady, this, &Avatar::rigReady);
connect(_skeletonModel.get(), &Model::rigReset, this, &Avatar::rigReset);
using namespace recording;
_skeletonModel->flagAsCauterized();

View file

@ -1217,6 +1217,15 @@ void Avatar::setModelURLFinished(bool success) {
}
}
// rig is ready
void Avatar::rigReady() {
buildUnscaledEyeHeightCache();
}
// rig has been reset.
void Avatar::rigReset() {
clearUnscaledEyeHeightCache();
}
// create new model, can return an instance of a SoftAttachmentModel rather then Model
static std::shared_ptr<Model> allocateAttachmentModel(bool isSoft, const Rig& rigOverride, bool isCauterized) {
@ -1584,18 +1593,17 @@ void Avatar::ensureInScene(AvatarSharedPointer self, const render::ScenePointer&
}
}
// thread-safe
float Avatar::getEyeHeight() const {
if (QThread::currentThread() != thread()) {
float result = DEFAULT_AVATAR_EYE_HEIGHT;
BLOCKING_INVOKE_METHOD(const_cast<Avatar*>(this), "getEyeHeight", Q_RETURN_ARG(float, result));
return result;
}
return getModelScale() * getUnscaledEyeHeight();
}
// thread-safe
float Avatar::getUnscaledEyeHeight() const {
return _unscaledEyeHeightCache.get();
}
void Avatar::buildUnscaledEyeHeightCache() {
float skeletonHeight = getUnscaledEyeHeightFromSkeleton();
// Sanity check by looking at the model extents.
@ -1606,12 +1614,16 @@ float Avatar::getUnscaledEyeHeight() const {
// This helps prevent absurdly large avatars from exceeding the domain height limit.
const float MESH_SLOP_RATIO = 1.5f;
if (meshHeight > skeletonHeight * MESH_SLOP_RATIO) {
return meshHeight;
_unscaledEyeHeightCache.set(meshHeight);
} else {
return skeletonHeight;
_unscaledEyeHeightCache.set(skeletonHeight);
}
}
void Avatar::clearUnscaledEyeHeightCache() {
_unscaledEyeHeightCache.set(DEFAULT_AVATAR_EYE_HEIGHT);
}
float Avatar::getUnscaledEyeHeightFromSkeleton() const {
// TODO: if performance becomes a concern we can cache this value rather then computing it everytime.

View file

@ -257,8 +257,8 @@ public:
Q_INVOKABLE virtual float getEyeHeight() const override;
// returns eye height of avatar in meters, ignoreing avatar scale.
// if _targetScale is 1 then this will be identical to getEyeHeight;
// returns eye height of avatar in meters, ignoring avatar scale.
// if _targetScale is 1 then this will be identical to getEyeHeight.
virtual float getUnscaledEyeHeight() const override;
// returns true, if an acurate eye height estimage can be obtained by inspecting the avatar model skeleton and geometry,
@ -280,10 +280,17 @@ public slots:
glm::vec3 getRightPalmPosition() const;
glm::quat getRightPalmRotation() const;
// hooked up to Model::setURLFinished signal
void setModelURLFinished(bool success);
// hooked up to Model::rigReady & rigReset signals
void rigReady();
void rigReset();
protected:
float getUnscaledEyeHeightFromSkeleton() const;
void buildUnscaledEyeHeightCache();
void clearUnscaledEyeHeightCache();
virtual const QString& getSessionDisplayNameForTransport() const override { return _empty; } // Save a tiny bit of bandwidth. Mixer won't look at what we send.
QString _empty{};
virtual void maybeUpdateSessionDisplayNameFromTransport(const QString& sessionDisplayName) override { _sessionDisplayName = sessionDisplayName; } // don't use no-op setter!
@ -384,6 +391,8 @@ protected:
float _displayNameTargetAlpha { 1.0f };
float _displayNameAlpha { 1.0f };
ThreadSafeValueCache<float> _unscaledEyeHeightCache { DEFAULT_AVATAR_EYE_HEIGHT };
};
#endif // hifi_Avatar_h

View file

@ -13,4 +13,6 @@ OtherAvatar::OtherAvatar(QThread* thread) : Avatar(thread) {
_headData = new Head(this);
_skeletonModel = std::make_shared<SkeletonModel>(this, nullptr);
connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished);
connect(_skeletonModel.get(), &Model::rigReady, this, &Avatar::rigReady);
connect(_skeletonModel.get(), &Model::rigReset, this, &Avatar::rigReset);
}

View file

@ -483,8 +483,22 @@ public:
virtual void setTargetScale(float targetScale);
float getDomainLimitedScale() const;
float getDomainMinScale() const;
float getDomainMaxScale() const;
/**jsdoc
* returns the minimum scale allowed for this avatar in the current domain.
* This value can change as the user changes avatars or when changing domains.
* @function AvatarData.getDomainMinScale
* @returns {number} minimum scale allowed for this avatar in the current domain.
*/
Q_INVOKABLE float getDomainMinScale() const;
/**jsdoc
* returns the maximum scale allowed for this avatar in the current domain.
* This value can change as the user changes avatars or when changing domains.
* @function AvatarData.getDomainMaxScale
* @returns {number} maximum scale allowed for this avatar in the current domain.
*/
Q_INVOKABLE float getDomainMaxScale() const;
// returns eye height of avatar in meters, ignoreing avatar scale.
// if _targetScale is 1 then this will be identical to getEyeHeight;

View file

@ -286,6 +286,7 @@ void Model::reset() {
if (isLoaded()) {
const FBXGeometry& geometry = getFBXGeometry();
_rig.reset(geometry);
emit rigReset();
}
}
@ -322,6 +323,7 @@ bool Model::updateGeometry() {
_blendedVertexBuffers.push_back(buffer);
}
needFullUpdate = true;
emit rigReady();
}
return needFullUpdate;
}

View file

@ -273,6 +273,8 @@ signals:
void setURLFinished(bool success);
void setCollisionModelURLFinished(bool success);
void requestRenderUpdate();
void rigReady();
void rigReset();
protected:

View file

@ -12,6 +12,10 @@
(function () {
var dispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js");
function clamp(val, min, max) {
return Math.max(min, Math.min(max, val));
}
function ScaleAvatar(hand) {
this.hand = hand;
this.scalingStartAvatarScale = 0;
@ -61,7 +65,7 @@
controllerData.controllerLocations[this.otherHand()].position));
var newAvatarScale = (scalingCurrentDistance / this.scalingStartDistance) * this.scalingStartAvatarScale;
MyAvatar.scale = newAvatarScale;
MyAvatar.scale = clamp(newAvatarScale, MyAvatar.getDomainMinScale(), MyAvatar.getDomainMaxScale());
MyAvatar.scaleChanged();
}
return dispatcherUtils.makeRunningValues(true, [], []);