From d74856e01b50737a44d900299974187b901ab925 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 24 Feb 2015 11:21:04 -0800 Subject: [PATCH 1/4] add angularVelocity to controller --- interface/src/devices/SixenseManager.cpp | 12 ++++++++++++ .../scripting/ControllerScriptingInterface.cpp | 15 +++++++++++++++ .../src/scripting/ControllerScriptingInterface.h | 1 + libraries/avatars/src/HandData.cpp | 2 +- libraries/avatars/src/HandData.h | 4 +++- 5 files changed, 32 insertions(+), 2 deletions(-) diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index ffaa5260db..609ac7b349 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -260,6 +260,18 @@ void SixenseManager::update(float deltaTime) { float sign = (i == 0) ? -1.0f : 1.0f; rotation *= glm::angleAxis(sign * PI/4.0f, glm::vec3(0.0f, 0.0f, 1.0f)); + // Angular Velocity of Palm + glm::quat deltaRotation = rotation * glm::inverse(palm->getRawRotation()); + glm::vec3 angularVelocity(0.0f); + float rotationAngle = glm::angle(deltaRotation); + if ((rotationAngle > EPSILON) && (deltaTime > 0.0f)) { + angularVelocity = glm::normalize(glm::axis(deltaRotation)); + angularVelocity *= (rotationAngle / deltaTime); + palm->setRawAngularVelocity(angularVelocity); + } else { + palm->setRawAngularVelocity(glm::vec3(0.0f)); + } + if (_lowVelocityFilter) { // Use a velocity sensitive filter to damp small motions and preserve large ones with // no latency. diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index 929a763e70..2188f45374 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -208,6 +208,21 @@ glm::quat ControllerScriptingInterface::getSpatialControlRawRotation(int control } return glm::quat(); // bad index } + +glm::vec3 ControllerScriptingInterface::getSpatialControlRawAngularVelocity(int controlIndex) const { + int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM; + int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM; + const PalmData* palmData = getActivePalm(palmIndex); + if (palmData) { + switch (controlOfPalm) { + case PALM_SPATIALCONTROL: + return palmData->getRawAngularVelocity(); + case TIP_SPATIALCONTROL: + return palmData->getRawAngularVelocity(); // Tip = palm angular velocity + } + } + return glm::vec3(0); // bad index +} glm::vec3 ControllerScriptingInterface::getSpatialControlNormal(int controlIndex) const { int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM; diff --git a/interface/src/scripting/ControllerScriptingInterface.h b/interface/src/scripting/ControllerScriptingInterface.h index d56d159c06..c088dd6c9a 100644 --- a/interface/src/scripting/ControllerScriptingInterface.h +++ b/interface/src/scripting/ControllerScriptingInterface.h @@ -96,6 +96,7 @@ public slots: virtual glm::vec3 getSpatialControlVelocity(int controlIndex) const; virtual glm::vec3 getSpatialControlNormal(int controlIndex) const; virtual glm::quat getSpatialControlRawRotation(int controlIndex) const; + virtual glm::vec3 getSpatialControlRawAngularVelocity(int controlIndex) const; virtual void captureKeyEvents(const KeyEvent& event); virtual void releaseKeyEvents(const KeyEvent& event); diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index 5d850d06d0..9a9b51c1c8 100644 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -67,7 +67,7 @@ PalmData::PalmData(HandData* owningHandData) : _rawRotation(0.0f, 0.0f, 0.0f, 1.0f), _rawPosition(0.0f), _rawVelocity(0.0f), -_rotationalVelocity(0.0f), +_rawAngularVelocity(0.0f), _totalPenetration(0.0f), _controllerButtons(0), _isActive(false), diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index 534ea67726..a5e2b2907e 100644 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -98,6 +98,8 @@ public: void setRawPosition(const glm::vec3& pos) { _rawPosition = pos; } void setRawVelocity(const glm::vec3& velocity) { _rawVelocity = velocity; } const glm::vec3& getRawVelocity() const { return _rawVelocity; } + void setRawAngularVelocity(const glm::vec3& angularVelocity) { _rawAngularVelocity = angularVelocity; } + const glm::vec3& getRawAngularVelocity() const { return _rawAngularVelocity; } void addToPosition(const glm::vec3& delta); void addToPenetration(const glm::vec3& penetration) { _totalPenetration += penetration; } @@ -148,7 +150,7 @@ private: glm::quat _rawRotation; glm::vec3 _rawPosition; glm::vec3 _rawVelocity; - glm::vec3 _rotationalVelocity; + glm::vec3 _rawAngularVelocity; glm::quat _lastRotation; glm::vec3 _tipPosition; From 7489b468f3a4f473ed6825ac5c81d12242330c01 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 24 Feb 2015 11:48:35 -0800 Subject: [PATCH 2/4] give angular velocity to the thrown ball --- examples/controllers/hydra/toyball.js | 72 +++++++++++++++++++-------- 1 file changed, 52 insertions(+), 20 deletions(-) diff --git a/examples/controllers/hydra/toyball.js b/examples/controllers/hydra/toyball.js index b2ce6c1463..06e7f5a2e7 100644 --- a/examples/controllers/hydra/toyball.js +++ b/examples/controllers/hydra/toyball.js @@ -29,15 +29,21 @@ var RIGHT_BUTTON_FWD = 11; var RIGHT_BUTTON_3 = 9; var BALL_RADIUS = 0.08; -var GRAVITY_STRENGTH = 1.0; +var GRAVITY_STRENGTH = 3.0; var HELD_COLOR = { red: 240, green: 0, blue: 0 }; var THROWN_COLOR = { red: 128, green: 0, blue: 0 }; +var averageLinearVelocity = [ { x: 0, y: 0, z : 0 }, { x: 0, y: 0, z : 0 } ]; + +var LIFETIME_SECONDS = 600; + +var BALL_MODEL_URL = "https://hifi-public.s3.amazonaws.com/ryan/baseball4.fbx"; + var leftBallAlreadyInHand = false; var rightBallAlreadyInHand = false; -var leftHandEntity; -var rightHandEntity; +var leftHandEntity = false; +var rightHandEntity = false; var newSound = SoundCache.getSound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/throw.raw"); var catchSound = SoundCache.getSound("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/catch.raw"); @@ -67,31 +73,55 @@ function checkControllerSide(whichSide) { var BUTTON_3; var TRIGGER; var palmPosition; + var palmRotation; var ballAlreadyInHand; var handMessage; + var linearVelocity; + var angularVelocity; + var AVERAGE_FACTOR = 0.33; if (whichSide == LEFT_PALM) { BUTTON_FWD = LEFT_BUTTON_FWD; BUTTON_3 = LEFT_BUTTON_3; TRIGGER = 0; palmPosition = Controller.getSpatialControlPosition(LEFT_PALM); + palmRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(LEFT_PALM)); ballAlreadyInHand = leftBallAlreadyInHand; handMessage = "LEFT"; + averageLinearVelocity[0] = Vec3.sum(Vec3.multiply(AVERAGE_FACTOR, Controller.getSpatialControlVelocity(LEFT_TIP)), + Vec3.multiply(1.0 - AVERAGE_FACTOR, averageLinearVelocity[0])); + linearVelocity = averageLinearVelocity[0]; + angularVelocity = Vec3.multiplyQbyV(MyAvatar.orientation, Controller.getSpatialControlRawAngularVelocity(LEFT_TIP)); + angularVelocity = Vec3.multiply(180.0 / Math.PI, angularVelocity); } else { BUTTON_FWD = RIGHT_BUTTON_FWD; BUTTON_3 = RIGHT_BUTTON_3; TRIGGER = 1; palmPosition = Controller.getSpatialControlPosition(RIGHT_PALM); + palmRotation = Quat.multiply(MyAvatar.orientation, Controller.getSpatialControlRawRotation(RIGHT_PALM)); ballAlreadyInHand = rightBallAlreadyInHand; + averageLinearVelocity[1] = Vec3.sum(Vec3.multiply(AVERAGE_FACTOR, Controller.getSpatialControlVelocity(RIGHT_TIP)), + Vec3.multiply(1.0 - AVERAGE_FACTOR, averageLinearVelocity[1])); + linearVelocity = averageLinearVelocity[1]; + angularVelocity = Vec3.multiplyQbyV(MyAvatar.orientation, Controller.getSpatialControlRawAngularVelocity(RIGHT_TIP)); + angularVelocity = Vec3.multiply(180.0 / Math.PI, angularVelocity); handMessage = "RIGHT"; } var grabButtonPressed = (Controller.isButtonPressed(BUTTON_FWD) || Controller.isButtonPressed(BUTTON_3) || (Controller.getTriggerValue(TRIGGER) > 0.5)); // If I don't currently have a ball in my hand, then try to catch closest one + if (leftHandEntity && !leftHandEntity.isKnownID) { + leftHandEntity = Entities.identifyEntity(leftHandEntity); + } + if (rightHandEntity && !rightHandEntity.isKnownID) { + rightHandEntity = Entities.identifyEntity(rightHandEntity); + } + if (!ballAlreadyInHand && grabButtonPressed) { var closestEntity = Entities.findClosestEntity(palmPosition, targetRadius); + //if (closestEntity.isKnownID && ((leftHandEntity && (closestEntity.id == leftHandEntity.id)) || (rightHandEntity && (closestEntity.id == rightHandEntity.id)))) { if (closestEntity.isKnownID) { debugPrint(handMessage + " HAND- CAUGHT SOMETHING!!"); @@ -107,13 +137,14 @@ function checkControllerSide(whichSide) { var properties = { position: { x: ballPosition.x, y: ballPosition.y, z: ballPosition.z }, - color: HELD_COLOR, + rotation: palmRotation, + color: HELD_COLOR, velocity : { x: 0, y: 0, z: 0}, - lifetime : 600, - inHand: true }; + gravity: { x: 0, y: 0, z: 0} + }; Entities.editEntity(closestEntity, properties); - Audio.playSound(catchSound, { position: ballPosition }); + Audio.playSound(catchSound, { position: ballPosition }); return; // exit early } @@ -129,18 +160,20 @@ function checkControllerSide(whichSide) { if (grabButtonPressed && !ballAlreadyInHand) { var ballPosition = getBallHoldPosition(whichSide); var properties = { - type: "Sphere", + type: "Model", + modelURL: BALL_MODEL_URL, position: { x: ballPosition.x, y: ballPosition.y, - z: ballPosition.z }, + z: ballPosition.z }, + rotation: palmRotation, velocity: { x: 0, y: 0, z: 0}, gravity: { x: 0, y: 0, z: 0}, - inHand: true, dimensions: { x: BALL_RADIUS * 2, y: BALL_RADIUS * 2, z: BALL_RADIUS * 2 }, damping: 0.00001, + shapeType: "sphere", + collisionsWillMove: false, color: HELD_COLOR, - - lifetime: 600 // 10 seconds - same as default, not needed but here as an example + lifetime: LIFETIME_SECONDS }; newEntity = Entities.addEntity(properties); @@ -174,21 +207,20 @@ function checkControllerSide(whichSide) { var properties = { position: { x: ballPosition.x, y: ballPosition.y, z: ballPosition.z }, + rotation: palmRotation, + velocity: { x: 0, y: 0, z: 0}, + gravity: { x: 0, y: 0, z: 0}, }; Entities.editEntity(handEntity, properties); } else { debugPrint(">>>>> " + handMessage + "-BALL IN HAND, not grabbing, THROW!!!"); // If toy ball just released, add velocity to it! - var tipVelocity = Controller.getSpatialControlVelocity(whichTip); - var THROWN_VELOCITY_SCALING = 1.5; var properties = { - velocity: { x: tipVelocity.x * THROWN_VELOCITY_SCALING, - y: tipVelocity.y * THROWN_VELOCITY_SCALING, - z: tipVelocity.z * THROWN_VELOCITY_SCALING } , + velocity: linearVelocity, + rotation: palmRotation, + angularVelocity: angularVelocity, collisionsWillMove: true, - inHand: false, color: THROWN_COLOR, - lifetime: 10, gravity: { x: 0, y: -GRAVITY_STRENGTH, z: 0}, }; @@ -216,7 +248,7 @@ function checkController(deltaTime) { // this is expected for hydras if (!(numberOfButtons==12 && numberOfTriggers == 2 && controllersPerTrigger == 2)) { - debugPrint("no hydra connected?"); + debugPrint("total buttons = " + numberOfButtons + ", Triggers = " + numberOfTriggers + ", controllers/trigger = " + controllersPerTrigger); return; // bail if no hydra } From 9d021a1a1ee166e65c71ec003791cbb1fca5b5b3 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 24 Feb 2015 11:49:12 -0800 Subject: [PATCH 3/4] remove unused line --- examples/controllers/hydra/toyball.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/controllers/hydra/toyball.js b/examples/controllers/hydra/toyball.js index 06e7f5a2e7..5306769e95 100644 --- a/examples/controllers/hydra/toyball.js +++ b/examples/controllers/hydra/toyball.js @@ -121,7 +121,6 @@ function checkControllerSide(whichSide) { if (!ballAlreadyInHand && grabButtonPressed) { var closestEntity = Entities.findClosestEntity(palmPosition, targetRadius); - //if (closestEntity.isKnownID && ((leftHandEntity && (closestEntity.id == leftHandEntity.id)) || (rightHandEntity && (closestEntity.id == rightHandEntity.id)))) { if (closestEntity.isKnownID) { debugPrint(handMessage + " HAND- CAUGHT SOMETHING!!"); From 573390b42960b394adb75cd16b6d48930288354c Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 24 Feb 2015 11:55:41 -0800 Subject: [PATCH 4/4] fix dice for collision shapes, add angular velocity --- examples/dice.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/dice.js b/examples/dice.js index d33da576c1..1205f38ee1 100644 --- a/examples/dice.js +++ b/examples/dice.js @@ -53,8 +53,10 @@ function shootDice(position, velocity) { position: position, velocity: velocity, rotation: Quat.fromPitchYawRollDegrees(Math.random() * 360, Math.random() * 360, Math.random() * 360), + angularVelocity: { x: Math.random() * 100, y: Math.random() * 100, z: Math.random() * 100 }, lifetime: LIFETIME, gravity: { x: 0, y: GRAVITY, z: 0 }, + shapeType: "box", collisionsWillMove: true })); position = Vec3.sum(position, Vec3.multiply(DIE_SIZE, Vec3.normalize(Quat.getRight(Camera.getOrientation()))));