222 lines
No EOL
8.1 KiB
JavaScript
222 lines
No EOL
8.1 KiB
JavaScript
//
|
|
// pickRayController.js
|
|
//
|
|
// Created by Milad
|
|
// Copyright 2019 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
var _this;
|
|
function PickRayController(){
|
|
_this = this;
|
|
_this.eventHandler = null;
|
|
_this.rayType = 'local';
|
|
_this.intersection = null;
|
|
_this.lastPick = null;
|
|
_this.currentPick = null;
|
|
_this.mappingName = null;
|
|
_this.mapping = null;
|
|
_this._boundMousePressHandler = null;
|
|
}
|
|
|
|
PickRayController.prototype.create =
|
|
function(){
|
|
_this.mapping = Controller.newMapping(_this.mappingName);
|
|
|
|
_this.mapping.from(Controller.Standard.LTClick).to(function (value) {
|
|
if (value === 0) {
|
|
return;
|
|
}
|
|
|
|
_this.getUUIDFromLaser(Controller.Standard.LeftHand);
|
|
});
|
|
|
|
|
|
_this.mapping.from(Controller.Standard.RTClick).to(function (value) {
|
|
if (value === 0) {
|
|
return;
|
|
}
|
|
|
|
_this.getUUIDFromLaser(Controller.Standard.RightHand);
|
|
});
|
|
|
|
return _this;
|
|
};
|
|
// The following two functions are a modified version of what's found in scripts/system/libraries/controllers.js
|
|
|
|
PickRayController.prototype.handleUUID =
|
|
function(uuid){
|
|
if (!_this.lastPick && !_this.currentPick) {
|
|
_this.currentPick = uuid;
|
|
_this.lastPick = uuid;
|
|
} else {
|
|
_this.lastPick = _this.currentPick;
|
|
_this.currentPick = uuid;
|
|
}
|
|
};
|
|
PickRayController.prototype.setType =
|
|
function(type){
|
|
_this.rayType = type;
|
|
|
|
return _this;
|
|
};
|
|
PickRayController.prototype.setMapName =
|
|
function (name) {
|
|
_this.mappingName = name;
|
|
|
|
return _this;
|
|
};
|
|
PickRayController.prototype.pickRayTypeHandler =
|
|
function (pickRay){
|
|
if (arguments.length === 2) {
|
|
pickRay = { origin: arguments[0], direction: arguments[1] };
|
|
}
|
|
switch (_this.rayType) {
|
|
case 'avatar':
|
|
var avatarIntersection = AvatarList.findRayIntersection(pickRay, [], [MyAvatar.sessionUUID]);
|
|
_this.intersection = avatarIntersection;
|
|
_this.handleUUID(avatarIntersection.avatarID);
|
|
break;
|
|
case 'local':
|
|
var overlayIntersection = Overlays.findRayIntersection(pickRay, [], []);
|
|
_this.intersection = overlayIntersection;
|
|
_this.handleUUID(overlayIntersection.overlayID);
|
|
break;
|
|
case 'entity':
|
|
var entityIntersection = Entities.findRayIntersection(pickRay, [], []);
|
|
_this.intersection = entityIntersection;
|
|
_this.handleUUID(entityIntersection.avatarID);
|
|
break;
|
|
default:
|
|
console.log("ray type not handled");
|
|
}
|
|
}
|
|
|
|
// Handle the interaction when in desktop and a mouse is pressed
|
|
PickRayController.prototype.mousePressHandler =
|
|
function mousePressHandler(event) {
|
|
if (HMD.active || !event.isLeftButton) {
|
|
return;
|
|
}
|
|
// log("event", event, false)
|
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
|
// log("pickRay", pickRay, false);
|
|
_this.pickRayTypeHandler(pickRay);
|
|
if (_this.currentPick) {
|
|
// log("intersection", _this.intersection.intersection)
|
|
_this.eventHandler(_this.currentPick, _this.intersection);
|
|
}
|
|
};
|
|
// Returns the right UUID based on hand triggered
|
|
PickRayController.prototype.getUUIDFromLaser =
|
|
function (hand) {
|
|
hand = hand === Controller.Standard.LeftHand
|
|
? Controller.Standard.LeftHand
|
|
: Controller.Standard.RightHand;
|
|
|
|
var pose = _this.getControllerWorldLocation(hand);
|
|
var start = pose.position;
|
|
var direction = Vec3.multiplyQbyV(pose.orientation, [0, 1, 0]);
|
|
|
|
_this.pickRayTypeHandler(start, direction);
|
|
|
|
if (_this.currentPick) {
|
|
_this.eventHandler(_this.currentPick, _this.intersection);
|
|
}
|
|
};
|
|
// Utility function for the ControllerWorldLocation offset
|
|
PickRayController.prototype.getGrabPointSphereOffset =
|
|
function getGrabPointSphereOffset(handController) {
|
|
// These values must match what's in scripts/system/libraries/controllers.js
|
|
// x = upward, y = forward, z = lateral
|
|
var GRAB_POINT_SPHERE_OFFSET = { x: 0.04, y: 0.13, z: 0.039 };
|
|
var offset = GRAB_POINT_SPHERE_OFFSET;
|
|
if (handController === Controller.Standard.LeftHand) {
|
|
offset = {
|
|
x: -GRAB_POINT_SPHERE_OFFSET.x,
|
|
y: GRAB_POINT_SPHERE_OFFSET.y,
|
|
z: GRAB_POINT_SPHERE_OFFSET.z
|
|
};
|
|
}
|
|
|
|
return Vec3.multiply(MyAvatar.sensorToWorldScale, offset);
|
|
};
|
|
|
|
// controllerWorldLocation is where the controller would be, in-world, with an added offset
|
|
PickRayController.prototype.getControllerWorldLocation =
|
|
function getControllerWorldLocation(handController, doOffset) {
|
|
var orientation;
|
|
var position;
|
|
var valid = false;
|
|
|
|
if (handController >= 0) {
|
|
var pose = Controller.getPoseValue(handController);
|
|
valid = pose.valid;
|
|
var controllerJointIndex;
|
|
if (pose.valid) {
|
|
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) {
|
|
var offset = getGrabPointSphereOffset(handController);
|
|
position = Vec3.sum(position, Vec3.multiplyQbyV(orientation, offset));
|
|
}
|
|
|
|
} else if (!HMD.isHandControllerAvailable()) {
|
|
// NOTE: keep _this offset in sync with scripts/system/controllers/handControllerPointer.js:493
|
|
var VERTICAL_HEAD_LASER_OFFSET = 0.1 * MyAvatar.sensorToWorldScale;
|
|
position = Vec3.sum(Camera.position, Vec3.multiplyQbyV(Camera.orientation, { x: 0, y: VERTICAL_HEAD_LASER_OFFSET, z: 0 }));
|
|
orientation = Quat.multiply(Camera.orientation, Quat.angleAxis(-90, { x: 1, y: 0, z: 0 }));
|
|
valid = true;
|
|
}
|
|
}
|
|
|
|
return {
|
|
position: position,
|
|
translation: position,
|
|
orientation: orientation,
|
|
rotation: orientation,
|
|
valid: valid
|
|
};
|
|
};
|
|
|
|
// Enables mouse press and trigger events
|
|
var controllerConnected = false;
|
|
PickRayController.prototype.enable =
|
|
function(){
|
|
if (!controllerConnected) {
|
|
controllerConnected = true;
|
|
Controller.mousePressEvent.connect(_this.mousePressHandler);
|
|
Controller.enableMapping(_this.mappingName);
|
|
}
|
|
return _this;
|
|
};
|
|
PickRayController.prototype.disable =
|
|
function(){
|
|
if (controllerConnected) {
|
|
controllerConnected = false;
|
|
Controller.mousePressEvent.disconnect(_this.mousePressHandler);
|
|
Controller.disableMapping(_this.mappingName);
|
|
}
|
|
return _this;
|
|
};
|
|
PickRayController.prototype.destroy =
|
|
function(){
|
|
_this.disable();
|
|
}
|
|
PickRayController.prototype.registerEventHandler =
|
|
function(fn){
|
|
_this.eventHandler = fn;
|
|
|
|
return _this;
|
|
};
|
|
|
|
module.exports = PickRayController; |