FIRE-35686: Update BVH save state
- add optional unlock for mPelvis (for partial-pose BVH) - add settings option for mPelvis BVH lock state - T-pose now only BVH locks Body tab; face and hands are now BVH-unlocked by defaultmaster
parent
d92e78ccc0
commit
743aca7ee4
|
|
@ -8100,6 +8100,17 @@
|
|||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSPoserPelvisUnlockedForBvhSave</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Whether the mPelvis joint should be position/rotationally locked when a BVH is created.</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
<string>Boolean</string>
|
||||
<key>Value</key>
|
||||
<integer>0</integer>
|
||||
</map>
|
||||
<key>FSPoserOnSaveConfirmOverwrite</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ constexpr std::string_view POSER_TRACKPAD_SENSITIVITY_SAVE_KEY = "FSPoserTrackpa
|
|||
constexpr std::string_view POSER_STOPPOSINGWHENCLOSED_SAVE_KEY = "FSPoserStopPosingWhenClosed";
|
||||
constexpr std::string_view POSER_SAVEEXTERNALFORMAT_SAVE_KEY = "FSPoserSaveExternalFileAlso";
|
||||
constexpr std::string_view POSER_SAVECONFIRMREQUIRED_SAVE_KEY = "FSPoserOnSaveConfirmOverwrite";
|
||||
constexpr std::string_view POSER_UNLOCKPELVISINBVH_SAVE_KEY = "FSPoserPelvisUnlockedForBvhSave";
|
||||
constexpr char ICON_SAVE_OK[] = "icon_rotation_is_own_work";
|
||||
constexpr char ICON_SAVE_FAILED[] = "icon_save_failed_button";
|
||||
|
||||
|
|
@ -212,6 +213,8 @@ bool FSFloaterPoser::postBuild()
|
|||
mMiscJointsPnl = getChild<LLPanel>("misc_joints_panel");
|
||||
mCollisionVolumesPnl = getChild<LLPanel>("collision_volumes_panel");
|
||||
|
||||
mUnlockPelvisInBvhSaveCbx = getChild<LLCheckBoxCtrl>("unlock_pelvis_for_bvh_save_checkbox");
|
||||
mUnlockPelvisInBvhSaveCbx->setVisible(getSavingToBvh());
|
||||
mAlsoSaveBvhCbx = getChild<LLCheckBoxCtrl>("also_save_bvh_checkbox");
|
||||
mAlsoSaveBvhCbx->setCommitCallback([this](LLUICtrl*, const LLSD&) { onClickSavingToBvh(); });
|
||||
|
||||
|
|
@ -2587,7 +2590,9 @@ void FSFloaterPoser::writeBvhMotion(llofstream* fileStream, LLVOAvatar* avatar,
|
|||
if (!joint)
|
||||
return;
|
||||
|
||||
auto rotation = mPoserAnimator.getJointExportRotation(avatar, *joint);
|
||||
bool lockPelvisJoint = gSavedSettings.getBOOL(POSER_UNLOCKPELVISINBVH_SAVE_KEY);
|
||||
|
||||
auto rotation = mPoserAnimator.getJointExportRotation(avatar, *joint, !lockPelvisJoint);
|
||||
auto position = mPoserAnimator.getJointPosition(avatar, *joint);
|
||||
|
||||
switch (joint->boneType())
|
||||
|
|
@ -2684,7 +2689,11 @@ bool FSFloaterPoser::getSavingToBvh()
|
|||
return gSavedSettings.getBOOL(POSER_SAVEEXTERNALFORMAT_SAVE_KEY);
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onClickSavingToBvh() { refreshTextHighlightingOnJointScrollLists(); }
|
||||
void FSFloaterPoser::onClickSavingToBvh()
|
||||
{
|
||||
mUnlockPelvisInBvhSaveCbx->setVisible(getSavingToBvh());
|
||||
refreshTextHighlightingOnJointScrollLists();
|
||||
}
|
||||
|
||||
void FSFloaterPoser::onClickLockWorldRotBtn()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -513,6 +513,7 @@ public:
|
|||
LLPanel* mPosesLoadSavePnl{ nullptr };
|
||||
|
||||
LLCheckBoxCtrl* mAlsoSaveBvhCbx{ nullptr };
|
||||
LLCheckBoxCtrl* mUnlockPelvisInBvhSaveCbx{ nullptr };
|
||||
|
||||
LLUICtrl* mTrackpadSensitivitySpnr{ nullptr };
|
||||
LLUICtrl* mYawSpnr{ nullptr };
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ void FSJointPose::setPublicRotation(bool zeroBase, const LLQuaternion& rot)
|
|||
addStateToUndo(FSJointState(mCurrentState));
|
||||
|
||||
if (zeroBase)
|
||||
zeroBaseRotation();
|
||||
zeroBaseRotation(true);
|
||||
|
||||
mCurrentState.mRotation.set(rot);
|
||||
}
|
||||
|
|
@ -208,12 +208,13 @@ void FSJointPose::reflectRotation()
|
|||
mCurrentState.reflectRotation();
|
||||
}
|
||||
|
||||
void FSJointPose::zeroBaseRotation()
|
||||
void FSJointPose::zeroBaseRotation(bool lockInBvh)
|
||||
{
|
||||
if (mIsCollisionVolume)
|
||||
return;
|
||||
|
||||
mCurrentState.zeroBaseRotation();
|
||||
mCurrentState.mUserSpecifiedBaseZero = lockInBvh;
|
||||
}
|
||||
|
||||
bool FSJointPose::isBaseRotationZero() const
|
||||
|
|
@ -233,12 +234,12 @@ void FSJointPose::purgeUndoQueue()
|
|||
mLastSetJointStates.clear();
|
||||
}
|
||||
|
||||
bool FSJointPose::userHaseSetBaseRotationToZero() const
|
||||
bool FSJointPose::userHasSetBaseRotationToZero() const
|
||||
{
|
||||
if (mIsCollisionVolume)
|
||||
return false;
|
||||
|
||||
return mCurrentState.userSetBaseRotationToZero();
|
||||
return mCurrentState.mUserSpecifiedBaseZero;
|
||||
}
|
||||
|
||||
bool FSJointPose::getWorldRotationLockState() const
|
||||
|
|
|
|||
|
|
@ -107,7 +107,8 @@ class FSJointPose
|
|||
/// <summary>
|
||||
/// Sets the private rotation of the represented joint to zero.
|
||||
/// </summary>
|
||||
void zeroBaseRotation();
|
||||
/// <param name="lockInBvh">Whether the joint should be locked if exported to BVH.</param>
|
||||
void zeroBaseRotation(bool lockInBvh);
|
||||
|
||||
/// <summary>
|
||||
/// Queries whether the represented joint is zero.
|
||||
|
|
@ -173,7 +174,7 @@ class FSJointPose
|
|||
/// Gets whether the user has specified the base rotation of a joint to be zero.
|
||||
/// </summary>
|
||||
/// <returns>True if the user performed some action to specify zero rotation as the base, otherwise false.</returns>
|
||||
bool userHaseSetBaseRotationToZero() const;
|
||||
bool userHasSetBaseRotationToZero() const;
|
||||
|
||||
/// <summary>
|
||||
/// Gets whether the rotation of a joint has been 'locked' so that its world rotation can remain constant while parent joints change.
|
||||
|
|
@ -230,11 +231,9 @@ class FSJointPose
|
|||
{
|
||||
mBaseRotation.set(otherState.mBaseRotation);
|
||||
mRotation.set(otherState.mRotation);
|
||||
mUserSpecifiedBaseZero = otherState.userSetBaseRotationToZero();
|
||||
mUserSpecifiedBaseZero = otherState.mUserSpecifiedBaseZero;
|
||||
}
|
||||
|
||||
bool userSetBaseRotationToZero() const { return mUserSpecifiedBaseZero; }
|
||||
|
||||
bool baseRotationIsZero() const { return mBaseRotation == LLQuaternion::DEFAULT; }
|
||||
|
||||
void resetJoint()
|
||||
|
|
@ -247,11 +246,7 @@ class FSJointPose
|
|||
mScale.setZero();
|
||||
}
|
||||
|
||||
void zeroBaseRotation()
|
||||
{
|
||||
mBaseRotation = LLQuaternion::DEFAULT;
|
||||
mUserSpecifiedBaseZero = true;
|
||||
}
|
||||
void zeroBaseRotation() { mBaseRotation = LLQuaternion::DEFAULT; }
|
||||
|
||||
void revertJointToBase(LLJoint* joint) const
|
||||
{
|
||||
|
|
@ -294,7 +289,7 @@ class FSJointPose
|
|||
mRotation.set(state->mRotation);
|
||||
mPosition.set(state->mPosition);
|
||||
mScale.set(state->mScale);
|
||||
mUserSpecifiedBaseZero = state->userSetBaseRotationToZero();
|
||||
mUserSpecifiedBaseZero = state->mUserSpecifiedBaseZero;
|
||||
mRotationIsWorldLocked = state->mRotationIsWorldLocked;
|
||||
}
|
||||
|
||||
|
|
@ -304,12 +299,22 @@ class FSJointPose
|
|||
LLVector3 mScale;
|
||||
bool mRotationIsWorldLocked = false;
|
||||
|
||||
/// <summary>
|
||||
/// A value indicating whether the user has explicitly set the base rotation to zero.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The base-rotation, representing any 'current animation' state when posing starts, may become zero for several reasons.
|
||||
/// Loading a Pose, editing a rotation intended to save to BVH, or setting to 'T-Pose' being examples.
|
||||
/// If a user intends on creating a BVH, zero-rotation has a special meaning upon upload: the joint is free (is not animated by that BVH).
|
||||
/// This value represents the explicit intent to have that joint be 'free' in BVH (which is sometimes undesireable).
|
||||
/// </remarks>
|
||||
bool mUserSpecifiedBaseZero = false;
|
||||
|
||||
private:
|
||||
LLQuaternion mStartingRotation;
|
||||
LLQuaternion mBaseRotation;
|
||||
LLVector3 mBasePosition;
|
||||
LLVector3 mBaseScale;
|
||||
bool mUserSpecifiedBaseZero = false;
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -318,7 +318,7 @@ bool FSPoserAnimator::exportRotationWillLockJoint(LLVOAvatar* avatar, const FSPo
|
|||
if (!jointPose)
|
||||
return false;
|
||||
|
||||
if (!jointPose->userHaseSetBaseRotationToZero())
|
||||
if (!jointPose->userHasSetBaseRotationToZero())
|
||||
return false;
|
||||
|
||||
F32 rot_threshold = ROTATION_KEYFRAME_THRESHOLD / llmax((F32)getChildJointDepth(&joint, 0) * 0.33f, 1.f);
|
||||
|
|
@ -344,7 +344,7 @@ bool FSPoserAnimator::userSetBaseRotationToZero(LLVOAvatar* avatar, const FSPose
|
|||
if (!jointPose)
|
||||
return false;
|
||||
|
||||
return jointPose->userHaseSetBaseRotationToZero();
|
||||
return jointPose->userHasSetBaseRotationToZero();
|
||||
}
|
||||
|
||||
bool FSPoserAnimator::allBaseRotationsAreZero(LLVOAvatar* avatar) const
|
||||
|
|
@ -373,6 +373,21 @@ void FSPoserAnimator::setAllAvatarStartingRotationsToZero(LLVOAvatar* avatar)
|
|||
return;
|
||||
|
||||
posingMotion->setAllRotationsToZeroAndClearUndo();
|
||||
|
||||
for (size_t index = 0; index != PoserJoints.size(); ++index)
|
||||
{
|
||||
auto boneType = PoserJoints[index].boneType();
|
||||
bool setBvhToLock = boneType == BODY || boneType == WHOLEAVATAR;
|
||||
if (setBvhToLock)
|
||||
continue; // setAllRotationsToZeroAndClearUndo specified this is the default behaviour
|
||||
|
||||
FSJointPose* jointPose = posingMotion->getJointPoseByJointName(PoserJoints[index].jointName());
|
||||
if (!jointPose)
|
||||
continue;
|
||||
|
||||
posingMotion->setJointBvhLock(jointPose, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FSPoserAnimator::recaptureJoint(LLVOAvatar* avatar, const FSPoserJoint& joint, E_BoneAxisTranslation translation, S32 negation)
|
||||
|
|
@ -434,7 +449,7 @@ void FSPoserAnimator::recaptureJointAsDelta(LLVOAvatar* avatar, const FSPoserJoi
|
|||
}
|
||||
}
|
||||
|
||||
LLVector3 FSPoserAnimator::getJointExportRotation(LLVOAvatar* avatar, const FSPoserJoint& joint) const
|
||||
LLVector3 FSPoserAnimator::getJointExportRotation(LLVOAvatar* avatar, const FSPoserJoint& joint, bool lockWholeAvatar) const
|
||||
{
|
||||
auto rotation = getJointRotation(avatar, joint, SWAP_NOTHING, NEGATE_NOTHING);
|
||||
if (exportRotationWillLockJoint(avatar, joint))
|
||||
|
|
@ -452,10 +467,10 @@ LLVector3 FSPoserAnimator::getJointExportRotation(LLVOAvatar* avatar, const FSPo
|
|||
if (!jointPose)
|
||||
return vec3;
|
||||
|
||||
if (!jointPose->userHaseSetBaseRotationToZero())
|
||||
if (!jointPose->userHasSetBaseRotationToZero())
|
||||
return vec3;
|
||||
|
||||
if (joint.boneType() == WHOLEAVATAR)
|
||||
if (lockWholeAvatar && joint.boneType() == WHOLEAVATAR)
|
||||
return LLVector3(DEG_TO_RAD * 0.295f, 0.f, 0.f);
|
||||
|
||||
F32 minimumRotation = DEG_TO_RAD * 0.65f / llmax((F32)getChildJointDepth(&joint, 0) * 0.33f, 1.f);
|
||||
|
|
|
|||
|
|
@ -497,12 +497,13 @@ public:
|
|||
/// </summary>
|
||||
/// <param name="avatar">The avatar whose joint is being queried.</param>
|
||||
/// <param name="joint">The joint to determine the rotation for.</param>
|
||||
/// <param name="lockWholeAvatar">Whether the whole avatar should be rotation/position locked in the BVH export.</param>
|
||||
/// <returns>The rotation of the requested joint for export.</returns>
|
||||
/// <remarks>
|
||||
/// The BVH export format requires some minimal amount of rotation so it animates the joint on upload.
|
||||
/// The WHOLEAVATAR joint (mPelvis) never exports as 'free'.
|
||||
/// </remarks>
|
||||
LLVector3 getJointExportRotation(LLVOAvatar* avatar, const FSPoserJoint& joint) const;
|
||||
LLVector3 getJointExportRotation(LLVOAvatar* avatar, const FSPoserJoint& joint, bool lockWholeAvatar) const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the rotation of a joint for the supplied avatar.
|
||||
|
|
|
|||
|
|
@ -264,6 +264,11 @@ void FSPosingMotion::setAllRotationsToZeroAndClearUndo()
|
|||
}
|
||||
}
|
||||
|
||||
void FSPosingMotion::setJointBvhLock(FSJointPose* joint, bool lockInBvh)
|
||||
{
|
||||
joint->zeroBaseRotation(lockInBvh);
|
||||
}
|
||||
|
||||
bool FSPosingMotion::vectorsNotQuiteEqual(LLVector3 v1, LLVector3 v2) const
|
||||
{
|
||||
if (vectorAxesAlmostEqual(v1.mV[VX], v2.mV[VX]) &&
|
||||
|
|
|
|||
|
|
@ -121,8 +121,17 @@ public:
|
|||
/// <summary>
|
||||
/// Sets all of the non-Collision Volume base-and-delta rotations to zero, and clears the undo/redo queue.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// By default, sets the joint to lock in BVH export.
|
||||
/// </remarks>
|
||||
void setAllRotationsToZeroAndClearUndo();
|
||||
|
||||
/// <summary>
|
||||
/// Sets the BVH export state for the supplied joint.
|
||||
/// </summary>
|
||||
/// <param name="lockInBvh">Whether the joint should be locked if exported to BVH.</param>
|
||||
void setJointBvhLock(FSJointPose* joint, bool lockInBvh);
|
||||
|
||||
private:
|
||||
/// <summary>
|
||||
/// The axial difference considered close enough to be the same.
|
||||
|
|
|
|||
|
|
@ -553,6 +553,17 @@ width="430">
|
|||
function="Poser.CommitSpinner"
|
||||
parameter="2"/>
|
||||
</spinner>
|
||||
<check_box
|
||||
control_name="FSPoserPelvisUnlockedForBvhSave"
|
||||
name="unlock_pelvis_for_bvh_save_checkbox"
|
||||
visible="false"
|
||||
height="16"
|
||||
label="Unlock Pelvis in BVH"
|
||||
follows="left|top"
|
||||
left="5"
|
||||
tool_tip="When you save this pose to BVH, the Pelvis will not be 'locked', meaning your pose could move in-world."
|
||||
top_pad="15"
|
||||
width="134" />
|
||||
<!-- to make this panel behaves like the others in code-behind, it has an invisible list -->
|
||||
<scroll_list
|
||||
visible="false"
|
||||
|
|
|
|||
Loading…
Reference in New Issue