FIRE-30873: first pass at swapping axes for the UI control

master
Angeldark Raymaker 2024-09-12 11:57:13 +01:00
parent 8c010617e6
commit 327bb00c7e
5 changed files with 104 additions and 20 deletions

View File

@ -908,14 +908,6 @@ void FSFloaterPoser::onAvatarPositionSet()
setSelectedJointsPosition(posX, posY, posZ);
}
/// <summary>
/// The trackball controller is not friendly to photographers (or normal people).
/// This method could be streamlined but at the high cost of picking apart what it does.
/// The simplest thing to do would be to reimplement the code behind the slider!
/// TLDR: we just want the trackball to behave like a 2-axis slider.
///
/// BEWARE! Changes to behaviour here require their inverse to be applied on the slider-callback.
/// </summary>
void FSFloaterPoser::onLimbTrackballChanged()
{
FSVirtualTrackpad *trackBall = getChild<FSVirtualTrackpad>(POSER_AVATAR_TRACKBALL_NAME);

View File

@ -99,7 +99,34 @@ LLVector3 FSPoserAnimator::getJointRotation(LLVOAvatar *avatar, FSPoserJoint joi
return vec3;
LLQuaternion rot = avJoint->getRotation();
rot.getEulerAngles(&vec3.mV[VX], &vec3.mV[VZ], &vec3.mV[VY]);
return translateRotationFromQuaternion(joint.boneTranslation(), rot);
}
// from the bone to the UI; this is the 'forwards' use of the enum
LLVector3 FSPoserAnimator::translateRotationFromQuaternion(E_BoneAxisTranslation translation, LLQuaternion rotation)
{
LLVector3 vec3;
switch (translation)
{
case SWAP_YAW_AND_ROLL:
rotation.getEulerAngles(&vec3.mV[VY], &vec3.mV[VZ], &vec3.mV[VX]);
break;
case SWAP_YAW_AND_PITCH:
rotation.getEulerAngles(&vec3.mV[VZ], &vec3.mV[VX], &vec3.mV[VY]);
break;
case SWAP_ROLL_AND_PITCH:
rotation.getEulerAngles(&vec3.mV[VX], &vec3.mV[VY], &vec3.mV[VZ]);
break;
case SWAP_NOTHING:
default:
rotation.getEulerAngles(&vec3.mV[VX], &vec3.mV[VZ], &vec3.mV[VY]);
break;
}
return vec3;
}
@ -115,10 +142,38 @@ void FSPoserAnimator::setJointRotation(LLVOAvatar *avatar, const FSPoserJoint *j
if (!avJoint)
return;
LLMatrix3 rot_mat = LLMatrix3(rotation.mV[VX], rotation.mV[VY], rotation.mV[VZ]);
LLQuaternion rot_quat = translateRotationToQuaternion(joint->boneTranslation(), rotation);
avJoint->setRotation(rot_quat);
}
// from the UI to the bone, the inverse translation, the un-swap, the backwards
LLQuaternion FSPoserAnimator::translateRotationToQuaternion(E_BoneAxisTranslation translation, LLVector3 rotation)
{
LLMatrix3 rot_mat;
switch (translation)
{
case SWAP_YAW_AND_ROLL:
rot_mat = LLMatrix3(rotation.mV[VZ], rotation.mV[VY], -1 * rotation.mV[VX]);
break;
case SWAP_YAW_AND_PITCH:
rot_mat = LLMatrix3(rotation.mV[VY], rotation.mV[VX], rotation.mV[VZ]);
break;
case SWAP_ROLL_AND_PITCH:
rot_mat = LLMatrix3(rotation.mV[VX], rotation.mV[VZ], rotation.mV[VY]);
break;
case SWAP_NOTHING:
default:
rot_mat = LLMatrix3(rotation.mV[VX], rotation.mV[VY], rotation.mV[VZ]);
break;
}
LLQuaternion rot_quat;
rot_quat = LLQuaternion(rot_mat) * rot_quat;
avJoint->setRotation(rot_quat);
return rot_quat;
}
LLVector3 FSPoserAnimator::getJointScale(LLVOAvatar *avatar, FSPoserJoint joint)

View File

@ -58,6 +58,20 @@ typedef enum E_BoneDeflectionStyles
SYMPATHETIC = 2, // change the other joint, but opposite to a mirrored way, eg: both go right or both go left
} E_BoneDeflectionStyles;
/// <summary>
/// When we're going from bone-rotation to the UI sliders, some of the axes need swapping so they make sense in UI-terms.
/// eg: for one bone, the X-axis may mean up and down, but for another bone, the x-axis might be left-right.
/// These are translations of bone-TO-UI; an inverse translation needs to happen the other way.
/// It would be nice if these were defined in XML; but then they're not const, and I want const.
/// </summary>
typedef enum E_BoneAxisTranslation
{
SWAP_NOTHING = 0,
SWAP_YAW_AND_ROLL = 1,
SWAP_YAW_AND_PITCH = 2,
SWAP_ROLL_AND_PITCH = 3,
} E_BoneAxisTranslation;
class FSPoserAnimator
{
public:
@ -73,6 +87,7 @@ public:
std::string _jointName; // expected to be a match to LLJoint.getName() for a joint implementation.
std::string _mirrorJointName;
E_BoneTypes _boneList;
E_BoneAxisTranslation _boneTranslation;
public:
/// <summary>
/// Gets the name of the joint.
@ -89,6 +104,11 @@ public:
/// </summary>
E_BoneTypes boneType() const { return _boneList; }
/// <summary>
/// Gets the E_BoneAxisTranslation of the joint.
/// </summary>
E_BoneAxisTranslation boneTranslation() const { return _boneTranslation; }
/// <summary>
/// Creates a new instance of a PoserJoint.
/// </summary>
@ -99,11 +119,12 @@ public:
/// </param>
/// <param name="b">The opposite joint name, if any. Also expected to be a well-known name.</param>
/// <param name="c">The </param>
FSPoserJoint(std::string a, std::string b, E_BoneTypes c)
FSPoserJoint(std::string a, std::string b, E_BoneTypes c, E_BoneAxisTranslation d = SWAP_NOTHING)
{
_jointName = a;
_mirrorJointName = b;
_boneList = c;
_boneTranslation = d;
}
};
@ -122,7 +143,7 @@ public:
/// </remarks>
const std::vector<FSPoserJoint> PoserJoints {
// head, torso, legs
{"mPelvis", "", WHOLEAVATAR}, {"mTorso", "", BODY}, {"mChest", "", BODY}, {"mNeck", "", BODY}, {"mHead", "", BODY},
{"mPelvis", "", WHOLEAVATAR}, {"mTorso", "", BODY, SWAP_YAW_AND_ROLL}, {"mChest", "", BODY}, {"mNeck", "", BODY}, {"mHead", "", BODY},
{"mCollarLeft", "mCollarRight", BODY}, {"mShoulderLeft", "mShoulderRight", BODY}, {"mElbowLeft", "mElbowRight", BODY}, {"mWristLeft", "mWristRight", BODY},
{"mCollarRight", "mCollarLeft", BODY}, {"mShoulderRight", "mShoulderLeft", BODY}, {"mElbowRight", "mElbowLeft", BODY}, {"mWristRight", "mWristLeft", BODY},
{"mHipLeft", "", BODY}, {"mKneeLeft", "", BODY}, {"mAnkleLeft", "", BODY},
@ -269,6 +290,23 @@ public:
private:
bool _currentlyPosingSelf = false;
/// <summary>
/// Translates a rotation vector from the UI to a Quaternion for the bone.
/// This also performs the axis-swapping the UI needs for up/down/left/right to make sense.
/// </summary>
/// <param name="translation">The axis translation to perform.</param>
/// <param name="rotation">The rotation to transform to quaternion.</param>
/// <returns>The rotation quaternion.</returns>
LLQuaternion translateRotationToQuaternion(E_BoneAxisTranslation translation, LLVector3 rotation);
/// <summary>
/// Translates a bone-rotation quaternion to a vector usable easily on the UI.
/// </summary>
/// <param name="translation">The axis translation to perform.</param>
/// <param name="rotation">The rotation to transform to matrix.</param>
/// <returns>The rotation vector.</returns>
LLVector3 translateRotationFromQuaternion(E_BoneAxisTranslation translation, LLQuaternion rotation);
// public:
// static LLMotion *create(const LLUUID &id) { return new FSPoserAnimator(id); }

View File

@ -43,7 +43,6 @@ public:
Optional<LLViewBorder::Params> border;
Optional<LLUIImage *> image_moon_back, image_moon_front, image_sphere, image_sun_back, image_sun_front;
Optional<bool> pinch_mode;
Optional<bool> allow_drag_outside;
Params();
};

View File

@ -594,10 +594,10 @@ width="565">
left_delta="0"
top_pad="2"
width="200">Up/Down:</text>
<slider decimal_digits="0"
<slider decimal_digits="1"
follows="left|top"
height="16"
increment="1"
increment="0.1"
initial_value="0"
layout="topleft"
left_delta="5"
@ -614,10 +614,10 @@ width="565">
left_delta="-5"
top_pad="0"
width="200">Left/Right:</text>
<slider decimal_digits="0"
<slider decimal_digits="1"
follows="left|top"
height="16"
increment="1"
increment="0.1"
initial_value="0"
layout="topleft"
left_delta="5"
@ -634,10 +634,10 @@ width="565">
left_delta="-5"
top_pad="-1"
width="200">Roll:</text>
<slider decimal_digits="0"
<slider decimal_digits="1"
follows="left|top"
height="16"
increment="1"
increment="0.1"
initial_value="0"
layout="topleft"
left_delta="5"