convert grab.js to use spring action. rotation doesn't work right, yet

This commit is contained in:
Seth Alves 2015-06-08 18:25:58 -07:00
parent eb85f7f818
commit 14a45e8349
3 changed files with 65 additions and 39 deletions

View file

@ -4,7 +4,7 @@
// Created by Eric Levin on May 1, 2015 // Created by Eric Levin on May 1, 2015
// Copyright 2015 High Fidelity, Inc. // Copyright 2015 High Fidelity, Inc.
// //
// Grab's physically moveable entities with the mouse, by applying a spring force. // Grab's physically moveable entities with the mouse, by applying a spring force.
// //
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -20,6 +20,7 @@ var ANGULAR_DAMPING_RATE = 0.40;
// NOTE: to improve readability global variable names start with 'g' // NOTE: to improve readability global variable names start with 'g'
var gIsGrabbing = false; var gIsGrabbing = false;
var gGrabbedEntity = null; var gGrabbedEntity = null;
var gActionID = null;
var gPrevMouse = {x: 0, y: 0}; var gPrevMouse = {x: 0, y: 0};
var gEntityProperties; var gEntityProperties;
var gStartPosition; var gStartPosition;
@ -31,20 +32,20 @@ var gPlaneNormal = ZERO_VEC3;
// gMaxGrabDistance is a function of the size of the object. // gMaxGrabDistance is a function of the size of the object.
var gMaxGrabDistance; var gMaxGrabDistance;
// gGrabMode defines the degrees of freedom of the grab target positions // gGrabMode defines the degrees of freedom of the grab target positions
// relative to gGrabStartPosition options include: // relative to gGrabStartPosition options include:
// xzPlane (default) // xzPlane (default)
// verticalCylinder (SHIFT) // verticalCylinder (SHIFT)
// rotate (CONTROL) // rotate (CONTROL)
// Modes to eventually support?: // Modes to eventually support?:
// xyPlane // xyPlane
// yzPlane // yzPlane
// polar // polar
// elevationAzimuth // elevationAzimuth
var gGrabMode = "xzplane"; var gGrabMode = "xzplane";
// gGrabOffset allows the user to grab an object off-center. It points from ray's intersection // gGrabOffset allows the user to grab an object off-center. It points from ray's intersection
// with the move-plane to object center (at the moment the grab is initiated). Future target positions // with the move-plane to object center (at the moment the grab is initiated). Future target positions
// are relative to the ray's intersection by the same offset. // are relative to the ray's intersection by the same offset.
var gGrabOffset = { x: 0, y: 0, z: 0 }; var gGrabOffset = { x: 0, y: 0, z: 0 };
@ -162,7 +163,7 @@ function computeNewGrabPlane() {
var xzOffset = Vec3.subtract(gPointOnPlane, Camera.getPosition()); var xzOffset = Vec3.subtract(gPointOnPlane, Camera.getPosition());
xzOffset.y = 0; xzOffset.y = 0;
gXzDistanceToGrab = Vec3.length(xzOffset); gXzDistanceToGrab = Vec3.length(xzOffset);
if (gGrabMode !== "rotate" && maybeResetMousePosition) { if (gGrabMode !== "rotate" && maybeResetMousePosition) {
// we reset the mouse position whenever we stop rotating // we reset the mouse position whenever we stop rotating
Window.setCursorPosition(gMouseAtRotateStart.x, gMouseAtRotateStart.y); Window.setCursorPosition(gMouseAtRotateStart.x, gMouseAtRotateStart.y);
@ -193,6 +194,7 @@ function mousePressEvent(event) {
var cameraPosition = Camera.getPosition(); var cameraPosition = Camera.getPosition();
gBeaconHeight = Vec3.length(entityProperties.dimensions); gBeaconHeight = Vec3.length(entityProperties.dimensions);
print("gBeaconHeight = " + gBeaconHeight);
gMaxGrabDistance = gBeaconHeight / MAX_SOLID_ANGLE; gMaxGrabDistance = gBeaconHeight / MAX_SOLID_ANGLE;
if (Vec3.distance(objectPosition, cameraPosition) > gMaxGrabDistance) { if (Vec3.distance(objectPosition, cameraPosition) > gMaxGrabDistance) {
// don't allow grabs of things far away // don't allow grabs of things far away
@ -231,6 +233,8 @@ function mouseReleaseEvent() {
} }
gIsGrabbing = false gIsGrabbing = false
Entities.deleteAction(grabbedEntity, gActionID);
gActionID = null;
Overlays.editOverlay(gBeacon, { visible: false }); Overlays.editOverlay(gBeacon, { visible: false });
@ -250,6 +254,8 @@ function mouseMoveEvent(event) {
gOriginalGravity = entityProperties.gravity; gOriginalGravity = entityProperties.gravity;
} }
var actionArgs;
if (gGrabMode === "rotate") { if (gGrabMode === "rotate") {
var deltaMouse = { x: 0, y: 0 }; var deltaMouse = { x: 0, y: 0 };
var dx = event.x - gPreviousMouse.x; var dx = event.x - gPreviousMouse.x;
@ -259,9 +265,12 @@ function mouseMoveEvent(event) {
var dragOffset = Vec3.multiply(dx, Quat.getRight(orientation)); var dragOffset = Vec3.multiply(dx, Quat.getRight(orientation));
dragOffset = Vec3.sum(dragOffset, Vec3.multiply(-dy, Quat.getUp(orientation))); dragOffset = Vec3.sum(dragOffset, Vec3.multiply(-dy, Quat.getUp(orientation)));
var axis = Vec3.cross(dragOffset, Quat.getFront(orientation)); var axis = Vec3.cross(dragOffset, Quat.getFront(orientation));
var axis = Vec3.normalize(axis); // var axis = Vec3.normalize(axis);
var ROTATE_STRENGTH = 8.0; // magic number tuned by hand // var ROTATE_STRENGTH = 8.0; // magic number tuned by hand
gAngularVelocity = Vec3.multiply(ROTATE_STRENGTH, axis); // gAngularVelocity = Vec3.multiply(ROTATE_STRENGTH, axis);
var targetRotation = Quat.angleAxis(Vec3.length(axis), Vec3.normalize(axis));
actionArgs = {targetRotation: targetRotation, angularTimeScale: 1.0};
} else { } else {
var newTargetPosition; var newTargetPosition;
if (gGrabMode === "verticalCylinder") { if (gGrabMode === "verticalCylinder") {
@ -284,9 +293,18 @@ function mouseMoveEvent(event) {
} }
} }
gTargetPosition = Vec3.sum(newTargetPosition, gGrabOffset); gTargetPosition = Vec3.sum(newTargetPosition, gGrabOffset);
actionArgs = {targetPosition: gTargetPosition, linearTimeScale: 0.1};
} }
gPreviousMouse = { x: event.x, y: event.y }; gPreviousMouse = { x: event.x, y: event.y };
gMouseCursorLocation = { x: Window.getCursorPositionX(), y: Window.getCursorPositionY() }; gMouseCursorLocation = { x: Window.getCursorPositionX(), y: Window.getCursorPositionY() };
if (!gActionID) {
gActionID = Entities.addAction("spring", gGrabbedEntity, actionArgs);
} else {
Entities.updateAction(gGrabbedEntity, gActionID, actionArgs);
}
updateDropLine(gTargetPosition);
} }
function keyReleaseEvent(event) { function keyReleaseEvent(event) {
@ -309,38 +327,37 @@ function keyPressEvent(event) {
computeNewGrabPlane(); computeNewGrabPlane();
} }
function update(deltaTime) { // function update(deltaTime) {
if (!gIsGrabbing) { // if (!gIsGrabbing) {
return; // return;
} // }
var entityProperties = Entities.getEntityProperties(gGrabbedEntity); // var entityProperties = Entities.getEntityProperties(gGrabbedEntity);
gCurrentPosition = entityProperties.position; // gCurrentPosition = entityProperties.position;
if (gGrabMode === "rotate") { // if (gGrabMode === "rotate") {
gAngularVelocity = Vec3.subtract(gAngularVelocity, Vec3.multiply(gAngularVelocity, ANGULAR_DAMPING_RATE)); // gAngularVelocity = Vec3.subtract(gAngularVelocity, Vec3.multiply(gAngularVelocity, ANGULAR_DAMPING_RATE));
Entities.editEntity(gGrabbedEntity, { angularVelocity: gAngularVelocity, }); // Entities.editEntity(gGrabbedEntity, { angularVelocity: gAngularVelocity, });
} // }
// always push toward linear grab position, even when rotating // // always push toward linear grab position, even when rotating
var newVelocity = ZERO_VEC3; // var newVelocity = ZERO_VEC3;
var dPosition = Vec3.subtract(gTargetPosition, gCurrentPosition); // var dPosition = Vec3.subtract(gTargetPosition, gCurrentPosition);
var delta = Vec3.length(dPosition); // var delta = Vec3.length(dPosition);
if (delta > CLOSE_ENOUGH) { // if (delta > CLOSE_ENOUGH) {
var MAX_POSITION_DELTA = 4.0; // var MAX_POSITION_DELTA = 4.0;
if (delta > MAX_POSITION_DELTA) { // if (delta > MAX_POSITION_DELTA) {
dPosition = Vec3.multiply(dPosition, MAX_POSITION_DELTA / delta); // dPosition = Vec3.multiply(dPosition, MAX_POSITION_DELTA / delta);
} // }
// desired speed is proportional to displacement by the inverse of timescale // // desired speed is proportional to displacement by the inverse of timescale
// (for critically damped motion) // // (for critically damped motion)
newVelocity = Vec3.multiply(dPosition, INV_MOVE_TIMESCALE); // newVelocity = Vec3.multiply(dPosition, INV_MOVE_TIMESCALE);
} // }
Entities.editEntity(gGrabbedEntity, { velocity: newVelocity, }); // Entities.editEntity(gGrabbedEntity, { velocity: newVelocity, });
updateDropLine(gTargetPosition); // }
}
Controller.mouseMoveEvent.connect(mouseMoveEvent); Controller.mouseMoveEvent.connect(mouseMoveEvent);
Controller.mousePressEvent.connect(mousePressEvent); Controller.mousePressEvent.connect(mousePressEvent);
Controller.mouseReleaseEvent.connect(mouseReleaseEvent); Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
Controller.keyPressEvent.connect(keyPressEvent); Controller.keyPressEvent.connect(keyPressEvent);
Controller.keyReleaseEvent.connect(keyReleaseEvent); Controller.keyReleaseEvent.connect(keyReleaseEvent);
Script.update.connect(update); // Script.update.connect(update);

View file

@ -28,6 +28,10 @@ ObjectActionPullToPoint::~ObjectActionPullToPoint() {
} }
void ObjectActionPullToPoint::updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep) { void ObjectActionPullToPoint::updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep) {
if (!_ownerEntity) {
qDebug() << "ObjectActionPullToPoint::updateAction no owner entity";
return;
}
if (!tryLockForRead()) { if (!tryLockForRead()) {
// don't risk hanging the thread running the physics simulation // don't risk hanging the thread running the physics simulation
return; return;

View file

@ -28,6 +28,10 @@ ObjectActionSpring::~ObjectActionSpring() {
} }
void ObjectActionSpring::updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep) { void ObjectActionSpring::updateAction(btCollisionWorld* collisionWorld, btScalar deltaTimeStep) {
if (!_ownerEntity) {
qDebug() << "ObjectActionSpring::updateAction no owner entity";
return;
}
if (!tryLockForRead()) { if (!tryLockForRead()) {
// don't risk hanging the thread running the physics simulation // don't risk hanging the thread running the physics simulation
return; return;
@ -111,6 +115,7 @@ bool ObjectActionSpring::updateArguments(QVariantMap arguments) {
if (rtOk) { if (rtOk) {
_rotationalTarget = rotationalTarget; _rotationalTarget = rotationalTarget;
_rotationalTargetSet = true;
if (rscOk) { if (rscOk) {
_angularTimeScale = angularTimeScale; _angularTimeScale = angularTimeScale;