This commit is contained in:
Andrzej Kapolka 2014-02-11 14:22:45 -08:00
commit edf8361cfc
15 changed files with 272 additions and 114 deletions

View file

@ -69,6 +69,12 @@ function checkCamera() {
var viewJoystickPosition = Controller.getJoystickPosition(VIEW_CONTROLLER);
yaw -= viewJoystickPosition.x * JOYSTICK_YAW_MAG * deltaTime;
pitch += viewJoystickPosition.y * JOYSTICK_PITCH_MAG * deltaTime;
if (yaw > 360) {
yaw -= 360;
}
if (yaw < -360) {
yaw += 360;
}
var orientation = Quat.fromPitchYawRoll(pitch, yaw, roll);
Camera.setOrientation(orientation);
}

210
examples/hydraMove.js Normal file
View file

@ -0,0 +1,210 @@
//
// hydraMove.js
// hifi
//
// Created by Brad Hefta-Gaub on 2/10/14.
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
//
// This is an example script that demonstrates use of the Controller and MyAvatar classes to implement
// avatar flying through the hydra/controller joysticks
//
//
var damping = 0.9;
var position = { x: MyAvatar.position.x, y: MyAvatar.position.y, z: MyAvatar.position.z };
var joysticksCaptured = false;
var THRUST_CONTROLLER = 0;
var VIEW_CONTROLLER = 1;
var INITIAL_THRUST_MULTPLIER = 1.0;
var THRUST_INCREASE_RATE = 1.05;
var MAX_THRUST_MULTIPLIER = 75.0;
var thrustMultiplier = INITIAL_THRUST_MULTPLIER;
var grabDelta = { x: 0, y: 0, z: 0};
var grabDeltaVelocity = { x: 0, y: 0, z: 0};
var grabStartRotation = { x: 0, y: 0, z: 0, w: 1};
var grabCurrentRotation = { x: 0, y: 0, z: 0, w: 1};
var grabbingWithRightHand = false;
var wasGrabbingWithRightHand = false;
var grabbingWithLeftHand = false;
var wasGrabbingWithLeftHand = false;
var EPSILON = 0.000001;
var velocity = { x: 0, y: 0, z: 0};
var deltaTime = 1/60; // approximately our FPS - maybe better to be elapsed time since last call
var THRUST_MAG_UP = 800.0;
var THRUST_MAG_DOWN = 300.0;
var THRUST_MAG_FWD = 500.0;
var THRUST_MAG_BACK = 300.0;
var THRUST_MAG_LATERAL = 250.0;
var THRUST_JUMP = 120.0;
var YAW_MAG = 500.0;
var PITCH_MAG = 100.0;
var THRUST_MAG_HAND_JETS = THRUST_MAG_FWD;
var JOYSTICK_YAW_MAG = YAW_MAG;
var JOYSTICK_PITCH_MAG = PITCH_MAG * 0.5;
var LEFT_PALM = 0;
var LEFT_BUTTON_4 = 4;
var RIGHT_PALM = 2;
var RIGHT_BUTTON_4 = 10;
// Used by handleGrabBehavior() for managing the grab position changes
function getAndResetGrabDelta() {
var HAND_GRAB_SCALE_DISTANCE = 2.0;
var delta = Vec3.multiply(grabDelta, (MyAvatar.scale * HAND_GRAB_SCALE_DISTANCE));
grabDelta = { x: 0, y: 0, z: 0};
var avatarRotation = MyAvatar.orientation;
var result = Vec3.multiplyQbyV(avatarRotation, Vec3.multiply(delta, -1));
return result;
}
// Used by handleGrabBehavior() for managing the grab velocity feature
function getAndResetGrabDeltaVelocity() {
var HAND_GRAB_SCALE_VELOCITY = 50.0;
var delta = Vec3.multiply(grabDeltaVelocity, (MyAvatar.scale * HAND_GRAB_SCALE_VELOCITY));
grabDeltaVelocity = { x: 0, y: 0, z: 0};
var avatarRotation = MyAvatar.orientation;
var result = Quat.multiply(avatarRotation, Vec3.multiply(delta, -1));
return result;
}
// Used by handleGrabBehavior() for managing the grab rotation feature
function getAndResetGrabRotation() {
var quatDiff = Quat.multiply(grabCurrentRotation, Quat.inverse(grabStartRotation));
grabStartRotation = grabCurrentRotation;
return quatDiff;
}
// handles all the grab related behavior: position (crawl), velocity (flick), and rotate (twist)
function handleGrabBehavior() {
// check for and handle grab behaviors
grabbingWithRightHand = Controller.isButtonPressed(RIGHT_BUTTON_4);
grabbingWithLeftHand = Controller.isButtonPressed(LEFT_BUTTON_4);
stoppedGrabbingWithLeftHand = false;
stoppedGrabbingWithRightHand = false;
if (grabbingWithRightHand && !wasGrabbingWithRightHand) {
// Just starting grab, capture starting rotation
grabStartRotation = Controller.getSpatialControlRawRotation(RIGHT_PALM);
}
if (grabbingWithRightHand) {
grabDelta = Vec3.sum(grabDelta, Vec3.multiply(Controller.getSpatialControlVelocity(RIGHT_PALM), deltaTime));
grabCurrentRotation = Controller.getSpatialControlRawRotation(RIGHT_PALM);
}
if (!grabbingWithRightHand && wasGrabbingWithRightHand) {
// Just ending grab, capture velocity
grabDeltaVelocity = Controller.getSpatialControlVelocity(RIGHT_PALM);
stoppedGrabbingWithRightHand = true;
}
if (grabbingWithLeftHand && !wasGrabbingWithLeftHand) {
// Just starting grab, capture starting rotation
grabStartRotation = Controller.getSpatialControlRawRotation(LEFT_PALM);
}
if (grabbingWithLeftHand) {
grabDelta = Vec3.sum(grabDelta, Vec3.multiply(Controller.getSpatialControlVelocity(LEFT_PALM), deltaTime));
grabCurrentRotation = Controller.getSpatialControlRawRotation(LEFT_PALM);
}
if (!grabbingWithLeftHand && wasGrabbingWithLeftHand) {
// Just ending grab, capture velocity
grabDeltaVelocity = Controller.getSpatialControlVelocity(LEFT_PALM);
stoppedGrabbingWithLeftHand = true;
}
grabbing = grabbingWithRightHand || grabbingWithLeftHand;
stoppedGrabbing = stoppedGrabbingWithRightHand || stoppedGrabbingWithLeftHand;
if (grabbing) {
// move position
var moveFromGrab = getAndResetGrabDelta();
if (Vec3.length(moveFromGrab) > EPSILON) {
MyAvatar.position = Vec3.sum(MyAvatar.position, moveFromGrab);
velocity = { x: 0, y: 0, z: 0};
}
// add some rotation...
var deltaRotation = getAndResetGrabRotation();
var GRAB_CONTROLLER_TURN_SCALING = 0.5;
var euler = Vec3.multiply(Quat.safeEulerAngles(deltaRotation), GRAB_CONTROLLER_TURN_SCALING);
// Adjust body yaw by yaw from controller
var orientation = Quat.multiply(Quat.angleAxis(-euler.y, {x:0, y: 1, z:0}), MyAvatar.orientation);
MyAvatar.orientation = orientation;
// Adjust head pitch from controller
MyAvatar.headPitch = MyAvatar.headPitch - euler.x;
}
// add some velocity...
if (stoppedGrabbing) {
velocity = Vec3.sum(velocity, getAndResetGrabDeltaVelocity());
}
// handle residual velocity
if(Vec3.length(velocity) > EPSILON) {
MyAvatar.position = Vec3.sum(MyAvatar.position, Vec3.multiply(velocity, deltaTime));
// damp velocity
velocity = Vec3.multiply(velocity, damping);
}
wasGrabbingWithRightHand = grabbingWithRightHand;
wasGrabbingWithLeftHand = grabbingWithLeftHand;
}
// Main update function that handles flying and grabbing behaviort
function flyWithHydra() {
var thrustJoystickPosition = Controller.getJoystickPosition(THRUST_CONTROLLER);
if (thrustJoystickPosition.x != 0 || thrustJoystickPosition.y != 0) {
if (thrustMultiplier < MAX_THRUST_MULTIPLIER) {
thrustMultiplier *= 1 + (deltaTime * THRUST_INCREASE_RATE);
}
var currentOrientation = MyAvatar.orientation;
var front = Quat.getFront(currentOrientation);
var right = Quat.getRight(currentOrientation);
var up = Quat.getUp(currentOrientation);
var thrustFront = Vec3.multiply(front, MyAvatar.scale * THRUST_MAG_HAND_JETS *
thrustJoystickPosition.y * thrustMultiplier * deltaTime);
MyAvatar.addThrust(thrustFront);
var thrustRight = Vec3.multiply(right, MyAvatar.scale * THRUST_MAG_HAND_JETS *
thrustJoystickPosition.x * thrustMultiplier * deltaTime);
MyAvatar.addThrust(thrustRight);
} else {
thrustMultiplier = INITIAL_THRUST_MULTPLIER;
}
// View Controller
var viewJoystickPosition = Controller.getJoystickPosition(VIEW_CONTROLLER);
if (viewJoystickPosition.x != 0 || viewJoystickPosition.y != 0) {
// change the body yaw based on our x controller
var orientation = MyAvatar.orientation;
var deltaOrientation = Quat.fromPitchYawRoll(0, (-1 * viewJoystickPosition.x * JOYSTICK_YAW_MAG * deltaTime), 0);
MyAvatar.orientation = Quat.multiply(orientation, deltaOrientation);
// change the headPitch based on our x controller
//pitch += viewJoystickPosition.y * JOYSTICK_PITCH_MAG * deltaTime;
var newPitch = MyAvatar.headPitch + (viewJoystickPosition.y * JOYSTICK_PITCH_MAG * deltaTime);
MyAvatar.headPitch = newPitch;
}
handleGrabBehavior();
}
Script.willSendVisualDataCallback.connect(flyWithHydra);
Controller.captureJoystick(THRUST_CONTROLLER);
Controller.captureJoystick(VIEW_CONTROLLER);
// Map keyPress and mouse move events to our callbacks
function scriptEnding() {
// re-enabled the standard application for touch events
Controller.releaseJoystick(THRUST_CONTROLLER);
Controller.releaseJoystick(VIEW_CONTROLLER);
}
Script.scriptEnding.connect(scriptEnding);

View file

@ -4042,7 +4042,7 @@ void Application::loadScript(const QString& fileNameString) {
scriptEngine->getParticlesScriptingInterface()->setParticleTree(_particles.getTree());
// hook our avatar object into this script engine
scriptEngine->setAvatarData( static_cast<Avatar*>(_myAvatar), "MyAvatar");
scriptEngine->setAvatarData(_myAvatar, "MyAvatar"); // leave it as a MyAvatar class to expose thrust features
CameraScriptableObject* cameraScriptable = new CameraScriptableObject(&_myCamera, &_viewFrustum);
scriptEngine->registerGlobalObject("Camera", cameraScriptable);

View file

@ -172,6 +172,21 @@ glm::vec3 ControllerScriptingInterface::getSpatialControlVelocity(int controlInd
return glm::vec3(0); // bad index
}
glm::quat ControllerScriptingInterface::getSpatialControlRawRotation(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->getRawRotation();
case TIP_SPATIALCONTROL:
return palmData->getRawRotation(); // currently the tip doesn't have a unique rotation, use the palm rotation
}
}
return glm::quat(); // bad index
}
glm::vec3 ControllerScriptingInterface::getSpatialControlNormal(int controlIndex) const {
int palmIndex = controlIndex / NUMBER_OF_SPATIALCONTROLS_PER_PALM;
int controlOfPalm = controlIndex % NUMBER_OF_SPATIALCONTROLS_PER_PALM;

View file

@ -58,7 +58,7 @@ public slots:
virtual glm::vec3 getSpatialControlPosition(int controlIndex) const;
virtual glm::vec3 getSpatialControlVelocity(int controlIndex) const;
virtual glm::vec3 getSpatialControlNormal(int controlIndex) const;
virtual glm::quat getSpatialControlRawRotation(int controlIndex) const;
virtual void captureKeyEvents(const KeyEvent& event);
virtual void releaseKeyEvents(const KeyEvent& event);

View file

@ -32,12 +32,7 @@ Hand::Hand(Avatar* owningAvatar) :
_ballColor(0.0, 0.0, 0.4),
_collisionCenter(0,0,0),
_collisionAge(0),
_collisionDuration(0),
_pitchUpdate(0),
_grabDelta(0, 0, 0),
_grabDeltaVelocity(0, 0, 0),
_grabStartRotation(0, 0, 0, 1),
_grabCurrentRotation(0, 0, 0, 1)
_collisionDuration(0)
{
}
@ -54,28 +49,6 @@ void Hand::init() {
void Hand::reset() {
}
glm::vec3 Hand::getAndResetGrabDelta() {
const float HAND_GRAB_SCALE_DISTANCE = 2.f;
glm::vec3 delta = _grabDelta * _owningAvatar->getScale() * HAND_GRAB_SCALE_DISTANCE;
_grabDelta = glm::vec3(0,0,0);
glm::quat avatarRotation = _owningAvatar->getOrientation();
return avatarRotation * -delta;
}
glm::vec3 Hand::getAndResetGrabDeltaVelocity() {
const float HAND_GRAB_SCALE_VELOCITY = 5.f;
glm::vec3 delta = _grabDeltaVelocity * _owningAvatar->getScale() * HAND_GRAB_SCALE_VELOCITY;
_grabDeltaVelocity = glm::vec3(0,0,0);
glm::quat avatarRotation = _owningAvatar->getOrientation();
return avatarRotation * -delta;
}
glm::quat Hand::getAndResetGrabRotation() {
glm::quat diff = _grabCurrentRotation * glm::inverse(_grabStartRotation);
_grabStartRotation = _grabCurrentRotation;
return diff;
}
void Hand::simulate(float deltaTime, bool isMine) {
if (_collisionAge > 0.f) {
@ -99,19 +72,6 @@ void Hand::simulate(float deltaTime, bool isMine) {
_buckyBalls.grab(palm, fingerTipPosition, _owningAvatar->getOrientation(), deltaTime);
if (palm.getControllerButtons() & BUTTON_4) {
_grabDelta += palm.getRawVelocity() * deltaTime;
_grabCurrentRotation = palm.getRawRotation();
}
if ((palm.getLastControllerButtons() & BUTTON_4) && !(palm.getControllerButtons() & BUTTON_4)) {
// Just ending grab, capture velocity
_grabDeltaVelocity = palm.getRawVelocity();
}
if (!(palm.getLastControllerButtons() & BUTTON_4) && (palm.getControllerButtons() & BUTTON_4)) {
// Just starting grab, capture starting rotation
_grabStartRotation = palm.getRawRotation();
}
if (palm.getControllerButtons() & BUTTON_1) {
if (glm::length(fingerTipPosition - _lastFingerAddVoxel) > (FINGERTIP_VOXEL_SIZE / 2.f)) {
QColor paintColor = Menu::getInstance()->getActionForOption(MenuOption::VoxelPaintColor)->data().value<QColor>();

View file

@ -58,15 +58,6 @@ public:
const glm::vec3& getLeapFingerTipBallPosition (int ball) const { return _leapFingerTipBalls [ball].position;}
const glm::vec3& getLeapFingerRootBallPosition(int ball) const { return _leapFingerRootBalls[ball].position;}
// Pitch from controller input to view
const float getPitchUpdate() const { return _pitchUpdate; }
void setPitchUpdate(float pitchUpdate) { _pitchUpdate = pitchUpdate; }
// Get the drag distance to move
glm::vec3 getAndResetGrabDelta();
glm::vec3 getAndResetGrabDeltaVelocity();
glm::quat getAndResetGrabRotation();
private:
// disallow copies of the Hand, copy of owning Avatar is disallowed too
Hand(const Hand&);
@ -100,13 +91,6 @@ private:
void calculateGeometry();
void handleVoxelCollision(PalmData* palm, const glm::vec3& fingerTipPosition, VoxelTreeElement* voxel, float deltaTime);
float _pitchUpdate;
glm::vec3 _grabDelta;
glm::vec3 _grabDeltaVelocity;
glm::quat _grabStartRotation;
glm::quat _grabCurrentRotation;
};
#endif

View file

@ -328,21 +328,6 @@ void MyAvatar::simulate(float deltaTime) {
updateChatCircle(deltaTime);
// Get any position, velocity, or rotation update from Grab Drag controller
glm::vec3 moveFromGrab = _hand.getAndResetGrabDelta();
if (glm::length(moveFromGrab) > EPSILON) {
_position += moveFromGrab;
_velocity = glm::vec3(0, 0, 0);
}
_velocity += _hand.getAndResetGrabDeltaVelocity();
glm::quat deltaRotation = _hand.getAndResetGrabRotation();
const float GRAB_CONTROLLER_TURN_SCALING = 0.5f;
glm::vec3 euler = safeEulerAngles(deltaRotation) * GRAB_CONTROLLER_TURN_SCALING;
// Adjust body yaw by yaw from controller
setOrientation(glm::angleAxis(-euler.y, glm::vec3(0, 1, 0)) * getOrientation());
// Adjust head pitch from controller
getHead().setPitch(getHead().getPitch() - euler.x);
_position += _velocity * deltaTime;
// update avatar skeleton and simulate hand and head
@ -807,39 +792,6 @@ void MyAvatar::updateThrust(float deltaTime) {
up;
}
}
// Add thrust and rotation from hand controllers
const float THRUST_MAG_HAND_JETS = THRUST_MAG_FWD;
const float JOYSTICK_YAW_MAG = YAW_MAG;
const float JOYSTICK_PITCH_MAG = PITCH_MAG * 0.5f;
const int THRUST_CONTROLLER = 0;
const int VIEW_CONTROLLER = 1;
for (size_t i = 0; i < getHand().getPalms().size(); ++i) {
PalmData& palm = getHand().getPalms()[i];
// If the script hasn't captured this joystick, then let the default behavior work
if (!Application::getInstance()->getControllerScriptingInterface()->isJoystickCaptured(palm.getSixenseID())) {
if (palm.isActive() && (palm.getSixenseID() == THRUST_CONTROLLER)) {
if (palm.getJoystickY() != 0.f) {
FingerData& finger = palm.getFingers()[0];
if (finger.isActive()) {
}
_thrust += front * _scale * THRUST_MAG_HAND_JETS * palm.getJoystickY() * _thrustMultiplier * deltaTime;
}
if (palm.getJoystickX() != 0.f) {
_thrust += right * _scale * THRUST_MAG_HAND_JETS * palm.getJoystickX() * _thrustMultiplier * deltaTime;
}
} else if (palm.isActive() && (palm.getSixenseID() == VIEW_CONTROLLER)) {
if (palm.getJoystickX() != 0.f) {
_bodyYawDelta -= palm.getJoystickX() * JOYSTICK_YAW_MAG * deltaTime;
}
if (palm.getJoystickY() != 0.f) {
getHand().setPitchUpdate(getHand().getPitchUpdate() +
(palm.getJoystickY() * JOYSTICK_PITCH_MAG * deltaTime));
}
}
}
}
// Update speed brake status
const float MIN_SPEED_BRAKE_VELOCITY = _scale * 0.4f;

View file

@ -45,7 +45,6 @@ public:
// setters
void setMousePressed(bool mousePressed) { _mousePressed = mousePressed; }
void setThrust(glm::vec3 newThrust) { _thrust = newThrust; }
void setVelocity(const glm::vec3 velocity) { _velocity = velocity; }
void setLeanScale(float scale) { _leanScale = scale; }
void setGravity(glm::vec3 gravity);
@ -78,9 +77,6 @@ public:
static void sendKillAvatar();
// Set/Get update the thrust that will move the avatar around
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
glm::vec3 getThrust() { return _thrust; };
void orbit(const glm::vec3& position, int deltaX, int deltaY);
@ -94,9 +90,13 @@ public slots:
void increaseSize();
void decreaseSize();
void resetSize();
void sendIdentityPacket();
// Set/Get update the thrust that will move the avatar around
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
glm::vec3 getThrust() { return _thrust; };
void setThrust(glm::vec3 newThrust) { _thrust = newThrust; }
private:
bool _mousePressed;
float _bodyPitchDelta;

View file

@ -67,6 +67,7 @@ class AvatarData : public NodeData {
Q_OBJECT
Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPosition)
Q_PROPERTY(float scale READ getTargetScale WRITE setTargetScale)
Q_PROPERTY(glm::vec3 handPosition READ getHandPosition WRITE setHandPosition)
Q_PROPERTY(float bodyYaw READ getBodyYaw WRITE setBodyYaw)
Q_PROPERTY(float bodyPitch READ getBodyPitch WRITE setBodyPitch)

View file

@ -12,6 +12,7 @@
#include <QtCore/QObject>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
#include "EventTypes.h"
@ -37,6 +38,7 @@ public slots:
virtual glm::vec3 getSpatialControlPosition(int controlIndex) const = 0;
virtual glm::vec3 getSpatialControlVelocity(int controlIndex) const = 0;
virtual glm::vec3 getSpatialControlNormal(int controlIndex) const = 0;
virtual glm::quat getSpatialControlRawRotation(int controlIndex) const = 0;
virtual void captureKeyEvents(const KeyEvent& event) = 0;
virtual void releaseKeyEvents(const KeyEvent& event) = 0;

View file

@ -9,7 +9,10 @@
//
//
#include <glm/gtx/vector_angle.hpp>
#include <OctreeConstants.h>
#include <SharedUtil.h>
#include "Quat.h"
glm::quat Quat::multiply(const glm::quat& q1, const glm::quat& q2) {
@ -24,6 +27,11 @@ glm::quat Quat::fromPitchYawRoll(float pitch, float yaw, float roll) {
return glm::quat(glm::radians(glm::vec3(pitch, yaw, roll)));
}
glm::quat Quat::inverse(const glm::quat& q) {
return glm::inverse(q);
}
glm::vec3 Quat::getFront(const glm::quat& orientation) {
return orientation * IDENTITY_FRONT;
}
@ -35,3 +43,12 @@ glm::vec3 Quat::getRight(const glm::quat& orientation) {
glm::vec3 Quat::getUp(const glm::quat& orientation) {
return orientation * IDENTITY_UP;
}
glm::vec3 Quat::safeEulerAngles(const glm::quat& orientation) {
return ::safeEulerAngles(orientation);
}
glm::quat Quat::angleAxis(float angle, const glm::vec3& v) {
return glm::angleAxis(angle, v);
}

View file

@ -23,11 +23,12 @@ public slots:
glm::quat multiply(const glm::quat& q1, const glm::quat& q2);
glm::quat fromVec3(const glm::vec3& vec3);
glm::quat fromPitchYawRoll(float pitch, float yaw, float roll);
glm::quat inverse(const glm::quat& q);
glm::vec3 getFront(const glm::quat& orientation);
glm::vec3 getRight(const glm::quat& orientation);
glm::vec3 getUp(const glm::quat& orientation);
glm::vec3 safeEulerAngles(const glm::quat& orientation);
glm::quat angleAxis(float angle, const glm::vec3& v);
};
#endif /* defined(__hifi__Quat__) */

View file

@ -19,6 +19,14 @@ glm::vec3 Vec3::multiply(const glm::vec3& v1, float f) {
return v1 * f;
}
glm::vec3 Vec3::multiplyQbyV(const glm::quat& q, const glm::vec3& v) {
return q * v;
}
glm::vec3 Vec3::sum(const glm::vec3& v1, const glm::vec3& v2) {
return v1 + v2;
}
float Vec3::length(const glm::vec3& v) {
return glm::length(v);
}

View file

@ -23,7 +23,9 @@ class Vec3 : public QObject {
public slots:
glm::vec3 multiply(const glm::vec3& v1, const glm::vec3& v2);
glm::vec3 multiply(const glm::vec3& v1, float f);
glm::vec3 multiplyQbyV(const glm::quat& q, const glm::vec3& v);
glm::vec3 sum(const glm::vec3& v1, const glm::vec3& v2);
float length(const glm::vec3& v);
};