Merge branch 'master' of github.com:highfidelity/hifi into parents

This commit is contained in:
Seth Alves 2015-11-03 16:53:00 -08:00
commit ffb0317a50
9 changed files with 70 additions and 128 deletions

View file

@ -176,6 +176,9 @@ function MyController(hand) {
this.pointer = null; // entity-id of line object
this.triggerValue = 0; // rolling average of trigger value
this.rawTriggerValue = 0;
this.offsetPosition = { x: 0.0, y: 0.0, z: 0.0 };
this.offsetRotation = { x: 0.0, y: 0.0, z: 0.0, w: 1.0 };
var _this = this;
@ -291,7 +294,7 @@ function MyController(hand) {
return this.triggerValue < TRIGGER_OFF_VALUE;
};
this.triggerSqueezed = function() {
this.triggerSqueezed = function() {
var triggerValue = this.rawTriggerValue;
return triggerValue > TRIGGER_ON_VALUE;
};
@ -352,7 +355,7 @@ function MyController(hand) {
var intersection = Entities.findRayIntersection(pickRayBacked, true);
if (intersection.intersects && !intersection.properties.locked) {
if (intersection.intersects) {
// the ray is intersecting something we can move.
var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection);
this.grabbedEntity = intersection.entityID;
@ -381,7 +384,7 @@ function MyController(hand) {
// the hand is very close to the intersected object. go into close-grabbing mode.
if (grabbableData.wantsTrigger) {
this.setState(STATE_NEAR_GRABBING_NON_COLLIDING);
} else {
} else if (!intersection.properties.locked) {
this.setState(STATE_NEAR_GRABBING);
}
} else {
@ -390,7 +393,8 @@ function MyController(hand) {
this.grabbedEntity = null;
} else {
// the hand is far from the intersected object. go into distance-holding mode
if (intersection.properties.collisionsWillMove) {
if (intersection.properties.collisionsWillMove
&& !intersection.properties.locked) {
this.setState(STATE_DISTANCE_HOLDING);
} else {
this.setState(STATE_FAR_GRABBING_NON_COLLIDING);
@ -502,7 +506,7 @@ function MyController(hand) {
// How far did the avatar turn this timestep?
// Note: The following code is too long because we need a Quat.quatBetween() function
// that returns the minimum quaternion between two quaternions.
// that returns the minimum quaternion between two quaternions.
var currentOrientation = MyAvatar.orientation;
if (Quat.dot(currentOrientation, this.currentAvatarOrientation) < 0.0) {
var negativeCurrentOrientation = {

View file

@ -1,68 +0,0 @@
// createBoxes.js
// part of bubblewand
//
// Created by James B. Pollack @imgntn -- 09/07/2015
// Copyright 2015 High Fidelity, Inc.
//
// Loads a wand model and attaches the bubble wand behavior.
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
Script.include("https://raw.githubusercontent.com/highfidelity/hifi/master/examples/utilities.js");
Script.include("https://raw.githubusercontent.com/highfidelity/hifi/master/examples/libraries/utils.js");
var bubbleModel = 'http://hifi-public.s3.amazonaws.com/james/bubblewand/models/bubble/bubble.fbx?' + randInt(0, 10000);;
//var scriptURL'http://hifi-public.s3.amazonaws.com/james/bubblewand/scripts/wand.js?'+randInt(0,10000);
//for local testing
//var scriptURL = "http://localhost:8080/scripts/setRecurringTimeout.js?" + randInt(0, 10000);
var scriptURL='http://hifi-public.s3.amazonaws.com/james/debug/timeouts/setRecurringTimeout.js?'+ randInt(0, 10000);
//create the wand in front of the avatar
var boxes=[];
var TEST_ENTITY_NAME = "TimerScript";
var TOTAL_ENTITIES = 100;
for (var i = 0; i < TOTAL_ENTITIES; i++) {
var box = Entities.addEntity({
type: "Box",
name: TEST_ENTITY_NAME,
position: {
x: randInt(0, 100) - 50 + MyAvatar.position.x,
y: randInt(0, 100) - 50 + MyAvatar.position.x,
z: randInt(0, 100) - 50 + MyAvatar.position.x,
},
dimensions: {
x: 1,
y: 1,
z: 1,
},
color: {
red: 255,
green: 0,
blue: 0,
},
//must be enabled to be grabbable in the physics engine
collisionsWillMove: true,
shapeType: 'box',
lifetime:60,
script: scriptURL
});
boxes.push(box)
}
function cleanup() {
while (boxes.length > 0) {
Entities.deleteEntity(boxes.pop());
}
}
Script.scriptEnding.connect(cleanup);

View file

@ -161,8 +161,7 @@ static QTimer locationUpdateTimer;
static QTimer balanceUpdateTimer;
static QTimer identityPacketTimer;
static QTimer billboardPacketTimer;
static QTimer checkFPStimer;
static QTimer idleTimer;
static QTimer pingTimer;
static const QString SNAPSHOT_EXTENSION = ".jpg";
static const QString SVO_EXTENSION = ".svo";
@ -186,9 +185,7 @@ static const quint64 TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS = 1 * USECS
static const QString INFO_HELP_PATH = "html/interface-welcome.html";
static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-commands.html";
static const unsigned int TARGET_SIM_FRAMERATE = 60;
static const unsigned int THROTTLED_SIM_FRAMERATE = 15;
static const int TARGET_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / TARGET_SIM_FRAMERATE;
static const int THROTTLED_SIM_FRAME_PERIOD_MS = MSECS_PER_SECOND / THROTTLED_SIM_FRAMERATE;
#ifndef __APPLE__
@ -847,8 +844,7 @@ void Application::cleanupBeforeQuit() {
balanceUpdateTimer.stop();
identityPacketTimer.stop();
billboardPacketTimer.stop();
checkFPStimer.stop();
idleTimer.stop();
pingTimer.stop();
QMetaObject::invokeMethod(&_settingsTimer, "stop", Qt::BlockingQueuedConnection);
// save state
@ -983,12 +979,9 @@ void Application::initializeGL() {
_entityEditSender.initialize(_enableProcessOctreeThread);
// call our timer function every second
connect(&checkFPStimer, &QTimer::timeout, this, &Application::checkFPS);
checkFPStimer.start(1000);
connect(&pingTimer, &QTimer::timeout, this, &Application::ping);
pingTimer.start(1000);
// call our idle function whenever we can
connect(&idleTimer, &QTimer::timeout, this, &Application::idle);
idleTimer.start(TARGET_SIM_FRAME_PERIOD_MS);
_idleLoopStdev.reset();
// update before the first render
@ -1052,6 +1045,26 @@ void Application::initializeUi() {
}
void Application::paintGL() {
_frameCount++;
// update fps moving average
uint64_t now = usecTimestampNow();
static uint64_t lastPaintBegin{ now };
uint64_t diff = now - lastPaintBegin;
if (diff != 0) {
_framesPerSecond.updateAverage((float)USECS_PER_SECOND / (float)diff);
}
lastPaintBegin = now;
// update fps once a second
if (now - _lastFramesPerSecondUpdate > USECS_PER_SECOND) {
_fps = _framesPerSecond.getAverage();
_lastFramesPerSecondUpdate = now;
}
idle(now);
PROFILE_RANGE(__FUNCTION__);
PerformanceTimer perfTimer("paintGL");
@ -1318,7 +1331,6 @@ void Application::paintGL() {
{
PerformanceTimer perfTimer("makeCurrent");
_offscreenContext->makeCurrent();
_frameCount++;
Stats::getInstance()->setRenderDetails(renderArgs._details);
// Reset the gpu::Context Stages
@ -2091,20 +2103,14 @@ bool Application::acceptSnapshot(const QString& urlString) {
return true;
}
// Every second, check the frame rates and other stuff
void Application::checkFPS() {
// Every second, send a ping, if menu item is checked.
void Application::ping() {
if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
DependencyManager::get<NodeList>()->sendPingPackets();
}
float diffTime = (float)_timerStart.nsecsElapsed() / 1000000000.0f;
_fps = (float)_frameCount / diffTime;
_frameCount = 0;
_timerStart.start();
}
void Application::idle() {
void Application::idle(uint64_t now) {
if (_aboutToQuit) {
return; // bail early, nothing to do here.
}
@ -2127,7 +2133,6 @@ void Application::idle() {
{
PROFILE_RANGE(__FUNCTION__);
uint64_t now = usecTimestampNow();
static uint64_t lastIdleStart{ now };
uint64_t idleStartToStartDuration = now - lastIdleStart;
if (idleStartToStartDuration != 0) {

View file

@ -306,8 +306,8 @@ public slots:
private slots:
void clearDomainOctreeDetails();
void checkFPS();
void idle();
void ping();
void idle(uint64_t now);
void aboutToQuit();
void handleScriptEngineLoaded(const QString& scriptFilename);
@ -541,6 +541,8 @@ private:
EntityItemID _keyboardFocusedItem;
quint64 _lastAcceptedKeyPress = 0;
SimpleMovingAverage _framesPerSecond{10};
quint64 _lastFramesPerSecondUpdate = 0;
SimpleMovingAverage _simsPerSecond{10};
int _simsPerSecondReport = 0;
quint64 _lastSimsPerSecondUpdate = 0;

View file

@ -286,10 +286,10 @@ void AvatarManager::handleOutgoingChanges(const VectorOfMotionStates& motionStat
void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents) {
for (Collision collision : collisionEvents) {
// TODO: Current physics uses null idA or idB for non-entities. The plan is to handle MOTIONSTATE_TYPE_AVATAR,
// and then MOTIONSTATE_TYPE_MYAVATAR. As it is, this code only covers the case of my avatar (in which case one
// if the ids will be null), and the behavior for other avatars is not specified. This has to be fleshed
// out as soon as we use the new motionstates.
// TODO: The plan is to handle MOTIONSTATE_TYPE_AVATAR, and then MOTIONSTATE_TYPE_MYAVATAR. As it is, other
// people's avatars will have an id that doesn't match any entities, and one's own avatar will have
// an id of null. Thus this code handles any collision in which one of the participating objects is
// my avatar. (Other user machines will make a similar analysis and inject sound for their collisions.)
if (collision.idA.isNull() || collision.idB.isNull()) {
MyAvatar* myAvatar = getMyAvatar();
const QString& collisionSoundURL = myAvatar->getCollisionSoundURL();
@ -299,9 +299,7 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents
const bool isSound = (collision.type == CONTACT_EVENT_TYPE_START) && (velocityChange > MIN_AVATAR_COLLISION_ACCELERATION);
if (!isSound) {
// TODO: When the new motion states are used, we'll probably break from the whole loop as soon as we hit our own avatar
// (regardless of isSound), because other users should inject for their own avatars.
continue;
return; // No sense iterating for others. We only have one avatar.
}
// Your avatar sound is personal to you, so let's say the "mass" part of the kinetic energy is already accounted for.
const float energy = velocityChange * velocityChange;
@ -314,7 +312,7 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents
AudioInjector::playSound(collisionSoundURL, energyFactorOfFull, AVATAR_STRETCH_FACTOR, myAvatar->getPosition());
myAvatar->collisionWithEntity(collision);
}
return; }
}
}
}

View file

@ -18,6 +18,7 @@
AvatarMotionState::AvatarMotionState(Avatar* avatar, btCollisionShape* shape) : ObjectMotionState(shape), _avatar(avatar) {
assert(_avatar);
_type = MOTIONSTATE_TYPE_AVATAR;
if (_shape) {
_mass = 100.0f; // HACK
}

View file

@ -120,6 +120,8 @@ MyAvatar::MyAvatar(RigPointer rig) :
connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired,
this, &MyAvatar::goToLocation);
_characterController.setEnabled(true);
_bodySensorMatrix = deriveBodyFromHMDSensor();
}
MyAvatar::~MyAvatar() {
@ -340,23 +342,6 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
}
void MyAvatar::updateHMDFollowVelocity() {
bool isMoving;
if (_lastIsMoving) {
const float MOVE_EXIT_SPEED_THRESHOLD = 0.07f; // m/sec
isMoving = glm::length(_velocity) >= MOVE_EXIT_SPEED_THRESHOLD;
} else {
const float MOVE_ENTER_SPEED_THRESHOLD = 0.2f; // m/sec
isMoving = glm::length(_velocity) > MOVE_ENTER_SPEED_THRESHOLD;
}
bool justStartedMoving = (_lastIsMoving != isMoving) && isMoving;
_lastIsMoving = isMoving;
bool hmdIsAtRest = _hmdAtRestDetector.update(_hmdSensorPosition, _hmdSensorOrientation);
if (hmdIsAtRest || justStartedMoving) {
_isFollowingHMD = true;
}
// compute offset to body's target position (in sensor-frame)
auto sensorBodyMatrix = deriveBodyFromHMDSensor();
_hmdFollowOffset = extractTranslation(sensorBodyMatrix) - extractTranslation(_bodySensorMatrix);
@ -365,13 +350,29 @@ void MyAvatar::updateHMDFollowVelocity() {
// don't pull the body DOWN to match the target (allow animation system to squat)
truncatedOffset.y = 0.0f;
}
float truncatedOffsetDistance = glm::length(truncatedOffset);
bool isMoving;
if (_lastIsMoving) {
const float MOVE_EXIT_SPEED_THRESHOLD = 0.07f; // m/sec
isMoving = glm::length(_velocity) >= MOVE_EXIT_SPEED_THRESHOLD;
} else {
const float MOVE_ENTER_SPEED_THRESHOLD = 0.2f; // m/sec
isMoving = glm::length(_velocity) > MOVE_ENTER_SPEED_THRESHOLD;
}
bool justStartedMoving = (_lastIsMoving != isMoving) && isMoving;
_lastIsMoving = isMoving;
bool hmdIsAtRest = _hmdAtRestDetector.update(_hmdSensorPosition, _hmdSensorOrientation);
const float MIN_HMD_HIP_SHIFT = 0.05f;
if (justStartedMoving || (hmdIsAtRest && truncatedOffsetDistance > MIN_HMD_HIP_SHIFT)) {
_isFollowingHMD = true;
}
bool needNewFollowSpeed = (_isFollowingHMD && _hmdFollowSpeed == 0.0f);
if (!needNewFollowSpeed) {
// check to see if offset has exceeded its threshold
float distance = glm::length(truncatedOffset);
const float MAX_HMD_HIP_SHIFT = 0.2f;
if (distance > MAX_HMD_HIP_SHIFT) {
if (truncatedOffsetDistance > MAX_HMD_HIP_SHIFT) {
_isFollowingHMD = true;
needNewFollowSpeed = true;
}

View file

@ -152,7 +152,6 @@ public slots:
Q_INVOKABLE glm::vec3 localCoordsToVoxelCoords(const QUuid& entityID, glm::vec3 localCoords);
signals:
void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);
void canAdjustLocksChanged(bool canAdjustLocks);

View file

@ -360,16 +360,16 @@ const CollisionEvents& PhysicsEngine::getCollisionEvents() {
glm::vec3 velocityChange = (motionStateA ? motionStateA->getObjectLinearVelocityChange() : glm::vec3(0.0f)) +
(motionStateB ? motionStateB->getObjectLinearVelocityChange() : glm::vec3(0.0f));
if (motionStateA && motionStateA->getType() == MOTIONSTATE_TYPE_ENTITY) {
if (motionStateA) {
QUuid idA = motionStateA->getObjectID();
QUuid idB;
if (motionStateB && motionStateB->getType() == MOTIONSTATE_TYPE_ENTITY) {
if (motionStateB) {
idB = motionStateB->getObjectID();
}
glm::vec3 position = bulletToGLM(contact.getPositionWorldOnB()) + _originOffset;
glm::vec3 penetration = bulletToGLM(contact.distance * contact.normalWorldOnB);
_collisionEvents.push_back(Collision(type, idA, idB, position, penetration, velocityChange));
} else if (motionStateB && motionStateB->getType() == MOTIONSTATE_TYPE_ENTITY) {
} else if (motionStateB) {
QUuid idB = motionStateB->getObjectID();
glm::vec3 position = bulletToGLM(contact.getPositionWorldOnA()) + _originOffset;
// NOTE: we're flipping the order of A and B (so that the first objectID is never NULL)