mirror of
https://github.com/lubosz/overte.git
synced 2025-08-07 19:21:16 +02:00
Merge pull request #11950 from hyperlogic/bug-fix/hand-scaling
Fix for hand controller avatar scaling.
This commit is contained in:
commit
a7a6dee8e0
8 changed files with 61 additions and 15 deletions
|
@ -114,7 +114,8 @@ MyAvatar::MyAvatar(QThread* thread) :
|
||||||
|
|
||||||
_skeletonModel = std::make_shared<MySkeletonModel>(this, nullptr);
|
_skeletonModel = std::make_shared<MySkeletonModel>(this, nullptr);
|
||||||
connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished);
|
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;
|
using namespace recording;
|
||||||
_skeletonModel->flagAsCauterized();
|
_skeletonModel->flagAsCauterized();
|
||||||
|
|
|
@ -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
|
// 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) {
|
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 {
|
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();
|
return getModelScale() * getUnscaledEyeHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// thread-safe
|
||||||
float Avatar::getUnscaledEyeHeight() const {
|
float Avatar::getUnscaledEyeHeight() const {
|
||||||
|
return _unscaledEyeHeightCache.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Avatar::buildUnscaledEyeHeightCache() {
|
||||||
float skeletonHeight = getUnscaledEyeHeightFromSkeleton();
|
float skeletonHeight = getUnscaledEyeHeightFromSkeleton();
|
||||||
|
|
||||||
// Sanity check by looking at the model extents.
|
// 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.
|
// This helps prevent absurdly large avatars from exceeding the domain height limit.
|
||||||
const float MESH_SLOP_RATIO = 1.5f;
|
const float MESH_SLOP_RATIO = 1.5f;
|
||||||
if (meshHeight > skeletonHeight * MESH_SLOP_RATIO) {
|
if (meshHeight > skeletonHeight * MESH_SLOP_RATIO) {
|
||||||
return meshHeight;
|
_unscaledEyeHeightCache.set(meshHeight);
|
||||||
} else {
|
} else {
|
||||||
return skeletonHeight;
|
_unscaledEyeHeightCache.set(skeletonHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Avatar::clearUnscaledEyeHeightCache() {
|
||||||
|
_unscaledEyeHeightCache.set(DEFAULT_AVATAR_EYE_HEIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
float Avatar::getUnscaledEyeHeightFromSkeleton() const {
|
float Avatar::getUnscaledEyeHeightFromSkeleton() const {
|
||||||
|
|
||||||
// TODO: if performance becomes a concern we can cache this value rather then computing it everytime.
|
// TODO: if performance becomes a concern we can cache this value rather then computing it everytime.
|
||||||
|
|
|
@ -257,8 +257,8 @@ public:
|
||||||
|
|
||||||
Q_INVOKABLE virtual float getEyeHeight() const override;
|
Q_INVOKABLE virtual float getEyeHeight() const override;
|
||||||
|
|
||||||
// returns eye height of avatar in meters, ignoreing avatar scale.
|
// returns eye height of avatar in meters, ignoring avatar scale.
|
||||||
// if _targetScale is 1 then this will be identical to getEyeHeight;
|
// if _targetScale is 1 then this will be identical to getEyeHeight.
|
||||||
virtual float getUnscaledEyeHeight() const override;
|
virtual float getUnscaledEyeHeight() const override;
|
||||||
|
|
||||||
// returns true, if an acurate eye height estimage can be obtained by inspecting the avatar model skeleton and geometry,
|
// 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::vec3 getRightPalmPosition() const;
|
||||||
glm::quat getRightPalmRotation() const;
|
glm::quat getRightPalmRotation() const;
|
||||||
|
|
||||||
|
// hooked up to Model::setURLFinished signal
|
||||||
void setModelURLFinished(bool success);
|
void setModelURLFinished(bool success);
|
||||||
|
|
||||||
|
// hooked up to Model::rigReady & rigReset signals
|
||||||
|
void rigReady();
|
||||||
|
void rigReset();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
float getUnscaledEyeHeightFromSkeleton() const;
|
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.
|
virtual const QString& getSessionDisplayNameForTransport() const override { return _empty; } // Save a tiny bit of bandwidth. Mixer won't look at what we send.
|
||||||
QString _empty{};
|
QString _empty{};
|
||||||
virtual void maybeUpdateSessionDisplayNameFromTransport(const QString& sessionDisplayName) override { _sessionDisplayName = sessionDisplayName; } // don't use no-op setter!
|
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 _displayNameTargetAlpha { 1.0f };
|
||||||
float _displayNameAlpha { 1.0f };
|
float _displayNameAlpha { 1.0f };
|
||||||
|
|
||||||
|
ThreadSafeValueCache<float> _unscaledEyeHeightCache { DEFAULT_AVATAR_EYE_HEIGHT };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_Avatar_h
|
#endif // hifi_Avatar_h
|
||||||
|
|
|
@ -13,4 +13,6 @@ OtherAvatar::OtherAvatar(QThread* thread) : Avatar(thread) {
|
||||||
_headData = new Head(this);
|
_headData = new Head(this);
|
||||||
_skeletonModel = std::make_shared<SkeletonModel>(this, nullptr);
|
_skeletonModel = std::make_shared<SkeletonModel>(this, nullptr);
|
||||||
connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished);
|
connect(_skeletonModel.get(), &Model::setURLFinished, this, &Avatar::setModelURLFinished);
|
||||||
|
connect(_skeletonModel.get(), &Model::rigReady, this, &Avatar::rigReady);
|
||||||
|
connect(_skeletonModel.get(), &Model::rigReset, this, &Avatar::rigReset);
|
||||||
}
|
}
|
||||||
|
|
|
@ -483,8 +483,22 @@ public:
|
||||||
virtual void setTargetScale(float targetScale);
|
virtual void setTargetScale(float targetScale);
|
||||||
|
|
||||||
float getDomainLimitedScale() const;
|
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.
|
// returns eye height of avatar in meters, ignoreing avatar scale.
|
||||||
// if _targetScale is 1 then this will be identical to getEyeHeight;
|
// if _targetScale is 1 then this will be identical to getEyeHeight;
|
||||||
|
|
|
@ -286,6 +286,7 @@ void Model::reset() {
|
||||||
if (isLoaded()) {
|
if (isLoaded()) {
|
||||||
const FBXGeometry& geometry = getFBXGeometry();
|
const FBXGeometry& geometry = getFBXGeometry();
|
||||||
_rig.reset(geometry);
|
_rig.reset(geometry);
|
||||||
|
emit rigReset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,6 +323,7 @@ bool Model::updateGeometry() {
|
||||||
_blendedVertexBuffers.push_back(buffer);
|
_blendedVertexBuffers.push_back(buffer);
|
||||||
}
|
}
|
||||||
needFullUpdate = true;
|
needFullUpdate = true;
|
||||||
|
emit rigReady();
|
||||||
}
|
}
|
||||||
return needFullUpdate;
|
return needFullUpdate;
|
||||||
}
|
}
|
||||||
|
|
|
@ -273,6 +273,8 @@ signals:
|
||||||
void setURLFinished(bool success);
|
void setURLFinished(bool success);
|
||||||
void setCollisionModelURLFinished(bool success);
|
void setCollisionModelURLFinished(bool success);
|
||||||
void requestRenderUpdate();
|
void requestRenderUpdate();
|
||||||
|
void rigReady();
|
||||||
|
void rigReset();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,10 @@
|
||||||
(function () {
|
(function () {
|
||||||
var dispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js");
|
var dispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
|
|
||||||
|
function clamp(val, min, max) {
|
||||||
|
return Math.max(min, Math.min(max, val));
|
||||||
|
}
|
||||||
|
|
||||||
function ScaleAvatar(hand) {
|
function ScaleAvatar(hand) {
|
||||||
this.hand = hand;
|
this.hand = hand;
|
||||||
this.scalingStartAvatarScale = 0;
|
this.scalingStartAvatarScale = 0;
|
||||||
|
@ -61,7 +65,7 @@
|
||||||
controllerData.controllerLocations[this.otherHand()].position));
|
controllerData.controllerLocations[this.otherHand()].position));
|
||||||
|
|
||||||
var newAvatarScale = (scalingCurrentDistance / this.scalingStartDistance) * this.scalingStartAvatarScale;
|
var newAvatarScale = (scalingCurrentDistance / this.scalingStartDistance) * this.scalingStartAvatarScale;
|
||||||
MyAvatar.scale = newAvatarScale;
|
MyAvatar.scale = clamp(newAvatarScale, MyAvatar.getDomainMinScale(), MyAvatar.getDomainMaxScale());
|
||||||
MyAvatar.scaleChanged();
|
MyAvatar.scaleChanged();
|
||||||
}
|
}
|
||||||
return dispatcherUtils.makeRunningValues(true, [], []);
|
return dispatcherUtils.makeRunningValues(true, [], []);
|
||||||
|
|
Loading…
Reference in a new issue