Hand Controller rendering is camera relative

Basically, when using the third person camera in HMD mode.  If the controllers are shown.
They should be shown in front of the users camera, not in front of the users avatar.

To accomplish this, two new faux joint indices are introduced.
CAMERA_RELATIVE_CONTROLLER_RIGHTHAND_INDEX and CAMERA_RELATIVE_CONTROLLER_LEFTHAND_INDEX.

These joint indices can be used for Overlay parenting. (But not for entity parenting because they are not transmitted over the network).
They can also be queried for by using the MyAvatar.getAbsoluteJointRotationInObjectFrame() call.

These new indices are now used by the controllerDisplay.js for the hand controller rendering.
They are also used by system/libraries/controllers.js as the origin for hand controller grabbing and interaction lasers.
This commit is contained in:
Anthony J. Thibault 2016-11-17 11:33:12 -08:00
parent 47bef18bd4
commit 38ac6fff03
6 changed files with 72 additions and 12 deletions

View file

@ -2333,14 +2333,49 @@ bool MyAvatar::hasDriveInput() const {
return fabsf(_driveKeys[TRANSLATE_X]) > 0.0f || fabsf(_driveKeys[TRANSLATE_Y]) > 0.0f || fabsf(_driveKeys[TRANSLATE_Z]) > 0.0f;
}
// The resulting matrix is used to render the hand controllers, even if the camera is decoupled from the avatar.
// Specificly, if we are rendering using a third person camera. We would like to render the hand controllers in front of the camera,
// not in front of the avatar.
glm::mat4 MyAvatar::computeCameraRelativeHandControllerMatrix(const glm::mat4& controllerSensorMatrix) const {
// Fetch the current camera transform.
glm::mat4 cameraWorldMatrix = qApp->getCamera()->getTransform();
if (qApp->getCamera()->getMode() == CAMERA_MODE_MIRROR) {
cameraWorldMatrix *= createMatFromScaleQuatAndPos(vec3(-1.0f, 1.0f, 1.0f), glm::quat(), glm::vec3());
}
// compute a NEW sensorToWorldMatrix for the camera. The equation is cameraWorldMatrix = cameraSensorToWorldMatrix * _hmdSensorMatrix.
// here we solve for the unknown cameraSensorToWorldMatrix.
glm::mat4 cameraSensorToWorldMatrix = cameraWorldMatrix * glm::inverse(_hmdSensorMatrix);
// Using the new cameraSensorToWorldMatrix, compute where the controller is in world space.
glm::mat4 controllerWorldMatrix = cameraSensorToWorldMatrix * controllerSensorMatrix;
// move it into avatar space
glm::mat4 avatarMatrix = createMatFromQuatAndPos(getOrientation(), getPosition());
return glm::inverse(avatarMatrix) * controllerWorldMatrix;
}
glm::quat MyAvatar::getAbsoluteJointRotationInObjectFrame(int index) const {
switch(index) {
switch (index) {
case CONTROLLER_LEFTHAND_INDEX: {
return getLeftHandControllerPoseInAvatarFrame().getRotation();
}
case CONTROLLER_RIGHTHAND_INDEX: {
return getRightHandControllerPoseInAvatarFrame().getRotation();
}
case CAMERA_RELATIVE_CONTROLLER_LEFTHAND_INDEX: {
auto pose = _leftHandControllerPoseInSensorFrameCache.get();
glm::mat4 controllerSensorMatrix = createMatFromQuatAndPos(pose.rotation, pose.translation);
glm::mat4 result = computeCameraRelativeHandControllerMatrix(controllerSensorMatrix);
return glmExtractRotation(result);
}
case CAMERA_RELATIVE_CONTROLLER_RIGHTHAND_INDEX: {
auto pose = _rightHandControllerPoseInSensorFrameCache.get();
glm::mat4 controllerSensorMatrix = createMatFromQuatAndPos(pose.rotation, pose.translation);
glm::mat4 result = computeCameraRelativeHandControllerMatrix(controllerSensorMatrix);
return glmExtractRotation(result);
}
default: {
return Avatar::getAbsoluteJointRotationInObjectFrame(index);
}
@ -2348,13 +2383,25 @@ glm::quat MyAvatar::getAbsoluteJointRotationInObjectFrame(int index) const {
}
glm::vec3 MyAvatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
switch(index) {
switch (index) {
case CONTROLLER_LEFTHAND_INDEX: {
return getLeftHandControllerPoseInAvatarFrame().getTranslation();
}
case CONTROLLER_RIGHTHAND_INDEX: {
return getRightHandControllerPoseInAvatarFrame().getTranslation();
}
case CAMERA_RELATIVE_CONTROLLER_LEFTHAND_INDEX: {
auto pose = _leftHandControllerPoseInSensorFrameCache.get();
glm::mat4 controllerSensorMatrix = createMatFromQuatAndPos(pose.rotation, pose.translation);
glm::mat4 result = computeCameraRelativeHandControllerMatrix(controllerSensorMatrix);
return extractTranslation(result);
}
case CAMERA_RELATIVE_CONTROLLER_RIGHTHAND_INDEX: {
auto pose = _rightHandControllerPoseInSensorFrameCache.get();
glm::mat4 controllerSensorMatrix = createMatFromQuatAndPos(pose.rotation, pose.translation);
glm::mat4 result = computeCameraRelativeHandControllerMatrix(controllerSensorMatrix);
return extractTranslation(result);
}
default: {
return Avatar::getAbsoluteJointTranslationInObjectFrame(index);
}

View file

@ -374,6 +374,7 @@ private:
void clampTargetScaleToDomainLimits();
void clampScaleChangeToDomainLimits(float desiredScale);
glm::mat4 computeCameraRelativeHandControllerMatrix(const glm::mat4& controllerSensorMatrix) const;
float _driveKeys[MAX_DRIVE_KEYS];
bool _wasPushing;

View file

@ -953,6 +953,12 @@ int AvatarData::getFauxJointIndex(const QString& name) const {
if (name == "_CONTROLLER_RIGHTHAND") {
return CONTROLLER_RIGHTHAND_INDEX;
}
if (name == "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND") {
return CAMERA_RELATIVE_CONTROLLER_LEFTHAND_INDEX;
}
if (name == "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND") {
return CAMERA_RELATIVE_CONTROLLER_RIGHTHAND_INDEX;
}
return -1;
}

View file

@ -539,6 +539,7 @@ void RayToAvatarIntersectionResultFromScriptValue(const QScriptValue& object, Ra
const int SENSOR_TO_WORLD_MATRIX_INDEX = 65534; // -2
const int CONTROLLER_RIGHTHAND_INDEX = 65533; // -3
const int CONTROLLER_LEFTHAND_INDEX = 65532; // -4
const int CAMERA_RELATIVE_CONTROLLER_RIGHTHAND_INDEX = 65531; // -5
const int CAMERA_RELATIVE_CONTROLLER_LEFTHAND_INDEX = 65530; // -6
#endif // hifi_AvatarData_h

View file

@ -69,7 +69,7 @@ VIVE_CONTROLLER_CONFIGURATION_LEFT = {
controllers: [
{
modelURL: viveModelURL,
jointIndex: MyAvatar.getJointIndex("_CONTROLLER_LEFTHAND"),
jointIndex: MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"),
naturalPosition: viveNaturalPosition,
rotation: leftBaseRotation,
position: Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, 0, 45), leftBasePosition),
@ -195,8 +195,7 @@ VIVE_CONTROLLER_CONFIGURATION_RIGHT = {
controllers: [
{
modelURL: viveModelURL,
jointIndex: MyAvatar.getJointIndex("_CONTROLLER_RIGHTHAND"),
jointIndex: MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND"),
rotation: rightBaseRotation,
position: Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, 0, -45), rightBasePosition),

View file

@ -35,16 +35,22 @@ getControllerWorldLocation = function (handController, doOffset) {
var position;
var pose = Controller.getPoseValue(handController);
var valid = pose.valid;
var controllerJointIndex;
if (pose.valid) {
orientation = Quat.multiply(MyAvatar.orientation, pose.rotation);
position = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation), MyAvatar.position);
if (handController === Controller.Standard.RightHand) {
controllerJointIndex = MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND");
} else {
controllerJointIndex = MyAvatar.getJointIndex("_CAMERA_RELATIVE_CONTROLLER_LEFTHAND");
}
orientation = Quat.multiply(MyAvatar.orientation, MyAvatar.getAbsoluteJointRotationInObjectFrame(controllerJointIndex));
position = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, MyAvatar.getAbsoluteJointTranslationInObjectFrame(controllerJointIndex)));
// add to the real position so the grab-point is out in front of the hand, a bit
if (doOffset) {
position = Vec3.sum(position, Vec3.multiplyQbyV(orientation, getGrabPointSphereOffset(handController)));
}
if (Menu.isOptionChecked("Third Person")) {
position = Vec3.sum(position, Vec3.subtract(Camera.position, MyAvatar.getEyePosition()));
var offset = getGrabPointSphereOffset(handController);
position = Vec3.sum(position, Vec3.multiplyQbyV(orientation, offset));
}
} else if (!HMD.isHandControllerAvailable()) {
position = MyAvatar.getHeadPosition();
orientation = Quat.multiply(MyAvatar.headOrientation, Quat.angleAxis(-90, { x: 1, y: 0, z: 0 }));