mirror of
https://github.com/AleziaKurdis/overte.git
synced 2025-08-22 15:46:25 +02:00
WL21317
New MyAvatar functions to support converting from avatar joint space to world space and vice versa. Added some tests to support these functions.
This commit is contained in:
parent
efe72e1b85
commit
6edc6b2756
4 changed files with 383 additions and 0 deletions
|
@ -773,6 +773,115 @@ controller::Pose MyAvatar::getRightHandTipPose() const {
|
|||
return pose;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//:1P: conversion functions for world-space to avatar-space or vice versa
|
||||
glm::vec3 MyAvatar::worldToAvatarPoint(const glm::vec3& position, const int jointIndex) const
|
||||
{
|
||||
glm::vec3 jointPos = getPosition();//default value if no or invalid joint specified
|
||||
glm::quat jointRot = getRotation();//default value if no or invalid joint specified
|
||||
if (jointIndex != -1)
|
||||
{
|
||||
if (!_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPos))
|
||||
{
|
||||
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||
}
|
||||
if (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))
|
||||
{
|
||||
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||
}
|
||||
}
|
||||
glm::vec3 modelOffset = position - jointPos;
|
||||
glm::vec3 modelPosition = glm::inverse(jointRot) * modelOffset;
|
||||
|
||||
return modelPosition;
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::worldToAvatarDirection(const glm::vec3& worldDir, const int jointIndex) const
|
||||
{
|
||||
glm::quat jointRot = getRotation();//default value if no or invalid joint specified
|
||||
if (jointIndex != -1)
|
||||
{
|
||||
if (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))
|
||||
{
|
||||
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 avatarDir = glm::inverse(jointRot) * worldDir;
|
||||
return avatarDir;
|
||||
}
|
||||
|
||||
glm::quat MyAvatar::worldToAvatarRotation(const glm::quat& worldRot, const int jointIndex) const
|
||||
{
|
||||
glm::quat jointRot = getRotation();//default value if no or invalid joint specified
|
||||
if (jointIndex != -1)
|
||||
{
|
||||
if (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))
|
||||
{
|
||||
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||
}
|
||||
}
|
||||
glm::quat avatarRot = glm::inverse(jointRot) * worldRot;
|
||||
return avatarRot;
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::avatarToWorldPoint(const glm::vec3& avatarPos, const int jointIndex) const
|
||||
{
|
||||
glm::vec3 jointPos = getPosition();//default value if no or invalid joint specified
|
||||
glm::quat jointRot = getRotation();//default value if no or invalid joint specified
|
||||
|
||||
if (jointIndex != -1)
|
||||
{
|
||||
if (!_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPos))
|
||||
{
|
||||
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||
}
|
||||
if (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))
|
||||
{
|
||||
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 worldOffset = jointRot * avatarPos;
|
||||
glm::vec3 worldPos = jointPos + worldOffset;
|
||||
|
||||
return worldPos;
|
||||
}
|
||||
|
||||
glm::vec3 MyAvatar::avatarToWorldDirection(const glm::vec3& avatarDir, const int jointIndex) const
|
||||
{
|
||||
glm::quat jointRot = getRotation();//default value if no or invalid joint specified
|
||||
if (jointIndex != -1)
|
||||
{
|
||||
if (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))
|
||||
{
|
||||
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||
}
|
||||
}
|
||||
glm::vec3 worldDir = jointRot * avatarDir;
|
||||
return worldDir;
|
||||
}
|
||||
|
||||
glm::quat MyAvatar::avatarToWorldRotation(const glm::quat& avatarRot, const int jointIndex) const
|
||||
{
|
||||
glm::quat jointRot = getRotation();//default value if no or invalid joint specified
|
||||
if (jointIndex != -1)
|
||||
{
|
||||
if (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))
|
||||
{
|
||||
qWarning() << "Invalid joint index specified: " << jointIndex;
|
||||
}
|
||||
}
|
||||
glm::quat worldRot = jointRot * avatarRot;
|
||||
return worldRot;
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
// virtual
|
||||
void MyAvatar::render(RenderArgs* renderArgs) {
|
||||
// don't render if we've been asked to disable local rendering
|
||||
|
|
|
@ -379,6 +379,19 @@ public:
|
|||
Q_INVOKABLE controller::Pose getLeftHandTipPose() const;
|
||||
Q_INVOKABLE controller::Pose getRightHandTipPose() const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//:1P: world-space to avatar-space rigconversion functions
|
||||
Q_INVOKABLE glm::vec3 worldToAvatarPoint(const glm::vec3& position, const int jointIndex = -1) const;
|
||||
Q_INVOKABLE glm::vec3 worldToAvatarDirection(const glm::vec3& direction, const int jointIndex = -1) const;
|
||||
Q_INVOKABLE glm::quat worldToAvatarRotation(const glm::quat& rotation, const int jointIndex = -1) const;
|
||||
|
||||
Q_INVOKABLE glm::vec3 avatarToWorldPoint(const glm::vec3& position, const int jointIndex = -1) const;
|
||||
Q_INVOKABLE glm::vec3 avatarToWorldDirection(const glm::vec3& direction, const int jointIndex = -1) const;
|
||||
Q_INVOKABLE glm::quat avatarToWorldRotation(const glm::quat& rotation, const int jointIndex = -1) const;
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AvatarWeakPointer getLookAtTargetAvatar() const { return _lookAtTargetAvatar; }
|
||||
void updateLookAtTargetAvatar();
|
||||
void clearLookAtTargetAvatar();
|
||||
|
|
127
scripts/avatarToWorldTests.js
Normal file
127
scripts/avatarToWorldTests.js
Normal file
|
@ -0,0 +1,127 @@
|
|||
var AVATAR_SELF_ID = "{00000000-0000-0000-0000-000000000001}";
|
||||
|
||||
var debugSphereBaseProperties = {
|
||||
type: "Sphere",
|
||||
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
|
||||
dynamic: false,
|
||||
collisionless: true,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
lifetime: 10.0,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": false, \"kinematic\": false } }"
|
||||
};
|
||||
|
||||
var debugBoxBaseProperties = {
|
||||
type: "Box",
|
||||
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
|
||||
dynamic: false,
|
||||
collisionless: true,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
lifetime: 10.0,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": false, \"kinematic\": false } }"
|
||||
};
|
||||
|
||||
//avatarToWorldPoint
|
||||
// create sphere for finger on left hand
|
||||
// each frame, calculate world position of finger, with some offset
|
||||
// update sphere to match this position
|
||||
var avatarToWorldPointTest_sphereEntity;
|
||||
function avatarToWorldPointTest() {
|
||||
var jointIndex = MyAvatar.getJointIndex("LeftHandPinky4");
|
||||
var jointOffset_WorldSpace = { x: 0.1, y: 0, z: 0 };
|
||||
var worldPos = MyAvatar.avatarToWorldPoint(jointOffset_WorldSpace, jointIndex);
|
||||
|
||||
var jointSphereProps = Object.create(debugSphereBaseProperties);
|
||||
jointSphereProps.name = "avatarToWorldPointTest_Sphere";
|
||||
jointSphereProps.color = { blue: 240, green: 150, red: 150 };
|
||||
jointSphereProps.position = worldPos;
|
||||
avatarToWorldPointTest_sphereEntity = Entities.addEntity(jointSphereProps);
|
||||
}
|
||||
function avatarToWorldPointTest_update(deltaTime) {
|
||||
var jointIndex = MyAvatar.getJointIndex("LeftHandPinky4");
|
||||
var jointOffset_WorldSpace = { x: 0.1, y: 0, z: 0 };
|
||||
var worldPos = MyAvatar.avatarToWorldPoint(jointOffset_WorldSpace, jointIndex);
|
||||
var newProperties = { position: worldPos };
|
||||
Entities.editEntity(avatarToWorldPointTest_sphereEntity, newProperties);
|
||||
}
|
||||
|
||||
//avatarToWorldDirection
|
||||
// create line in world space
|
||||
// each frame calculate world space direction of players head z axis
|
||||
// update line to match
|
||||
var avatarToWorldDirectionTest_lineEntity;
|
||||
function avatarToWorldDirectionTest() {
|
||||
var jointIndex = MyAvatar.getJointIndex("Head");
|
||||
var avatarPos = MyAvatar.getJointPosition(jointIndex);
|
||||
|
||||
var jointDir = { x: 1, y: 0, z: 1 };
|
||||
var worldDir = MyAvatar.avatarToWorldDirection(jointDir, jointIndex);
|
||||
print(worldDir.x);
|
||||
print(worldDir.y);
|
||||
print(worldDir.z);
|
||||
avatarToWorldDirectionTest_lineEntity = Entities.addEntity({
|
||||
type: "Line",
|
||||
color: {red: 250, green: 0, blue: 0},
|
||||
dimensions: {x: 5, y: 5, z: 5},
|
||||
lifetime: 10.0,
|
||||
linePoints: [{
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
}, worldDir
|
||||
],
|
||||
position : avatarPos,
|
||||
});
|
||||
}
|
||||
function avatarToWorldDirection_update(deltaTime) {
|
||||
var jointIndex = MyAvatar.getJointIndex("Head");
|
||||
var avatarPos = MyAvatar.getJointPosition(jointIndex);
|
||||
var jointDir = { x: 1, y: 0, z: 0 };
|
||||
var worldDir = MyAvatar.avatarToWorldDirection(jointDir, jointIndex);
|
||||
var newProperties = {
|
||||
linePoints: [{
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
}, worldDir
|
||||
],
|
||||
position : avatarPos
|
||||
};
|
||||
|
||||
Entities.editEntity(avatarToWorldDirectionTest_lineEntity, newProperties);
|
||||
}
|
||||
|
||||
//avatarToWorldRotation
|
||||
// create box in world space
|
||||
// each frame calculate world space rotation of players head
|
||||
// update box rotation to match
|
||||
var avatarToWorldRotationTest_boxEntity;
|
||||
function avatarToWorldRotationTest() {
|
||||
var jointIndex = MyAvatar.getJointIndex("Head");
|
||||
var jointPosition_WorldSpace = MyAvatar.getJointPosition(jointIndex);
|
||||
var jointRot = MyAvatar.getJointRotation(jointIndex);
|
||||
var jointRot_WorldSpace = MyAvatar.avatarToWorldRotation(jointRot, jointIndex);
|
||||
|
||||
var boxProps = Object.create(debugBoxBaseProperties);
|
||||
boxProps.name = "avatarToWorldRotationTest_Box";
|
||||
boxProps.color = { blue: 250, green: 250, red: 250 };
|
||||
boxProps.position = jointPosition_WorldSpace;
|
||||
boxProps.rotation = jointRot_WorldSpace;
|
||||
avatarToWorldRotationTest_boxEntity = Entities.addEntity(boxProps);
|
||||
}
|
||||
function avatarToWorldRotationTest_update(deltaTime) {
|
||||
var jointIndex = MyAvatar.getJointIndex("Head");
|
||||
var jointPosition_WorldSpace = MyAvatar.getJointPosition(jointIndex);
|
||||
var jointRot = MyAvatar.getJointRotation(jointIndex);
|
||||
var jointRot_WorldSpace = MyAvatar.avatarToWorldRotation(jointRot, jointIndex);
|
||||
var newProperties = { position: jointPosition_WorldSpace, rotation: jointRot_WorldSpace };
|
||||
Entities.editEntity(avatarToWorldRotationTest_boxEntity, newProperties);
|
||||
}
|
||||
|
||||
avatarToWorldPointTest();
|
||||
Script.update.connect(avatarToWorldPointTest_update);
|
||||
|
||||
avatarToWorldDirectionTest();
|
||||
Script.update.connect(avatarToWorldDirection_update);
|
||||
|
||||
avatarToWorldRotationTest();
|
||||
Script.update.connect(avatarToWorldRotationTest_update);
|
134
scripts/worldToAvatarTests.js
Normal file
134
scripts/worldToAvatarTests.js
Normal file
|
@ -0,0 +1,134 @@
|
|||
var AVATAR_SELF_ID = "{00000000-0000-0000-0000-000000000001}";
|
||||
|
||||
var debugSphereBaseProperties = {
|
||||
type: "Sphere",
|
||||
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
|
||||
dynamic: false,
|
||||
collisionless: true,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
lifetime: 10.0,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": false, \"kinematic\": false } }"
|
||||
};
|
||||
|
||||
var debugBoxBaseProperties = {
|
||||
type: "Box",
|
||||
dimensions: { x: 0.2, y: 0.2, z: 0.2 },
|
||||
dynamic: false,
|
||||
collisionless: true,
|
||||
gravity: { x: 0, y: 0, z: 0 },
|
||||
lifetime: 10.0,
|
||||
userData: "{ \"grabbableKey\": { \"grabbable\": false, \"kinematic\": false } }"
|
||||
};
|
||||
|
||||
//worldToAvatarPoint
|
||||
// calculate position offset from joint using getJointPosition
|
||||
// pass through worldToAvatarPoint to get offset in joint space of players joint
|
||||
// create a blue sphere and attach it to players joint using the joint space offset
|
||||
// The two spheres should appear in the same place, but the blue sphere will follow the avatar
|
||||
function worldToAvatarPointTest() {
|
||||
var jointIndex = MyAvatar.getJointIndex("LeftHandPinky4");
|
||||
var avatarPos = MyAvatar.position;
|
||||
|
||||
var jointPosition_WorldSpace = MyAvatar.getJointPosition(jointIndex);
|
||||
var jointOffset_WorldSpace = { x: 0.1, y: 0, z: 0 };
|
||||
var jointPosition_WorldSpaceOffset = Vec3.sum(jointPosition_WorldSpace, jointOffset_WorldSpace);
|
||||
var jointPosition_JointSpaceOffset = MyAvatar.worldToAvatarPoint(jointPosition_WorldSpaceOffset, jointIndex);
|
||||
|
||||
var jointSphereProps = Object.create(debugSphereBaseProperties);
|
||||
jointSphereProps.name = "worldToAvatarPointTest_Joint";
|
||||
jointSphereProps.color = { blue: 240, green: 150, red: 150 };
|
||||
jointSphereProps.localPosition = jointPosition_JointSpaceOffset;
|
||||
jointSphereProps.parentID = AVATAR_SELF_ID;
|
||||
jointSphereProps.parentJointIndex = jointIndex;
|
||||
Entities.addEntity(jointSphereProps);
|
||||
|
||||
var worldSphereProps = Object.create(debugSphereBaseProperties);
|
||||
worldSphereProps.name = "worldToAvatarPointTest_World";
|
||||
worldSphereProps.color = { blue: 150, green: 250, red: 150 };
|
||||
worldSphereProps.position = jointPosition_WorldSpaceOffset;
|
||||
Entities.addEntity(worldSphereProps);
|
||||
}
|
||||
|
||||
//worldToAvatarDirection
|
||||
// create line and attach to avatars head
|
||||
// each frame calculate direction of world x axis in joint space of players head
|
||||
// update arrow orientation to match
|
||||
var worldToAvatarDirectionTest_lineEntity;
|
||||
function worldToAvatarDirectionTest() {
|
||||
var jointIndex = MyAvatar.getJointIndex("Head");
|
||||
|
||||
var jointPosition_WorldSpace = MyAvatar.getJointPosition(jointIndex);
|
||||
var jointOffset_WorldSpace = { x: 0, y: 0, z: 0 };
|
||||
var jointPosition_WorldSpaceOffset = Vec3.sum(jointPosition_WorldSpace, jointOffset_WorldSpace);
|
||||
var jointPosition_JointSpaceOffset = MyAvatar.worldToAvatarPoint(jointPosition_WorldSpaceOffset, jointIndex);
|
||||
|
||||
var worldDir = { x: 1, y: 0, z: 0 };
|
||||
var avatarDir = MyAvatar.worldToAvatarDirection(worldDir, jointIndex);
|
||||
|
||||
worldToAvatarDirectionTest_lineEntity = Entities.addEntity({
|
||||
type: "Line",
|
||||
color: {red: 200, green: 250, blue: 0},
|
||||
dimensions: {x: 5, y: 5, z: 5},
|
||||
lifetime: 10.0,
|
||||
linePoints: [{
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
}, avatarDir
|
||||
],
|
||||
localPosition : jointOffset_WorldSpace,
|
||||
parentID : AVATAR_SELF_ID,
|
||||
parentJointIndex : jointIndex
|
||||
});
|
||||
}
|
||||
|
||||
function worldToAvatarDirectionTest_update(deltaTime) {
|
||||
var jointIndex = MyAvatar.getJointIndex("Head");
|
||||
var worldDir = { x: 1, y: 0, z: 0 };
|
||||
var avatarDir = MyAvatar.worldToAvatarDirection(worldDir, jointIndex);
|
||||
var newProperties = { linePoints: [{
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
}, avatarDir
|
||||
]};
|
||||
|
||||
Entities.editEntity(worldToAvatarDirectionTest_lineEntity, newProperties);
|
||||
}
|
||||
|
||||
//worldToAvatarRotation
|
||||
// create box and parent to some player joint
|
||||
// convert world identity rotation to joint space rotation
|
||||
// each frame, update box with new orientation
|
||||
var worldToAvatarRotationTest_boxEntity;
|
||||
function worldToAvatarRotationTest() {
|
||||
var jointIndex = MyAvatar.getJointIndex("RightHandPinky4");
|
||||
var avatarPos = MyAvatar.position;
|
||||
|
||||
var jointPosition_WorldSpace = MyAvatar.getJointPosition(jointIndex);
|
||||
var jointOffset_WorldSpace = { x: 0.0, y: 0, z: 0 };
|
||||
var jointPosition_WorldSpaceOffset = Vec3.sum(jointPosition_WorldSpace, jointOffset_WorldSpace);
|
||||
var jointPosition_JointSpaceOffset = MyAvatar.worldToAvatarPoint(jointPosition_WorldSpaceOffset, jointIndex);
|
||||
|
||||
var jointBoxProps = Object.create(debugBoxBaseProperties);
|
||||
jointBoxProps.name = "worldToAvatarRotationTest_Box";
|
||||
jointBoxProps.color = { blue: 0, green: 0, red: 250 };
|
||||
jointBoxProps.localPosition = jointPosition_JointSpaceOffset;
|
||||
jointBoxProps.parentID = AVATAR_SELF_ID;
|
||||
jointBoxProps.parentJointIndex = jointIndex;
|
||||
worldToAvatarRotationTest_boxEntity = Entities.addEntity(jointBoxProps);
|
||||
}
|
||||
function worldToAvatarRotationTest_update(deltaTime) {
|
||||
var jointIndex = MyAvatar.getJointIndex("RightHandPinky4");
|
||||
var worldRot = Quat.fromPitchYawRollDegrees(0,0,0);
|
||||
var avatarRot = MyAvatar.worldToAvatarRotation(worldRot, jointIndex);
|
||||
var newProperties = { localRotation: avatarRot };
|
||||
Entities.editEntity(worldToAvatarRotationTest_boxEntity, newProperties);
|
||||
}
|
||||
|
||||
worldToAvatarPointTest();
|
||||
worldToAvatarDirectionTest();
|
||||
worldToAvatarRotationTest();
|
||||
|
||||
Script.update.connect(worldToAvatarDirectionTest_update);
|
||||
Script.update.connect(worldToAvatarRotationTest_update);
|
Loading…
Reference in a new issue