Merge branch 'master' into 20812

This commit is contained in:
David Rowe 2016-03-01 11:16:14 +13:00
commit ddc5e952f1
29 changed files with 917 additions and 714 deletions

View file

@ -277,14 +277,17 @@ void EntityServer::readAdditionalConfiguration(const QJsonObject& settingsSectio
// set of stats to have, but we'd probably want a different data structure if we keep it very long. // set of stats to have, but we'd probably want a different data structure if we keep it very long.
// Since this version uses a single shared QMap for all senders, there could be some lock contention // Since this version uses a single shared QMap for all senders, there could be some lock contention
// on this QWriteLocker // on this QWriteLocker
void EntityServer::trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode) { void EntityServer::trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& sessionID) {
QWriteLocker locker(&_viewerSendingStatsLock); QWriteLocker locker(&_viewerSendingStatsLock);
_viewerSendingStats[viewerNode][dataID] = { usecTimestampNow(), dataLastEdited }; _viewerSendingStats[sessionID][dataID] = { usecTimestampNow(), dataLastEdited };
} }
void EntityServer::trackViewerGone(const QUuid& viewerNode) { void EntityServer::trackViewerGone(const QUuid& sessionID) {
QWriteLocker locker(&_viewerSendingStatsLock); QWriteLocker locker(&_viewerSendingStatsLock);
_viewerSendingStats.remove(viewerNode); _viewerSendingStats.remove(sessionID);
if (_entitySimulation) {
_entitySimulation->clearOwnership(sessionID);
}
} }
QString EntityServer::serverSubclassStats() { QString EntityServer::serverSubclassStats() {

View file

@ -27,6 +27,8 @@ struct ViewerSendingStats {
quint64 lastEdited; quint64 lastEdited;
}; };
class SimpleEntitySimulation;
class EntityServer : public OctreeServer, public NewlyCreatedEntityHook { class EntityServer : public OctreeServer, public NewlyCreatedEntityHook {
Q_OBJECT Q_OBJECT
public: public:
@ -52,8 +54,8 @@ public:
virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject) override; virtual void readAdditionalConfiguration(const QJsonObject& settingsSectionObject) override;
virtual QString serverSubclassStats() override; virtual QString serverSubclassStats() override;
virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& viewerNode) override; virtual void trackSend(const QUuid& dataID, quint64 dataLastEdited, const QUuid& sessionID) override;
virtual void trackViewerGone(const QUuid& viewerNode) override; virtual void trackViewerGone(const QUuid& sessionID) override;
public slots: public slots:
void pruneDeletedEntities(); void pruneDeletedEntities();
@ -65,7 +67,7 @@ private slots:
void handleEntityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode); void handleEntityPacket(QSharedPointer<ReceivedMessage> message, SharedNodePointer senderNode);
private: private:
EntitySimulation* _entitySimulation; SimpleEntitySimulation* _entitySimulation;
QTimer* _pruneDeletedEntitiesTimer = nullptr; QTimer* _pruneDeletedEntitiesTimer = nullptr;
QReadWriteLock _viewerSendingStatsLock; QReadWriteLock _viewerSendingStatsLock;

View file

@ -1,3 +1,4 @@
"use strict";
// handControllerGrab.js // handControllerGrab.js
// //
// Created by Eric Levin on 9/2/15 // Created by Eric Levin on 9/2/15
@ -801,6 +802,8 @@ function MyController(hand) {
this.isInitialGrab = false; this.isInitialGrab = false;
this.doubleParentGrab = false; this.doubleParentGrab = false;
this.checkForStrayChildren();
if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) { if (this.state == STATE_SEARCHING ? this.triggerSmoothedReleased() : this.bumperReleased()) {
this.setState(STATE_RELEASE); this.setState(STATE_RELEASE);
return; return;
@ -1444,6 +1447,13 @@ function MyController(hand) {
this.heartBeat(this.grabbedEntity); this.heartBeat(this.grabbedEntity);
var props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "parentID", "position"]); var props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "parentID", "position"]);
if (!props.position) {
// server may have reset, taking our equipped entity with it. move back to "off" stte
this.setState(STATE_RELEASE);
this.callEntityMethodOnGrabbed("releaseGrab");
return;
}
if (props.parentID == MyAvatar.sessionUUID && if (props.parentID == MyAvatar.sessionUUID &&
Vec3.length(props.localPosition) > NEAR_PICK_MAX_DISTANCE * 2.0) { Vec3.length(props.localPosition) > NEAR_PICK_MAX_DISTANCE * 2.0) {
// for whatever reason, the held/equipped entity has been pulled away. ungrab or unequip. // for whatever reason, the held/equipped entity has been pulled away. ungrab or unequip.
@ -1751,6 +1761,17 @@ function MyController(hand) {
return data; return data;
}; };
this.checkForStrayChildren = function() {
// sometimes things can get parented to a hand and this script is unaware. Search for such entities and
// unhook them.
var handJointIndex = MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? "RightHand" : "LeftHand");
var children = Entities.getChildrenIDsOfJoint(MyAvatar.sessionUUID, handJointIndex);
children.forEach(function(childID) {
print("disconnecting stray child of hand: (" + _this.hand + ") " + childID);
Entities.editEntity(childID, {parentID: NULL_UUID});
});
}
this.deactivateEntity = function(entityID, noVelocity) { this.deactivateEntity = function(entityID, noVelocity) {
var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {}); var data = getEntityCustomData(GRAB_USER_DATA_KEY, entityID, {});
if (data && data["refCount"]) { if (data && data["refCount"]) {

View file

@ -12,17 +12,23 @@
var APPARENT_2D_OVERLAY_DEPTH = 1.0; var APPARENT_2D_OVERLAY_DEPTH = 1.0;
var APPARENT_MAXIMUM_DEPTH = 100.0; // this is a depth at which things all seem sufficiently distant var APPARENT_MAXIMUM_DEPTH = 100.0; // this is a depth at which things all seem sufficiently distant
var lastDepthCheckTime = 0; var lastDepthCheckTime = Date.now();
var desiredDepth = APPARENT_2D_OVERLAY_DEPTH;
var TIME_BETWEEN_DEPTH_CHECKS = 100;
var MINIMUM_DEPTH_ADJUST = 0.01;
var NON_LINEAR_DIVISOR = 2;
Script.update.connect(function(deltaTime) { Script.update.connect(function(deltaTime) {
var TIME_BETWEEN_DEPTH_CHECKS = 100; var now = Date.now();
var timeSinceLastDepthCheck = Date.now() - lastDepthCheckTime; var timeSinceLastDepthCheck = now - lastDepthCheckTime;
if (timeSinceLastDepthCheck > TIME_BETWEEN_DEPTH_CHECKS) { if (timeSinceLastDepthCheck > TIME_BETWEEN_DEPTH_CHECKS) {
var newDesiredDepth = desiredDepth;
lastDepthCheckTime = now;
var reticlePosition = Reticle.position; var reticlePosition = Reticle.position;
// first check the 2D Overlays // first check the 2D Overlays
if (Reticle.pointingAtSystemOverlay || Overlays.getOverlayAtPoint(reticlePosition)) { if (Reticle.pointingAtSystemOverlay || Overlays.getOverlayAtPoint(reticlePosition)) {
Reticle.setDepth(APPARENT_2D_OVERLAY_DEPTH); newDesiredDepth = APPARENT_2D_OVERLAY_DEPTH;
} else { } else {
var pickRay = Camera.computePickRay(reticlePosition.x, reticlePosition.y); var pickRay = Camera.computePickRay(reticlePosition.x, reticlePosition.y);
@ -37,11 +43,30 @@ Script.update.connect(function(deltaTime) {
// If either the overlays or entities intersect, then set the reticle depth to // If either the overlays or entities intersect, then set the reticle depth to
// the distance of intersection // the distance of intersection
if (result.intersects) { if (result.intersects) {
Reticle.setDepth(result.distance); newDesiredDepth = result.distance;
} else { } else {
// if nothing intersects... set the depth to some sufficiently large depth // if nothing intersects... set the depth to some sufficiently large depth
Reticle.setDepth(APPARENT_MAXIMUM_DEPTH); newDesiredDepth = APPARENT_MAXIMUM_DEPTH;
} }
} }
// If the desired depth has changed, reset our fade start time
if (desiredDepth != newDesiredDepth) {
desiredDepth = newDesiredDepth;
}
}
// move the reticle toward the desired depth
if (desiredDepth != Reticle.depth) {
// cut distance between desiredDepth and current depth in half until we're close enough
var distanceToAdjustThisCycle = (desiredDepth - Reticle.depth) / NON_LINEAR_DIVISOR;
if (Math.abs(distanceToAdjustThisCycle) < MINIMUM_DEPTH_ADJUST) {
newDepth = desiredDepth;
} else {
newDepth = Reticle.depth + distanceToAdjustThisCycle;
}
Reticle.setDepth(newDepth);
} }
}); });

View file

@ -711,13 +711,32 @@ var intersection;
var SCALE_FACTOR = 200.0; var SCALE_FACTOR = 200.0;
function rayPlaneIntersection(pickRay, point, normal) { function rayPlaneIntersection(pickRay, point, normal) { //
//
// This version of the test returns the intersection of a line with a plane
//
var collides = Vec3.dot(pickRay.direction, normal);
var d = -Vec3.dot(point, normal); var d = -Vec3.dot(point, normal);
var t = -(Vec3.dot(pickRay.origin, normal) + d) / Vec3.dot(pickRay.direction, normal); var t = -(Vec3.dot(pickRay.origin, normal) + d) / collides;
return Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, t)); return Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, t));
} }
function rayPlaneIntersection2(pickRay, point, normal) {
//
// This version of the test returns false if the ray is directed away from the plane
//
var collides = Vec3.dot(pickRay.direction, normal);
var d = -Vec3.dot(point, normal);
var t = -(Vec3.dot(pickRay.origin, normal) + d) / collides;
if (t < 0.0) {
return false;
} else {
return Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, t));
}
}
function findClickedEntity(event) { function findClickedEntity(event) {
var pickZones = event.isControl; var pickZones = event.isControl;
@ -758,7 +777,8 @@ function findClickedEntity(event) {
var foundEntity = result.entityID; var foundEntity = result.entityID;
return { return {
pickRay: pickRay, pickRay: pickRay,
entityID: foundEntity entityID: foundEntity,
intersection: result.intersection
}; };
} }
@ -926,6 +946,7 @@ function mouseReleaseEvent(event) {
} }
function mouseClickEvent(event) { function mouseClickEvent(event) {
var wantDebug = false;
if (isActive && event.isLeftButton) { if (isActive && event.isLeftButton) {
var result = findClickedEntity(event); var result = findClickedEntity(event);
if (result === null) { if (result === null) {
@ -940,11 +961,15 @@ function mouseClickEvent(event) {
var properties = Entities.getEntityProperties(foundEntity); var properties = Entities.getEntityProperties(foundEntity);
if (isLocked(properties)) { if (isLocked(properties)) {
print("Model locked " + properties.id); if (wantDebug) {
print("Model locked " + properties.id);
}
} else { } else {
var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; var halfDiagonal = Vec3.length(properties.dimensions) / 2.0;
print("Checking properties: " + properties.id + " " + " - Half Diagonal:" + halfDiagonal); if (wantDebug) {
print("Checking properties: " + properties.id + " " + " - Half Diagonal:" + halfDiagonal);
}
// P P - Model // P P - Model
// /| A - Palm // /| A - Palm
// / | d B - unit vector toward tip // / | d B - unit vector toward tip
@ -981,8 +1006,9 @@ function mouseClickEvent(event) {
} else { } else {
selectionManager.addEntity(foundEntity, true); selectionManager.addEntity(foundEntity, true);
} }
if (wantDebug) {
print("Model selected: " + foundEntity); print("Model selected: " + foundEntity);
}
selectionDisplay.select(selectedEntityID, event); selectionDisplay.select(selectedEntityID, event);
if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) { if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) {

View file

@ -17,8 +17,8 @@ var SIZE = 10.0;
var SEPARATION = 20.0; var SEPARATION = 20.0;
var ROWS_X = 30; var ROWS_X = 30;
var ROWS_Z = 30; var ROWS_Z = 30;
var TYPE = "Sphere"; // Right now this can be "Box" or "Model" or "Sphere" var TYPE = "Model"; // Right now this can be "Box" or "Model" or "Sphere"
var MODEL_URL = "https://hifi-public.s3.amazonaws.com/models/props/LowPolyIsland/CypressTreeGroup.fbx"; var MODEL_URL = "http://hifi-content.s3.amazonaws.com/DomainContent/CellScience/Instances/vesicle.fbx";
var MODEL_DIMENSION = { x: 33, y: 16, z: 49 }; var MODEL_DIMENSION = { x: 33, y: 16, z: 49 };
var RATE_PER_SECOND = 1000; // The entity server will drop data if we create things too fast. var RATE_PER_SECOND = 1000; // The entity server will drop data if we create things too fast.
var SCRIPT_INTERVAL = 100; var SCRIPT_INTERVAL = 100;
@ -38,6 +38,7 @@ Script.setInterval(function () {
var numToCreate = RATE_PER_SECOND * (SCRIPT_INTERVAL / 1000.0); var numToCreate = RATE_PER_SECOND * (SCRIPT_INTERVAL / 1000.0);
for (var i = 0; i < numToCreate; i++) { for (var i = 0; i < numToCreate; i++) {
var position = { x: SIZE + (x * SEPARATION), y: SIZE, z: SIZE + (z * SEPARATION) }; var position = { x: SIZE + (x * SEPARATION), y: SIZE, z: SIZE + (z * SEPARATION) };
print('position:'+JSON.stringify(position))
if (TYPE == "Model") { if (TYPE == "Model") {
Entities.addEntity({ Entities.addEntity({
type: TYPE, type: TYPE,

View file

@ -16,6 +16,11 @@ HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
SPACE_LOCAL = "local"; SPACE_LOCAL = "local";
SPACE_WORLD = "world"; SPACE_WORLD = "world";
function objectTranslationPlanePoint(position, dimensions) {
var newPosition = { x: position.x, y: position.y, z: position.z };
newPosition.y -= dimensions.y / 2.0;
return newPosition;
}
SelectionManager = (function() { SelectionManager = (function() {
var that = {}; var that = {};
@ -2252,15 +2257,20 @@ SelectionDisplay = (function() {
var constrainMajorOnly = false; var constrainMajorOnly = false;
var startPosition = null; var startPosition = null;
var duplicatedEntityIDs = null; var duplicatedEntityIDs = null;
var translateXZTool = { var translateXZTool = {
mode: 'TRANSLATE_XZ', mode: 'TRANSLATE_XZ',
pickPlanePosition: { x: 0, y: 0, z: 0 },
greatestDimension: 0.0,
startingDistance: 0.0,
startingElevation: 0.0,
onBegin: function(event) { onBegin: function(event) {
SelectionManager.saveProperties(); SelectionManager.saveProperties();
startPosition = SelectionManager.worldPosition; startPosition = SelectionManager.worldPosition;
var dimensions = SelectionManager.worldDimensions; var dimensions = SelectionManager.worldDimensions;
var pickRay = Camera.computePickRay(event.x, event.y); var pickRay = Camera.computePickRay(event.x, event.y);
initialXZPick = rayPlaneIntersection(pickRay, startPosition, { initialXZPick = rayPlaneIntersection(pickRay, translateXZTool.pickPlanePosition, {
x: 0, x: 0,
y: 1, y: 1,
z: 0 z: 0
@ -2297,16 +2307,56 @@ SelectionDisplay = (function() {
visible: false visible: false
}); });
}, },
elevation: function(origin, intersection) {
return (origin.y - intersection.y) / Vec3.distance(origin, intersection);
},
onMove: function(event) { onMove: function(event) {
var wantDebug = false;
pickRay = Camera.computePickRay(event.x, event.y); pickRay = Camera.computePickRay(event.x, event.y);
var pick = rayPlaneIntersection(pickRay, SelectionManager.worldPosition, { var pick = rayPlaneIntersection2(pickRay, translateXZTool.pickPlanePosition, {
x: 0, x: 0,
y: 1, y: 1,
z: 0 z: 0
}); });
// If the pick ray doesn't hit the pick plane in this direction, do nothing.
// this will happen when someone drags across the horizon from the side they started on.
if (!pick) {
if (wantDebug) {
print("Pick ray does not intersect XZ plane.");
}
return;
}
var vector = Vec3.subtract(pick, initialXZPick); var vector = Vec3.subtract(pick, initialXZPick);
// If the mouse is too close to the horizon of the pick plane, stop moving
var MIN_ELEVATION = 0.02; // largest dimension of object divided by distance to it
var elevation = translateXZTool.elevation(pickRay.origin, pick);
if (wantDebug) {
print("Start Elevation: " + translateXZTool.startingElevation + ", elevation: " + elevation);
}
if ((translateXZTool.startingElevation > 0.0 && elevation < MIN_ELEVATION) ||
(translateXZTool.startingElevation < 0.0 && elevation > -MIN_ELEVATION)) {
if (wantDebug) {
print("too close to horizon!");
}
return;
}
// If the angular size of the object is too small, stop moving
var MIN_ANGULAR_SIZE = 0.01; // Radians
if (translateXZTool.greatestDimension > 0) {
var angularSize = Math.atan(translateXZTool.greatestDimension / Vec3.distance(pickRay.origin, pick));
if (wantDebug) {
print("Angular size = " + angularSize);
}
if (angularSize < MIN_ANGULAR_SIZE) {
return;
}
}
// If shifted, constrain to one axis // If shifted, constrain to one axis
if (event.isShifted) { if (event.isShifted) {
if (Math.abs(vector.x) > Math.abs(vector.z)) { if (Math.abs(vector.x) > Math.abs(vector.z)) {
@ -2368,7 +2418,7 @@ SelectionDisplay = (function() {
grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly), grid.snapToGrid(Vec3.sum(cornerPosition, vector), constrainMajorOnly),
cornerPosition); cornerPosition);
var wantDebug = false;
for (var i = 0; i < SelectionManager.selections.length; i++) { for (var i = 0; i < SelectionManager.selections.length; i++) {
var properties = SelectionManager.savedProperties[SelectionManager.selections[i]]; var properties = SelectionManager.savedProperties[SelectionManager.selections[i]];
@ -2645,11 +2695,6 @@ SelectionDisplay = (function() {
pickRayPosition, pickRayPosition,
planeNormal); planeNormal);
// Overlays.editOverlay(normalLine, {
// start: initialPosition,
// end: Vec3.sum(Vec3.multiply(100000, planeNormal), initialPosition),
// });
SelectionManager.saveProperties(); SelectionManager.saveProperties();
}; };
@ -3751,7 +3796,7 @@ SelectionDisplay = (function() {
}; };
that.mousePressEvent = function(event) { that.mousePressEvent = function(event) {
var wantDebug = false;
if (!event.isLeftButton) { if (!event.isLeftButton) {
// if another mouse button than left is pressed ignore it // if another mouse button than left is pressed ignore it
return false; return false;
@ -3777,7 +3822,7 @@ SelectionDisplay = (function() {
if (result.intersects) { if (result.intersects) {
var wantDebug = false;
if (wantDebug) { if (wantDebug) {
print("something intersects... "); print("something intersects... ");
print(" result.overlayID:" + result.overlayID + "[" + overlayNames[result.overlayID] + "]"); print(" result.overlayID:" + result.overlayID + "[" + overlayNames[result.overlayID] + "]");
@ -3874,7 +3919,10 @@ SelectionDisplay = (function() {
if (!somethingClicked) { if (!somethingClicked) {
print("rotate handle case..."); if (wantDebug) {
print("rotate handle case...");
}
// After testing our stretch handles, then check out rotate handles // After testing our stretch handles, then check out rotate handles
Overlays.editOverlay(yawHandle, { Overlays.editOverlay(yawHandle, {
@ -3942,15 +3990,17 @@ SelectionDisplay = (function() {
break; break;
default: default:
print("mousePressEvent()...... " + overlayNames[result.overlayID]); if (wantDebug) {
print("mousePressEvent()...... " + overlayNames[result.overlayID]);
}
mode = "UNKNOWN"; mode = "UNKNOWN";
break; break;
} }
} }
if (wantDebug) {
print(" somethingClicked:" + somethingClicked); print(" somethingClicked:" + somethingClicked);
print(" mode:" + mode); print(" mode:" + mode);
}
if (somethingClicked) { if (somethingClicked) {
@ -4093,12 +4143,25 @@ SelectionDisplay = (function() {
switch (result.overlayID) { switch (result.overlayID) {
case selectionBox: case selectionBox:
activeTool = translateXZTool; activeTool = translateXZTool;
translateXZTool.pickPlanePosition = result.intersection;
translateXZTool.greatestDimension = Math.max(Math.max(SelectionManager.worldDimensions.x, SelectionManager.worldDimensions.y),
SelectionManager.worldDimensions.z);
if (wantDebug) {
print("longest dimension: " + translateXZTool.greatestDimension);
translateXZTool.startingDistance = Vec3.distance(pickRay.origin, SelectionManager.position);
print("starting distance: " + translateXZTool.startingDistance);
translateXZTool.startingElevation = translateXZTool.elevation(pickRay.origin, translateXZTool.pickPlanePosition);
print(" starting elevation: " + translateXZTool.startingElevation);
}
mode = translateXZTool.mode; mode = translateXZTool.mode;
activeTool.onBegin(event); activeTool.onBegin(event);
somethingClicked = true; somethingClicked = true;
break; break;
default: default:
print("mousePressEvent()...... " + overlayNames[result.overlayID]); if (wantDebug) {
print("mousePressEvent()...... " + overlayNames[result.overlayID]);
}
mode = "UNKNOWN"; mode = "UNKNOWN";
break; break;
} }

View file

@ -400,7 +400,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
frustum = qApp->getDisplayViewFrustum(); frustum = qApp->getDisplayViewFrustum();
} }
if (frustum->sphereIntersectsFrustum(getPosition(), boundingRadius)) { if (!frustum->sphereIntersectsFrustum(getPosition(), boundingRadius)) {
endRender(); endRender();
return; return;
} }

View file

@ -153,25 +153,6 @@ std::shared_ptr<Avatar> AvatarActionHold::getTarget(float deltaTimeStep, glm::qu
palmPosition = holdingAvatar->getLeftPalmPosition(); palmPosition = holdingAvatar->getLeftPalmPosition();
palmRotation = holdingAvatar->getLeftPalmRotation(); palmRotation = holdingAvatar->getLeftPalmRotation();
} }
// In this case we are simulating the grab of another avatar.
// Because the hand controller velocity for their palms is not transmitted over the
// network, we have to synthesize our own.
if (_previousSet) {
// smooth linear velocity over two frames
glm::vec3 positionalDelta = palmPosition - _previousPositionalTarget;
linearVelocity = (positionalDelta + _previousPositionalDelta) / (deltaTimeStep + _previousDeltaTimeStep);
glm::quat deltaRotation = palmRotation * glm::inverse(_previousRotationalTarget);
float rotationAngle = glm::angle(deltaRotation);
if (rotationAngle > EPSILON) {
angularVelocity = glm::normalize(glm::axis(deltaRotation));
angularVelocity *= (rotationAngle / deltaTimeStep);
}
_previousPositionalDelta = positionalDelta;
_previousDeltaTimeStep = deltaTimeStep;
}
} }
rotation = palmRotation * _relativeRotation; rotation = palmRotation * _relativeRotation;
@ -278,6 +259,7 @@ void AvatarActionHold::doKinematicUpdate(float deltaTimeStep) {
}); });
forceBodyNonStatic(); forceBodyNonStatic();
activateBody(true);
} }
bool AvatarActionHold::updateArguments(QVariantMap arguments) { bool AvatarActionHold::updateArguments(QVariantMap arguments) {

View file

@ -301,7 +301,7 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int
// look at borrowed from overlays // look at borrowed from overlays
float elevation = -asinf(relativePosition.y / glm::length(relativePosition)); float elevation = -asinf(relativePosition.y / glm::length(relativePosition));
float azimuth = atan2f(relativePosition.x, relativePosition.z); float azimuth = atan2f(relativePosition.x, relativePosition.z);
glm::quat faceCamera = glm::quat(glm::vec3(elevation, azimuth, 0)) * quat(vec3(0, 0, -1)); // this extra *quat(vec3(0,0,-1)) was required to get the quad to flip this seems like we could optimize glm::quat faceCamera = glm::quat(glm::vec3(elevation, azimuth, 0)) * quat(vec3(0, -PI, 0)); // this extra *quat(vec3(0,-PI,0)) was required to get the quad to flip this seems like we could optimize
Transform transform; Transform transform;
transform.setTranslation(relativePosition); transform.setTranslation(relativePosition);

View file

@ -12,6 +12,7 @@
#include "EntityItemID.h" #include "EntityItemID.h"
#include <VariantMapToScriptValue.h> #include <VariantMapToScriptValue.h>
#include <SpatialParentFinder.h>
#include "EntitiesLogging.h" #include "EntitiesLogging.h"
#include "EntityActionFactoryInterface.h" #include "EntityActionFactoryInterface.h"
@ -1063,6 +1064,34 @@ QStringList EntityScriptingInterface::getJointNames(const QUuid& entityID) {
return result; return result;
} }
QVector<QUuid> EntityScriptingInterface::getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex) {
QVector<QUuid> result;
if (!_entityTree) {
return result;
}
_entityTree->withReadLock([&] {
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
if (!parentFinder) {
return;
}
bool success;
SpatiallyNestableWeakPointer parentWP = parentFinder->find(parentID, success);
if (!success) {
return;
}
SpatiallyNestablePointer parent = parentWP.lock();
if (!parent) {
return;
}
parent->forEachChild([&](SpatiallyNestablePointer child) {
if (child->getParentJointIndex() == jointIndex) {
result.push_back(child->getID());
}
});
});
return result;
}
float EntityScriptingInterface::calculateCost(float mass, float oldVelocity, float newVelocity) { float EntityScriptingInterface::calculateCost(float mass, float oldVelocity, float newVelocity) {
return std::abs(mass * (newVelocity - oldVelocity)); return std::abs(mass * (newVelocity - oldVelocity));
} }

View file

@ -168,7 +168,7 @@ public slots:
Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name); Q_INVOKABLE int getJointIndex(const QUuid& entityID, const QString& name);
Q_INVOKABLE QStringList getJointNames(const QUuid& entityID); Q_INVOKABLE QStringList getJointNames(const QUuid& entityID);
Q_INVOKABLE QVector<QUuid> getChildrenIDsOfJoint(const QUuid& parentID, int jointIndex);
signals: signals:
void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision);

View file

@ -18,51 +18,69 @@
#include "EntityItem.h" #include "EntityItem.h"
#include "EntitiesLogging.h" #include "EntitiesLogging.h"
const quint64 MIN_SIMULATION_OWNERSHIP_UPDATE_PERIOD = 2 * USECS_PER_SECOND; const quint64 MAX_OWNERLESS_PERIOD = 2 * USECS_PER_SECOND;
void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) {
if (_entitiesWithSimulator.size() == 0) {
return;
}
if (now < _nextSimulationExpiry) {
// nothing has expired yet
return;
}
// If an Entity has a simulation owner but there has been no update for a while: clear the owner.
// If an Entity goes ownerless for too long: zero velocity and remove from _entitiesWithSimulator.
_nextSimulationExpiry = now + MIN_SIMULATION_OWNERSHIP_UPDATE_PERIOD;
void SimpleEntitySimulation::clearOwnership(const QUuid& ownerID) {
QMutexLocker lock(&_mutex); QMutexLocker lock(&_mutex);
SetOfEntities::iterator itemItr = _entitiesWithSimulator.begin(); SetOfEntities::iterator itemItr = _entitiesWithSimulationOwner.begin();
while (itemItr != _entitiesWithSimulator.end()) { while (itemItr != _entitiesWithSimulationOwner.end()) {
EntityItemPointer entity = *itemItr; EntityItemPointer entity = *itemItr;
quint64 expiry = entity->getLastChangedOnServer() + MIN_SIMULATION_OWNERSHIP_UPDATE_PERIOD; if (entity->getSimulatorID() == ownerID) {
if (expiry < now) { // the simulator has abandonded this object --> remove from owned list
if (entity->getSimulatorID().isNull()) { qCDebug(entities) << "auto-removing simulation owner " << entity->getSimulatorID();
// no simulators are volunteering itemItr = _entitiesWithSimulationOwner.erase(itemItr);
// zero the velocity on this entity so that it doesn't drift far away
entity->setVelocity(Vectors::ZERO); if (entity->getDynamic() && entity->hasLocalVelocity()) {
entity->setAngularVelocity(Vectors::ZERO); // it is still moving dynamically --> add to orphaned list
entity->setAcceleration(Vectors::ZERO); _entitiesThatNeedSimulationOwner.insert(entity);
// remove from list quint64 expiry = entity->getLastChangedOnServer() + MAX_OWNERLESS_PERIOD;
itemItr = _entitiesWithSimulator.erase(itemItr); if (expiry < _nextOwnerlessExpiry) {
continue; _nextOwnerlessExpiry = expiry;
} else { }
// the simulator has stopped updating this object
// clear ownership and restart timer, giving nearby simulators time to volunteer
qCDebug(entities) << "auto-removing simulation owner " << entity->getSimulatorID();
entity->clearSimulationOwnership();
} }
// remove ownership and dirty all the tree elements that contain the it
entity->clearSimulationOwnership();
entity->markAsChangedOnServer(); entity->markAsChangedOnServer();
// dirty all the tree elements that contain the entity
DirtyOctreeElementOperator op(entity->getElement()); DirtyOctreeElementOperator op(entity->getElement());
getEntityTree()->recurseTreeWithOperator(&op); getEntityTree()->recurseTreeWithOperator(&op);
} else if (expiry < _nextSimulationExpiry) { } else {
_nextSimulationExpiry = expiry; ++itemItr;
}
}
}
void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) {
if (now > _nextOwnerlessExpiry) {
// search for ownerless objects that have expired
QMutexLocker lock(&_mutex);
_nextOwnerlessExpiry = -1;
SetOfEntities::iterator itemItr = _entitiesThatNeedSimulationOwner.begin();
while (itemItr != _entitiesThatNeedSimulationOwner.end()) {
EntityItemPointer entity = *itemItr;
quint64 expiry = entity->getLastChangedOnServer() + MAX_OWNERLESS_PERIOD;
if (expiry < now) {
// no simulators have volunteered ownership --> remove from list
itemItr = _entitiesThatNeedSimulationOwner.erase(itemItr);
if (entity->getSimulatorID().isNull() && entity->getDynamic() && entity->hasLocalVelocity()) {
// zero the derivatives
entity->setVelocity(Vectors::ZERO);
entity->setAngularVelocity(Vectors::ZERO);
entity->setAcceleration(Vectors::ZERO);
// dirty all the tree elements that contain it
entity->markAsChangedOnServer();
DirtyOctreeElementOperator op(entity->getElement());
getEntityTree()->recurseTreeWithOperator(&op);
}
} else {
++itemItr;
if (expiry < _nextOwnerlessExpiry) {
_nextOwnerlessExpiry = expiry;
}
}
} }
++itemItr;
} }
} }
@ -70,26 +88,47 @@ void SimpleEntitySimulation::addEntityInternal(EntityItemPointer entity) {
EntitySimulation::addEntityInternal(entity); EntitySimulation::addEntityInternal(entity);
if (!entity->getSimulatorID().isNull()) { if (!entity->getSimulatorID().isNull()) {
QMutexLocker lock(&_mutex); QMutexLocker lock(&_mutex);
_entitiesWithSimulator.insert(entity); _entitiesWithSimulationOwner.insert(entity);
} else if (entity->getDynamic() && entity->hasLocalVelocity()) {
QMutexLocker lock(&_mutex);
_entitiesThatNeedSimulationOwner.insert(entity);
quint64 expiry = entity->getLastChangedOnServer() + MAX_OWNERLESS_PERIOD;
if (expiry < _nextOwnerlessExpiry) {
_nextOwnerlessExpiry = expiry;
}
} }
} }
void SimpleEntitySimulation::removeEntityInternal(EntityItemPointer entity) { void SimpleEntitySimulation::removeEntityInternal(EntityItemPointer entity) {
EntitySimulation::removeEntityInternal(entity); EntitySimulation::removeEntityInternal(entity);
QMutexLocker lock(&_mutex); QMutexLocker lock(&_mutex);
_entitiesWithSimulator.remove(entity); _entitiesWithSimulationOwner.remove(entity);
_entitiesThatNeedSimulationOwner.remove(entity);
} }
void SimpleEntitySimulation::changeEntityInternal(EntityItemPointer entity) { void SimpleEntitySimulation::changeEntityInternal(EntityItemPointer entity) {
EntitySimulation::changeEntityInternal(entity); EntitySimulation::changeEntityInternal(entity);
if (!entity->getSimulatorID().isNull()) { if (entity->getSimulatorID().isNull()) {
QMutexLocker lock(&_mutex); QMutexLocker lock(&_mutex);
_entitiesWithSimulator.insert(entity); _entitiesWithSimulationOwner.remove(entity);
if (entity->getDynamic() && entity->hasLocalVelocity()) {
_entitiesThatNeedSimulationOwner.insert(entity);
quint64 expiry = entity->getLastChangedOnServer() + MAX_OWNERLESS_PERIOD;
if (expiry < _nextOwnerlessExpiry) {
_nextOwnerlessExpiry = expiry;
}
}
} else {
QMutexLocker lock(&_mutex);
_entitiesWithSimulationOwner.insert(entity);
_entitiesThatNeedSimulationOwner.remove(entity);
} }
entity->clearDirtyFlags(); entity->clearDirtyFlags();
} }
void SimpleEntitySimulation::clearEntitiesInternal() { void SimpleEntitySimulation::clearEntitiesInternal() {
_entitiesWithSimulator.clear(); QMutexLocker lock(&_mutex);
_entitiesWithSimulationOwner.clear();
_entitiesThatNeedSimulationOwner.clear();
} }

View file

@ -21,6 +21,8 @@ public:
SimpleEntitySimulation() : EntitySimulation() { } SimpleEntitySimulation() : EntitySimulation() { }
virtual ~SimpleEntitySimulation() { clearEntitiesInternal(); } virtual ~SimpleEntitySimulation() { clearEntitiesInternal(); }
void clearOwnership(const QUuid& ownerID);
protected: protected:
virtual void updateEntitiesInternal(const quint64& now) override; virtual void updateEntitiesInternal(const quint64& now) override;
virtual void addEntityInternal(EntityItemPointer entity) override; virtual void addEntityInternal(EntityItemPointer entity) override;
@ -28,8 +30,9 @@ protected:
virtual void changeEntityInternal(EntityItemPointer entity) override; virtual void changeEntityInternal(EntityItemPointer entity) override;
virtual void clearEntitiesInternal() override; virtual void clearEntitiesInternal() override;
SetOfEntities _entitiesWithSimulator; SetOfEntities _entitiesWithSimulationOwner;
quint64 _nextSimulationExpiry { 0 }; SetOfEntities _entitiesThatNeedSimulationOwner;
quint64 _nextOwnerlessExpiry { 0 };
}; };
#endif // hifi_SimpleEntitySimulation_h #endif // hifi_SimpleEntitySimulation_h

View file

@ -272,7 +272,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
float dt = (float)(numSteps) * PHYSICS_ENGINE_FIXED_SUBSTEP; float dt = (float)(numSteps) * PHYSICS_ENGINE_FIXED_SUBSTEP;
if (_numInactiveUpdates > 0) { if (_numInactiveUpdates > 0) {
const uint8_t MAX_NUM_INACTIVE_UPDATES = 3; const uint8_t MAX_NUM_INACTIVE_UPDATES = 20;
if (_numInactiveUpdates > MAX_NUM_INACTIVE_UPDATES) { if (_numInactiveUpdates > MAX_NUM_INACTIVE_UPDATES) {
// clear local ownership (stop sending updates) and let the server clear itself // clear local ownership (stop sending updates) and let the server clear itself
_entity->clearSimulationOwnership(); _entity->clearSimulationOwnership();
@ -282,7 +282,7 @@ bool EntityMotionState::remoteSimulationOutOfSync(uint32_t simulationStep) {
// until it is removed from the outgoing updates // until it is removed from the outgoing updates
// (which happens when we don't own the simulation and it isn't touching our simulation) // (which happens when we don't own the simulation and it isn't touching our simulation)
const float INACTIVE_UPDATE_PERIOD = 0.5f; const float INACTIVE_UPDATE_PERIOD = 0.5f;
return (dt > INACTIVE_UPDATE_PERIOD); return (dt > INACTIVE_UPDATE_PERIOD * (float)_numInactiveUpdates);
} }
if (!_body->isActive()) { if (!_body->isActive()) {
@ -404,8 +404,7 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q
assert(_entity); assert(_entity);
assert(entityTreeIsLocked()); assert(entityTreeIsLocked());
bool active = _body->isActive(); if (!_body->isActive()) {
if (!active) {
// make sure all derivatives are zero // make sure all derivatives are zero
glm::vec3 zero(0.0f); glm::vec3 zero(0.0f);
_entity->setVelocity(zero); _entity->setVelocity(zero);
@ -495,16 +494,12 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, const Q
qCDebug(physics) << " lastSimulated:" << debugTime(lastSimulated, now); qCDebug(physics) << " lastSimulated:" << debugTime(lastSimulated, now);
#endif //def WANT_DEBUG #endif //def WANT_DEBUG
if (sessionID == _entity->getSimulatorID()) { if (_numInactiveUpdates > 0) {
// we think we own the simulation // we own the simulation but the entity has stopped, so we tell the server that we're clearing simulatorID
if (!active) { // but we remember that we do still own it... and rely on the server to tell us that we don't
// we own the simulation but the entity has stopped, so we tell the server that we're clearing simulatorID properties.clearSimulationOwner();
// but we remember that we do still own it... and rely on the server to tell us that we don't _outgoingPriority = ZERO_SIMULATION_PRIORITY;
properties.clearSimulationOwner(); } else if (sessionID != _entity->getSimulatorID()) {
_outgoingPriority = ZERO_SIMULATION_PRIORITY;
}
// else the ownership is not changing so we don't bother to pack it
} else {
// we don't own the simulation for this entity yet, but we're sending a bid for it // we don't own the simulation for this entity yet, but we're sending a bid for it
properties.setSimulationOwner(sessionID, glm::max<uint8_t>(_outgoingPriority, VOLUNTEER_SIMULATION_PRIORITY)); properties.setSimulationOwner(sessionID, glm::max<uint8_t>(_outgoingPriority, VOLUNTEER_SIMULATION_PRIORITY));
_nextOwnershipBid = now + USECS_BETWEEN_OWNERSHIP_BIDS; _nextOwnershipBid = now + USECS_BETWEEN_OWNERSHIP_BIDS;

View file

@ -15,6 +15,7 @@
#include "SpatiallyNestable.h" #include "SpatiallyNestable.h"
const float defaultAACubeSize = 1.0f; const float defaultAACubeSize = 1.0f;
const int maxParentingChain = 30;
SpatiallyNestable::SpatiallyNestable(NestableType nestableType, QUuid id) : SpatiallyNestable::SpatiallyNestable(NestableType nestableType, QUuid id) :
_nestableType(nestableType), _nestableType(nestableType),
@ -56,14 +57,14 @@ void SpatiallyNestable::setParentID(const QUuid& parentID) {
}); });
} }
Transform SpatiallyNestable::getParentTransform(bool& success) const { Transform SpatiallyNestable::getParentTransform(bool& success, int depth) const {
Transform result; Transform result;
SpatiallyNestablePointer parent = getParentPointer(success); SpatiallyNestablePointer parent = getParentPointer(success);
if (!success) { if (!success) {
return result; return result;
} }
if (parent) { if (parent) {
Transform parentTransform = parent->getTransform(_parentJointIndex, success); Transform parentTransform = parent->getTransform(_parentJointIndex, success, depth + 1);
result = parentTransform.setScale(1.0f); // TODO: scaling result = parentTransform.setScale(1.0f); // TODO: scaling
} }
return result; return result;
@ -393,11 +394,11 @@ void SpatiallyNestable::setOrientation(const glm::quat& orientation) {
glm::vec3 SpatiallyNestable::getVelocity(bool& success) const { glm::vec3 SpatiallyNestable::getVelocity(bool& success) const {
glm::vec3 result; glm::vec3 result;
glm::vec3 parentVelocity = getParentVelocity(success); Transform parentTransform = getParentTransform(success);
if (!success) { if (!success) {
return result; return result;
} }
Transform parentTransform = getParentTransform(success); glm::vec3 parentVelocity = getParentVelocity(success);
if (!success) { if (!success) {
return result; return result;
} }
@ -448,11 +449,11 @@ glm::vec3 SpatiallyNestable::getParentVelocity(bool& success) const {
glm::vec3 SpatiallyNestable::getAngularVelocity(bool& success) const { glm::vec3 SpatiallyNestable::getAngularVelocity(bool& success) const {
glm::vec3 result; glm::vec3 result;
glm::vec3 parentAngularVelocity = getParentAngularVelocity(success); Transform parentTransform = getParentTransform(success);
if (!success) { if (!success) {
return result; return result;
} }
Transform parentTransform = getParentTransform(success); glm::vec3 parentAngularVelocity = getParentAngularVelocity(success);
if (!success) { if (!success) {
return result; return result;
} }
@ -499,22 +500,36 @@ glm::vec3 SpatiallyNestable::getParentAngularVelocity(bool& success) const {
return result; return result;
} }
const Transform SpatiallyNestable::getTransform(bool& success) const { const Transform SpatiallyNestable::getTransform(bool& success, int depth) const {
// return a world-space transform for this object's location
Transform parentTransform = getParentTransform(success);
Transform result; Transform result;
// return a world-space transform for this object's location
Transform parentTransform = getParentTransform(success, depth);
_transformLock.withReadLock([&] { _transformLock.withReadLock([&] {
Transform::mult(result, parentTransform, _transform); Transform::mult(result, parentTransform, _transform);
}); });
return result; return result;
} }
const Transform SpatiallyNestable::getTransform(int jointIndex, bool& success) const { const Transform SpatiallyNestable::getTransform(int jointIndex, bool& success, int depth) const {
// this returns the world-space transform for this object. It finds its parent's transform (which may // this returns the world-space transform for this object. It finds its parent's transform (which may
// cause this object's parent to query its parent, etc) and multiplies this object's local transform onto it. // cause this object's parent to query its parent, etc) and multiplies this object's local transform onto it.
Transform jointInWorldFrame; Transform jointInWorldFrame;
Transform worldTransform = getTransform(success); if (depth > maxParentingChain) {
success = false;
// someone created a loop. break it...
qDebug() << "Parenting loop detected.";
SpatiallyNestablePointer _this = getThisPointer();
_this->setParentID(QUuid());
bool setPositionSuccess;
AACube aaCube = getQueryAACube(setPositionSuccess);
if (setPositionSuccess) {
_this->setPosition(aaCube.calcCenter());
}
return jointInWorldFrame;
}
Transform worldTransform = getTransform(success, depth);
worldTransform.setScale(1.0f); // TODO -- scale; worldTransform.setScale(1.0f); // TODO -- scale;
if (!success) { if (!success) {
return jointInWorldFrame; return jointInWorldFrame;
@ -682,7 +697,7 @@ QList<SpatiallyNestablePointer> SpatiallyNestable::getChildren() const {
_childrenLock.withReadLock([&] { _childrenLock.withReadLock([&] {
foreach(SpatiallyNestableWeakPointer childWP, _children.values()) { foreach(SpatiallyNestableWeakPointer childWP, _children.values()) {
SpatiallyNestablePointer child = childWP.lock(); SpatiallyNestablePointer child = childWP.lock();
if (child) { if (child && child->_parentKnowsMe && child->getParentID() == getID()) {
children << child; children << child;
} }
} }

View file

@ -52,10 +52,10 @@ public:
static glm::quat localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success); static glm::quat localToWorld(const glm::quat& orientation, const QUuid& parentID, int parentJointIndex, bool& success);
// world frame // world frame
virtual const Transform getTransform(bool& success) const; virtual const Transform getTransform(bool& success, int depth = 0) const;
virtual void setTransform(const Transform& transform, bool& success); virtual void setTransform(const Transform& transform, bool& success);
virtual Transform getParentTransform(bool& success) const; virtual Transform getParentTransform(bool& success, int depth = 0) const;
virtual glm::vec3 getPosition(bool& success) const; virtual glm::vec3 getPosition(bool& success) const;
virtual glm::vec3 getPosition() const; virtual glm::vec3 getPosition() const;
@ -92,7 +92,7 @@ public:
virtual void setScale(const glm::vec3& scale); virtual void setScale(const glm::vec3& scale);
// get world-frame values for a specific joint // get world-frame values for a specific joint
virtual const Transform getTransform(int jointIndex, bool& success) const; virtual const Transform getTransform(int jointIndex, bool& success, int depth = 0) const;
virtual glm::vec3 getPosition(int jointIndex, bool& success) const; virtual glm::vec3 getPosition(int jointIndex, bool& success) const;
virtual glm::vec3 getScale(int jointIndex) const; virtual glm::vec3 getScale(int jointIndex) const;

View file

@ -60,10 +60,10 @@ void ViveControllerManager::activate() {
[this] (bool clicked) { this->setRenderControllers(clicked); }, [this] (bool clicked) { this->setRenderControllers(clicked); },
true, true); true, true);
if (!_hmd) { if (!_system) {
_hmd = acquireOpenVrSystem(); _system = acquireOpenVrSystem();
} }
Q_ASSERT(_hmd); Q_ASSERT(_system);
// OpenVR provides 3d mesh representations of the controllers // OpenVR provides 3d mesh representations of the controllers
// Disabled controller rendering code // Disabled controller rendering code
@ -71,7 +71,7 @@ void ViveControllerManager::activate() {
auto renderModels = vr::VRRenderModels(); auto renderModels = vr::VRRenderModels();
vr::RenderModel_t model; vr::RenderModel_t model;
if (!_hmd->LoadRenderModel(CONTROLLER_MODEL_STRING, &model)) { if (!_system->LoadRenderModel(CONTROLLER_MODEL_STRING, &model)) {
qDebug() << QString("Unable to load render model %1\n").arg(CONTROLLER_MODEL_STRING); qDebug() << QString("Unable to load render model %1\n").arg(CONTROLLER_MODEL_STRING);
} else { } else {
model::Mesh* mesh = new model::Mesh(); model::Mesh* mesh = new model::Mesh();
@ -118,7 +118,7 @@ void ViveControllerManager::activate() {
} }
*/ */
// unregister with UserInputMapper // register with UserInputMapper
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>(); auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
userInputMapper->registerDevice(_inputDevice); userInputMapper->registerDevice(_inputDevice);
_registeredWithInputMapper = true; _registeredWithInputMapper = true;
@ -130,9 +130,9 @@ void ViveControllerManager::deactivate() {
_container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS); _container->removeMenuItem(MENU_NAME, RENDER_CONTROLLERS);
_container->removeMenu(MENU_PATH); _container->removeMenu(MENU_PATH);
if (_hmd) { if (_system) {
releaseOpenVrSystem(); releaseOpenVrSystem();
_hmd = nullptr; _system = nullptr;
} }
_inputDevice->_poseStateMap.clear(); _inputDevice->_poseStateMap.clear();
@ -226,56 +226,56 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu
void ViveControllerManager::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { void ViveControllerManager::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) {
_poseStateMap.clear(); _poseStateMap.clear();
_buttonPressedMap.clear(); _buttonPressedMap.clear();
PerformanceTimer perfTimer("ViveControllerManager::update"); PerformanceTimer perfTimer("ViveControllerManager::update");
auto leftHandDeviceIndex = _system->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_LeftHand);
auto rightHandDeviceIndex = _system->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_RightHand);
if (!jointsCaptured) {
handleHandController(deltaTime, leftHandDeviceIndex, inputCalibrationData, true);
handleHandController(deltaTime, rightHandDeviceIndex, inputCalibrationData, false);
}
int numTrackedControllers = 0; int numTrackedControllers = 0;
if (leftHandDeviceIndex != vr::k_unTrackedDeviceIndexInvalid) {
for (vr::TrackedDeviceIndex_t device = vr::k_unTrackedDeviceIndex_Hmd + 1;
device < vr::k_unMaxTrackedDeviceCount && numTrackedControllers < 2; ++device) {
if (!_hmd->IsTrackedDeviceConnected(device)) {
continue;
}
if (_hmd->GetTrackedDeviceClass(device) != vr::TrackedDeviceClass_Controller) {
continue;
}
if (!_trackedDevicePose[device].bPoseIsValid) {
continue;
}
numTrackedControllers++; numTrackedControllers++;
bool left = numTrackedControllers == 2; }
if (rightHandDeviceIndex != vr::k_unTrackedDeviceIndexInvalid) {
numTrackedControllers++;
}
_trackedControllers = numTrackedControllers;
}
if (!jointsCaptured) { void ViveControllerManager::InputDevice::handleHandController(float deltaTime, uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand) {
const mat4& mat = _trackedDevicePoseMat4[device];
const vec3 linearVelocity = _trackedDeviceLinearVelocities[device]; if (_system->IsTrackedDeviceConnected(deviceIndex) &&
const vec3 angularVelocity = _trackedDeviceAngularVelocities[device]; _system->GetTrackedDeviceClass(deviceIndex) == vr::TrackedDeviceClass_Controller &&
handlePoseEvent(inputCalibrationData, mat, linearVelocity, angularVelocity, numTrackedControllers - 1); _trackedDevicePose[deviceIndex].bPoseIsValid) {
}
// process pose
const mat4& mat = _trackedDevicePoseMat4[deviceIndex];
const vec3 linearVelocity = _trackedDeviceLinearVelocities[deviceIndex];
const vec3 angularVelocity = _trackedDeviceAngularVelocities[deviceIndex];
handlePoseEvent(deltaTime, inputCalibrationData, mat, linearVelocity, angularVelocity, isLeftHand);
// handle inputs
vr::VRControllerState_t controllerState = vr::VRControllerState_t(); vr::VRControllerState_t controllerState = vr::VRControllerState_t();
if (_hmd->GetControllerState(device, &controllerState)) { if (_system->GetControllerState(deviceIndex, &controllerState)) {
//qDebug() << (numTrackedControllers == 1 ? "Left: " : "Right: ");
//qDebug() << "Trackpad: " << controllerState.rAxis[0].x << " " << controllerState.rAxis[0].y; // process each button
//qDebug() << "Trigger: " << controllerState.rAxis[1].x << " " << controllerState.rAxis[1].y;
for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) { for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) {
auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i); auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i);
bool pressed = 0 != (controllerState.ulButtonPressed & mask); bool pressed = 0 != (controllerState.ulButtonPressed & mask);
handleButtonEvent(i, pressed, left); handleButtonEvent(deltaTime, i, pressed, isLeftHand);
} }
// process each axis
for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) { for (uint32_t i = 0; i < vr::k_unControllerStateAxisCount; i++) {
handleAxisEvent(i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, left); handleAxisEvent(deltaTime, i, controllerState.rAxis[i].x, controllerState.rAxis[i].y, isLeftHand);
} }
} }
} }
_trackedControllers = numTrackedControllers;
} }
void ViveControllerManager::InputDevice::focusOutEvent() { void ViveControllerManager::InputDevice::focusOutEvent() {
@ -284,42 +284,46 @@ void ViveControllerManager::InputDevice::focusOutEvent() {
}; };
// These functions do translation from the Steam IDs to the standard controller IDs // These functions do translation from the Steam IDs to the standard controller IDs
void ViveControllerManager::InputDevice::handleAxisEvent(uint32_t axis, float x, float y, bool left) { void ViveControllerManager::InputDevice::handleAxisEvent(float deltaTime, uint32_t axis, float x, float y, bool isLeftHand) {
//FIX ME? It enters here every frame: probably we want to enter only if an event occurs //FIX ME? It enters here every frame: probably we want to enter only if an event occurs
axis += vr::k_EButton_Axis0; axis += vr::k_EButton_Axis0;
using namespace controller; using namespace controller;
if (axis == vr::k_EButton_SteamVR_Touchpad) { if (axis == vr::k_EButton_SteamVR_Touchpad) {
_axisStateMap[left ? LX : RX] = x; glm::vec2 stick(x, y);
_axisStateMap[left ? LY : RY] = y; if (isLeftHand) {
stick = _filteredLeftStick.process(deltaTime, stick);
} else {
stick = _filteredRightStick.process(deltaTime, stick);
}
_axisStateMap[isLeftHand ? LX : RX] = stick.x;
_axisStateMap[isLeftHand ? LY : RY] = stick.y;
} else if (axis == vr::k_EButton_SteamVR_Trigger) { } else if (axis == vr::k_EButton_SteamVR_Trigger) {
_axisStateMap[left ? LT : RT] = x; _axisStateMap[isLeftHand ? LT : RT] = x;
} }
} }
// These functions do translation from the Steam IDs to the standard controller IDs // These functions do translation from the Steam IDs to the standard controller IDs
void ViveControllerManager::InputDevice::handleButtonEvent(uint32_t button, bool pressed, bool left) { void ViveControllerManager::InputDevice::handleButtonEvent(float deltaTime, uint32_t button, bool pressed, bool isLeftHand) {
if (!pressed) { if (!pressed) {
return; return;
} }
using namespace controller;
if (button == vr::k_EButton_ApplicationMenu) { if (button == vr::k_EButton_ApplicationMenu) {
_buttonPressedMap.insert(left ? controller::LEFT_PRIMARY_THUMB : controller::RIGHT_PRIMARY_THUMB); _buttonPressedMap.insert(isLeftHand ? LEFT_PRIMARY_THUMB : RIGHT_PRIMARY_THUMB);
} else if (button == vr::k_EButton_Grip) { } else if (button == vr::k_EButton_Grip) {
// Tony says these are harder to reach, so make them the meta buttons _buttonPressedMap.insert(isLeftHand ? LB : RB);
_buttonPressedMap.insert(left ? controller::LB : controller::RB);
} else if (button == vr::k_EButton_SteamVR_Trigger) { } else if (button == vr::k_EButton_SteamVR_Trigger) {
_buttonPressedMap.insert(left ? controller::LT : controller::RT); _buttonPressedMap.insert(isLeftHand ? LT : RT);
} else if (button == vr::k_EButton_SteamVR_Touchpad) { } else if (button == vr::k_EButton_SteamVR_Touchpad) {
_buttonPressedMap.insert(left ? controller::LS : controller::RS); _buttonPressedMap.insert(isLeftHand ? LS : RS);
} else if (button == vr::k_EButton_System) {
//FIX ME: not able to ovrewrite the behaviour of this button
_buttonPressedMap.insert(left ? controller::LEFT_SECONDARY_THUMB : controller::RIGHT_SECONDARY_THUMB);
} }
} }
void ViveControllerManager::InputDevice::handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, void ViveControllerManager::InputDevice::handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData,
const mat4& mat, const vec3& linearVelocity, const mat4& mat, const vec3& linearVelocity,
const vec3& angularVelocity, bool left) { const vec3& angularVelocity, bool isLeftHand) {
// When the sensor-to-world rotation is identity the coordinate axes look like this: // When the sensor-to-world rotation is identity the coordinate axes look like this:
// //
// user // user
@ -384,8 +388,8 @@ void ViveControllerManager::InputDevice::handlePoseEvent(const controller::Input
static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET;
static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET;
auto translationOffset = (left ? leftTranslationOffset : rightTranslationOffset); auto translationOffset = (isLeftHand ? leftTranslationOffset : rightTranslationOffset);
auto rotationOffset = (left ? leftRotationOffset : rightRotationOffset); auto rotationOffset = (isLeftHand ? leftRotationOffset : rightRotationOffset);
glm::vec3 position = extractTranslation(mat); glm::vec3 position = extractTranslation(mat);
glm::quat rotation = glm::normalize(glm::quat_cast(mat)); glm::quat rotation = glm::normalize(glm::quat_cast(mat));
@ -399,7 +403,7 @@ void ViveControllerManager::InputDevice::handlePoseEvent(const controller::Input
// handle change in velocity due to translationOffset // handle change in velocity due to translationOffset
avatarPose.velocity = linearVelocity + glm::cross(angularVelocity, position - extractTranslation(mat)); avatarPose.velocity = linearVelocity + glm::cross(angularVelocity, position - extractTranslation(mat));
avatarPose.angularVelocity = angularVelocity; avatarPose.angularVelocity = angularVelocity;
_poseStateMap[left ? controller::LEFT_HAND : controller::RIGHT_HAND] = avatarPose.transform(controllerToAvatar); _poseStateMap[isLeftHand ? controller::LEFT_HAND : controller::RIGHT_HAND] = avatarPose.transform(controllerToAvatar);
} }
controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableInputs() const { controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableInputs() const {

View file

@ -50,7 +50,7 @@ public:
private: private:
class InputDevice : public controller::InputDevice { class InputDevice : public controller::InputDevice {
public: public:
InputDevice(vr::IVRSystem*& hmd) : controller::InputDevice("Vive"), _hmd(hmd) {} InputDevice(vr::IVRSystem*& system) : controller::InputDevice("Vive"), _system(system) {}
private: private:
// Device functions // Device functions
virtual controller::Input::NamedVector getAvailableInputs() const override; virtual controller::Input::NamedVector getAvailableInputs() const override;
@ -58,20 +58,46 @@ private:
virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override;
virtual void focusOutEvent() override; virtual void focusOutEvent() override;
void handleButtonEvent(uint32_t button, bool pressed, bool left); void handleHandController(float deltaTime, uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand);
void handleAxisEvent(uint32_t axis, float x, float y, bool left); void handleButtonEvent(float deltaTime, uint32_t button, bool pressed, bool isLeftHand);
void handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, void handleAxisEvent(float deltaTime, uint32_t axis, float x, float y, bool isLeftHand);
const vec3& linearVelocity, const vec3& angularVelocity, bool left); void handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const mat4& mat,
const vec3& linearVelocity, const vec3& angularVelocity, bool isLeftHand);
class FilteredStick {
public:
glm::vec2 process(float deltaTime, const glm::vec2& stick) {
// Use a timer to prevent the stick going to back to zero.
// This to work around the noisy touch pad that will flash back to zero breifly
const float ZERO_HYSTERESIS_PERIOD = 0.2f; // 200 ms
if (glm::length(stick) == 0.0f) {
if (_timer <= 0.0f) {
return glm::vec2(0.0f, 0.0f);
} else {
_timer -= deltaTime;
return _stick;
}
} else {
_timer = ZERO_HYSTERESIS_PERIOD;
_stick = stick;
return stick;
}
}
protected:
float _timer { 0.0f };
glm::vec2 _stick { 0.0f, 0.0f };
};
FilteredStick _filteredLeftStick;
FilteredStick _filteredRightStick;
int _trackedControllers { 0 }; int _trackedControllers { 0 };
vr::IVRSystem*& _hmd; vr::IVRSystem*& _system;
friend class ViveControllerManager; friend class ViveControllerManager;
}; };
void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign); void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign);
bool _registeredWithInputMapper { false }; bool _registeredWithInputMapper { false };
bool _modelLoaded { false }; bool _modelLoaded { false };
model::Geometry _modelGeometry; model::Geometry _modelGeometry;
@ -81,8 +107,8 @@ private:
int _rightHandRenderID { 0 }; int _rightHandRenderID { 0 };
bool _renderControllers { false }; bool _renderControllers { false };
vr::IVRSystem* _hmd { nullptr }; vr::IVRSystem* _system { nullptr };
std::shared_ptr<InputDevice> _inputDevice { std::make_shared<InputDevice>(_hmd) }; std::shared_ptr<InputDevice> _inputDevice { std::make_shared<InputDevice>(_system) };
static const QString NAME; static const QString NAME;

View file

@ -1,182 +0,0 @@
// Copyright 2016 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
//
(function() {
var self = this;
this.preload = function(entityId) {
//print('preload move randomly')
this.isConnected = false;
this.entityId = entityId;
this.updateInterval = 100;
this.posFrame = 0;
this.rotFrame = 0;
this.posInterval = 100;
this.rotInterval = 100;
this.minVelocity = 1;
this.maxVelocity = 5;
this.minAngularVelocity = 0.01;
this.maxAngularVelocity = 0.03;
this.initialize(entityId);
this.initTimeout = null;
var userData = {
ownershipKey: {
owner: MyAvatar.sessionUUID
},
grabbableKey: {
grabbable: false
}
};
Entities.editEntity(entityId, {
userData: JSON.stringify(userData)
})
}
this.initialize = function(entityId) {
//print('move randomly should initialize' + entityId)
var properties = Entities.getEntityProperties(entityId);
if (properties.userData.length === 0 || properties.hasOwnProperty('userData') === false) {
self.initTimeout = Script.setTimeout(function() {
//print('no user data yet, try again in one second')
self.initialize(entityId);
}, 1000)
} else {
//print('userdata before parse attempt' + properties.userData)
self.userData = null;
try {
self.userData = JSON.parse(properties.userData);
} catch (err) {
//print('error parsing json');
//print('properties are:' + properties.userData);
return;
}
Script.update.connect(self.update);
this.isConnected = true;
}
}
this.update = function(deltaTime) {
// print('jbp in update')
var data = Entities.getEntityProperties(self.entityId, 'userData').userData;
var userData;
try {
userData = JSON.parse(data)
} catch (e) {
//print('error parsing json' + data)
return;
};
// print('userdata is' + data)
//if the entity doesnt have an owner set yet
if (userData.hasOwnProperty('ownershipKey') !== true) {
//print('no movement owner yet')
return;
}
//print('owner is:::' + userData.ownershipKey.owner)
//get all the avatars to see if the owner is around
var avatars = AvatarList.getAvatarIdentifiers();
var ownerIsAround = false;
//if the current owner is not me...
if (userData.ownershipKey.owner !== MyAvatar.sessionUUID) {
//look to see if the current owner is around anymore
for (var i = 0; i < avatars.length; i++) {
if (avatars[i] === userData.ownershipKey.owner) {
ownerIsAround = true
//the owner is around
return;
};
}
//if the owner is not around, then take ownership
if (ownerIsAround === false) {
//print('taking ownership')
var userData = {
ownershipKey: {
owner: MyAvatar.sessionUUID
},
grabbableKey: {
grabbable: false
}
};
Entities.editEntity(self.entityId, {
userData: JSON.stringify(data)
})
}
}
//but if the current owner IS me, then move it
else {
//print('jbp im the owner so move it')
self.posFrame++;
self.rotFrame++;
if (self.posFrame > self.posInterval) {
self.posInterval = 100 * Math.random() + 300;
self.posFrame = 0;
var magnitudeV = self.maxVelocity;
var directionV = {
x: Math.random() - 0.5,
y: Math.random() - 0.5,
z: Math.random() - 0.5
};
//print("POS magnitude is " + magnitudeV + " and direction is " + directionV.x);
Entities.editEntity(self.entityId, {
velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV))
});
}
if (self.rotFrame > self.rotInterval) {
self.rotInterval = 100 * Math.random() + 250;
self.rotFrame = 0;
var magnitudeAV = self.maxAngularVelocity;
var directionAV = {
x: Math.random() - 0.5,
y: Math.random() - 0.5,
z: Math.random() - 0.5
};
//print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x);
Entities.editEntity(self.entityId, {
angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV))
});
}
}
}
this.unload = function() {
if (this.initTimeout !== null) {
Script.clearTimeout(this.initTimeout);
}
if (this.isConnected === true) {
Script.update.disconnect(this.update);
}
}
})

View file

@ -7,7 +7,7 @@
(function() { (function() {
var version = 11; var version = 12;
var added = false; var added = false;
this.frame = 0; this.frame = 0;
var utilsScript = Script.resolvePath('utils.js'); var utilsScript = Script.resolvePath('utils.js');
@ -23,22 +23,21 @@
} }
this.initialize = function(entityId) { this.initialize = function(entityId) {
print('JBP nav button should initialize' + entityId)
var properties = Entities.getEntityProperties(entityId); var properties = Entities.getEntityProperties(entityId);
if (properties.userData.length === 0 || properties.hasOwnProperty('userData') === false) { if (properties.userData.length === 0 || properties.hasOwnProperty('userData') === false) {
self.initTimeout = Script.setTimeout(function() { self.initTimeout = Script.setTimeout(function() {
print('JBP no user data yet, try again in one second') // print(' no user data yet, try again in one second')
self.initialize(entityId); self.initialize(entityId);
}, 1000) }, 1000)
} else { } else {
print('JBP userdata before parse attempt' + properties.userData) // print('userdata before parse attempt' + properties.userData)
self.userData = null; self.userData = null;
try { try {
self.userData = JSON.parse(properties.userData); self.userData = JSON.parse(properties.userData);
} catch (err) { } catch (err) {
print('JBP error parsing json'); // print(' error parsing json');
print('JBP properties are:' + properties.userData); // print(' properties are:' + properties.userData);
return; return;
} }
@ -46,9 +45,9 @@
var mySavedSettings = Settings.getValue(entityId); var mySavedSettings = Settings.getValue(entityId);
if (mySavedSettings.buttons !== undefined) { if (mySavedSettings.buttons !== undefined) {
print('JBP preload buttons' + mySavedSettings.buttons) // print(' preload buttons' + mySavedSettings.buttons)
mySavedSettings.buttons.forEach(function(b) { mySavedSettings.buttons.forEach(function(b) {
print('JBP deleting button' + b) // print(' deleting button' + b)
Overlays.deleteOverlay(b); Overlays.deleteOverlay(b);
}) })
Settings.setValue(entityId, '') Settings.setValue(entityId, '')
@ -56,16 +55,15 @@
self.buttonImageURL = baseURL + "GUI/GUI_" + self.userData.name + ".png?" + version; self.buttonImageURL = baseURL + "GUI/GUI_" + self.userData.name + ".png?" + version;
print('JBP BUTTON IMAGE URL:' + self.buttonImageURL) // print(' BUTTON IMAGE URL:' + self.buttonImageURL)
if (self.button === undefined) { if (self.button === undefined) {
// print('NAV NO BUTTON ADDING ONE!!') // print(' NO BUTTON ADDING ONE!!')
self.button = true; self.button = true;
self.addButton(); self.addButton();
} else { } else {
// print('NAV SELF ALREADY HAS A BUTTON!!') //print(' SELF ALREADY HAS A BUTTON!!')
} }
} }
} }

View file

@ -36,8 +36,6 @@
return; return;
} }
self.addButton(); self.addButton();
self.buttonShowing = false; self.buttonShowing = false;
self.showDistance = self.userData.showDistance; self.showDistance = self.userData.showDistance;
@ -51,8 +49,6 @@
}; };
self.sound = SoundCache.getSound(this.soundURL); self.sound = SoundCache.getSound(this.soundURL);
} }
this.addButton = function() { this.addButton = function() {

View file

@ -10,7 +10,7 @@
var self = this; var self = this;
var baseURL = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; var baseURL = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/";
var version = 2; var version = 3;
this.preload = function(entityId) { this.preload = function(entityId) {
this.soundPlaying = null; this.soundPlaying = null;
this.entityId = entityId; this.entityId = entityId;

View file

@ -52,13 +52,7 @@
print("Teleporting to (" + data.location.x + ", " + data.location.y + ", " + data.location.z + ")"); print("Teleporting to (" + data.location.x + ", " + data.location.y + ", " + data.location.z + ")");
MyAvatar.position = data.location; MyAvatar.position = data.location;
// if (data.hasOwnProperty('entryPoint') && data.hasOwnProperty('target')) {
// this.lookAtTarget(data.entryPoint, data.target);
// }
// else{
// }
} }
} }
@ -103,10 +97,4 @@
} }
} }
this.hoverEnterEntity = function(entityID) {
Entities.editEntity(entityID, {
animationURL: animationURL,
animationSettings: '{ "fps": 24, "firstFrame": 1, "lastFrame": 25, "frameIndex": 1, "running": true, "hold": true }'
});
}
}) })

View file

@ -7,7 +7,7 @@ var soundMap = [{
y: 15850, y: 15850,
z: 15850 z: 15850
}, },
volume: 0.1, volume: 0.03,
loop: true loop: true
} }
}, { }, {
@ -19,7 +19,7 @@ var soundMap = [{
y: 15950, y: 15950,
z: 15950 z: 15950
}, },
volume: 0.1, volume: 0.03,
loop: true loop: true
} }
}, { }, {
@ -31,7 +31,7 @@ var soundMap = [{
y: 15650, y: 15650,
z: 15650 z: 15650
}, },
volume: 0.1, volume: 0.03,
loop: true loop: true
} }
}, { }, {
@ -43,7 +43,7 @@ var soundMap = [{
y: 15750, y: 15750,
z: 15750 z: 15750
}, },
volume: 0.1, volume: 0.03,
loop: true loop: true
} }
} }

View file

@ -5,7 +5,7 @@
// 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
// //
var version = 1035; var version = 1112;
var cellLayout; var cellLayout;
var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/"; var baseLocation = "https://hifi-content.s3.amazonaws.com/DomainContent/CellScience/";
@ -103,9 +103,9 @@ var scenes = [{
instances: [{ instances: [{
model: "Cell", model: "Cell",
dimensions: { dimensions: {
x: 550, x: 500,
y: 620, y: 570,
z: 550 z: 500
}, },
offset: { offset: {
x: 0, x: 0,
@ -151,294 +151,253 @@ var scenes = [{
skybox: "cosmos_skybox_blurred" skybox: "cosmos_skybox_blurred"
}, },
instances: [{ instances: [{
model: "translation", model: "translation",
dimensions: { dimensions: {
x: 10, x: 10,
y: 16, y: 16,
z: 10 z: 10
},
offset: {
x: 0,
y: 0,
z: 0
},
radius: 300,
number: 7,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
},
target: locations.ribosome[1],
location: locations.ribosome[0],
baseURL: baseLocation
}),
script: "zoom.js?" + version,
visible: true
}, {
model: "vesicle",
dimensions: {
x: 60,
y: 60,
z: 60
},
randomSize: 10,
offset: {
x: 0,
y: 0,
z: 0
},
radius: 1000,
number: 22,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}
}),
script: "moveRandomly.js?" + version,
visible: true
}, { //golgi vesicles
model: "vesicle",
dimensions: {
x: 10,
y: 10,
z: 10
},
randomSize: 10,
offset: {
x: -319,
y: 66,
z: 976
},
radius: 140,
number: 10,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}
}),
script: "",
visible: true
}, { //golgi vesicles
model: "vesicle",
dimensions: {
x: 15,
y: 15,
z: 15
},
randomSize: 10,
offset: {
x: -319,
y: 66,
z: 976
},
radius: 115,
number: 7,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}
}),
script: "moveRandomly.js?" + version,
visible: true
}, {
model: "vesicle",
dimensions: {
x: 50,
y: 50,
z: 50
},
randomSize: 10,
offset: {
x: 0,
y: 0,
z: 0
},
radius: 600,
number: 15,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}
}),
script: "",
visible: true
}, { //outer vesicles
model: "vesicle",
dimensions: {
x: 60,
y: 60,
z: 60
},
randomSize: 10,
offset: {
x: 0,
y: 0,
z: 0
},
radius: 1600,
number: 22,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}
}),
script: "",
visible: true
}, { //outer vesicles
model: "vesicle",
dimensions: {
x: 40,
y: 40,
z: 40
},
randomSize: 10,
offset: {
x: 0,
y: 0,
z: 0
},
radius: 1400,
number: 22,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}
}),
script: "moveRandomly.js?" + version,
visible: true
}, { //outer vesicles
model: "vesicle",
dimensions: {
x: 80,
y: 80,
z: 80
},
randomSize: 10,
offset: {
x: 0,
y: 0,
z: 0
},
radius: 1800,
number: 22,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}
}),
script: "moveRandomly.js?" + version,
visible: true
}, },
// {//wigglies offset: {
// model:"wiggly", x: 0,
// dimensions:{x:320,y:40,z:160}, y: 0,
// randomSize: 10, z: 0
// offset:{x:0,y:0,z:0}, },
// radius:1800, radius: 300,
// number:50, number: 7,
// userData:"", userData: JSON.stringify({
// script:"moveRandomly", grabbableKey: {
// visible:true grabbable: false
// },
//// {//wigglies
// model:"wiggly",
// dimensions:{x:640,y:80,z:320},
// randomSize: 10,
// offset:{x:0,y:0,z:0},
// radius:2100,
// number:50,
// userData:"",
// script:"moveRandomly",
// visible:true
// },
{
model: "hexokinase",
dimensions: {
x: 3,
y: 4,
z: 3
}, },
randomSize: 10, target: locations.ribosome[1],
offset: { location: locations.ribosome[0],
x: 236, baseURL: baseLocation
y: 8, }),
z: 771 script: "zoom.js?" + version,
visible: true
}, {
model: "vesicle",
dimensions: {
x: 60,
y: 60,
z: 60
},
randomSize: 10,
offset: {
x: 0,
y: 0,
z: 0
},
radius: 1000,
number: 22,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}
}),
visible: true
}, { //golgi vesicles
model: "vesicle",
dimensions: {
x: 10,
y: 10,
z: 10
},
randomSize: 10,
offset: {
x: -319,
y: 66,
z: 976
},
radius: 140,
number: 10,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}
}),
script: "",
visible: true
}, { //golgi vesicles
model: "vesicle",
dimensions: {
x: 15,
y: 15,
z: 15
},
randomSize: 10,
offset: {
x: -319,
y: 66,
z: 976
},
radius: 115,
number: 7,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}
}),
visible: true
}, {
model: "vesicle",
dimensions: {
x: 50,
y: 50,
z: 50
},
randomSize: 10,
offset: {
x: 0,
y: 0,
z: 0
},
radius: 600,
number: 15,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}
}),
script: "",
visible: true
}, { //outer vesicles
model: "vesicle",
dimensions: {
x: 60,
y: 60,
z: 60
},
randomSize: 10,
offset: {
x: 0,
y: 0,
z: 0
},
radius: 1600,
number: 22,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}
}),
script: "",
visible: true
}, { //outer vesicles
model: "vesicle",
dimensions: {
x: 40,
y: 40,
z: 40
},
randomSize: 10,
offset: {
x: 0,
y: 0,
z: 0
},
radius: 1400,
number: 22,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}
}),
visible: true
}, { //outer vesicles
model: "vesicle",
dimensions: {
x: 80,
y: 80,
z: 80
},
randomSize: 10,
offset: {
x: 0,
y: 0,
z: 0
},
radius: 1800,
number: 22,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}
}),
visible: true
}, {
model: "hexokinase",
dimensions: {
x: 3,
y: 4,
z: 3
},
randomSize: 10,
offset: {
x: 236,
y: 8,
z: 771
},
radius: 80,
number: 7,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}, },
radius: 80, target: locations.hexokinase[1],
number: 7, location: locations.hexokinase[0],
userData: JSON.stringify({ baseURL: baseLocation
grabbableKey: { }),
grabbable: false script: "zoom.js?" + version,
}, visible: true
target: locations.hexokinase[1], }, {
location: locations.hexokinase[0], model: "pfructo_kinase",
baseURL: baseLocation dimensions: {
}), x: 3,
script: "zoom.js?" + version, y: 4,
visible: true z: 3
}, { },
model: "pfructo_kinase", randomSize: 10,
dimensions: { offset: {
x: 3, x: 236,
y: 4, y: 8,
z: 3 z: 771
},
radius: 60,
number: 7,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}, },
randomSize: 10, target: locations.hexokinase[1],
offset: { location: locations.hexokinase[0],
x: 236, }),
y: 8, script: "zoom.js?" + version,
z: 771 visible: true
}, {
model: "glucose_isomerase",
dimensions: {
x: 3,
y: 4,
z: 3
},
randomSize: 10,
offset: {
x: 236,
y: 8,
z: 771
},
radius: 70,
number: 7,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}, },
radius: 60, target: locations.hexokinase[1],
number: 7, location: locations.hexokinase[0],
userData: JSON.stringify({ }),
grabbableKey: { script: "zoom.js?" + version,
grabbable: false visible: true
}, }],
target: locations.hexokinase[1],
location: locations.hexokinase[0],
}),
script: "zoom.js?" + version,
visible: true
}, {
model: "glucose_isomerase",
dimensions: {
x: 3,
y: 4,
z: 3
},
randomSize: 10,
offset: {
x: 236,
y: 8,
z: 771
},
radius: 70,
number: 7,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
},
target: locations.hexokinase[1],
location: locations.hexokinase[0],
}),
script: "zoom.js?" + version,
visible: true
}
// {
// model:"NPC",
// dimensions:{x:20,y:20,z:20},
// randomSize: 10,
// offset:{x:208.593693,y:6.113100222,z:153.3202277},
// radius:520,
// number:25,
// userData: "",
// script:"",
// visible:true
// }
],
boundary: { boundary: {
radius: locations.cellLayout[2], radius: locations.cellLayout[2],
center: locations.cellLayout[0], center: locations.cellLayout[0],
@ -600,7 +559,7 @@ function ImportScene(scene) {
CreateZone(scene); CreateZone(scene);
CreateInstances(scene); CreateInstances(scene);
CreateBoundary(scene); // CreateBoundary(scene);
// print("done " + scene.name); // print("done " + scene.name);
@ -609,12 +568,10 @@ function ImportScene(scene) {
clearAllNav(); clearAllNav();
function clearAllNav() { function clearAllNav() {
// print('NAV CLEARING ALL NAV');
var result = Entities.findEntities(MyAvatar.position, 25000); var result = Entities.findEntities(MyAvatar.position, 25000);
result.forEach(function(r) { result.forEach(function(r) {
var properties = Entities.getEntityProperties(r, "name"); var properties = Entities.getEntityProperties(r, "name");
if (properties.name.indexOf('navigation button') > -1) { if (properties.name.indexOf('navigation button') > -1) {
// print('NAV DELETING NAV BUTTON AT START:: '+r)
Entities.deleteEntity(r); Entities.deleteEntity(r);
} }
}) })
@ -645,9 +602,6 @@ function createLayoutLights() {
} }
function CreateNavigationButton(scene, number) { function CreateNavigationButton(scene, number) {
// print('NAV NAVIGATION CREATING NAV!!' +scene.name + " " + number)
Entities.addEntity({ Entities.addEntity({
type: "Box", type: "Box",
name: scene.name + " navigation button", name: scene.name + " navigation button",
@ -818,7 +772,7 @@ function CreateInstances(scene) {
x: 0, x: 0,
y: 0, y: 0,
z: 0 z: 0
}, idBounds, 150); }, idBounds, 150, scene.instances[i]);
} }
//print('SCRIPT AT CREATE ENTITY: ' + script) //print('SCRIPT AT CREATE ENTITY: ' + script)
@ -831,6 +785,7 @@ function CreateInstances(scene) {
function CreateIdentification(name, position, rotation, dimensions, showDistance) { function CreateIdentification(name, position, rotation, dimensions, showDistance) {
//print ("creating ID for " + name); //print ("creating ID for " + name);
Entities.addEntity({ Entities.addEntity({
type: "Sphere", type: "Sphere",
name: "ID for " + name, name: "ID for " + name,
@ -9045,4 +9000,9 @@ createLayoutLights();
Script.scriptEnding.connect(function() { Script.scriptEnding.connect(function() {
Entities.addingEntity.disconnect(makeUngrabbable); Entities.addingEntity.disconnect(makeUngrabbable);
}); });
Script.setTimeout(function() {
print('JBP stopping cell science import');
Script.stop();
}, 30000)

View file

@ -18,8 +18,6 @@ if (USE_LOCAL_HOST === true) {
var USE_LOCAL_HOST = false; var USE_LOCAL_HOST = false;
Agent.isAvatar = true;
EntityViewer.setPosition({ EntityViewer.setPosition({
x: 3000, x: 3000,
y: 13500, y: 13500,

View file

@ -0,0 +1,103 @@
// Copyright 2016 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 basePosition = {
x: 3000,
y: 13500,
z: 3000
};
var initialized = false;
EntityViewer.setPosition(basePosition);
EntityViewer.setKeyholeRadius(60000);
var octreeQueryInterval = Script.setInterval(function() {
EntityViewer.queryOctree();
}, 200);
var THROTTLE = true;
var THROTTLE_RATE = 5000;
var sinceLastUpdate = 0;
//print('cells script')
function findCells() {
var results = Entities.findEntities(basePosition, 60000);
if (results.length === 0) {
// print('no entities found')
return;
}
results.forEach(function(v) {
var name = Entities.getEntityProperties(v, 'name').name;
// print('name is:: ' + name)
if (name === 'Cell') {
// print('found a cell!!' + v)
Script.setTimeout(function() {
moveCell(v);
}, Math.random() * THROTTLE_RATE);
}
});
}
var minAngularVelocity = 0.01;
var maxAngularVelocity = 0.03;
function moveCell(entityId) {
// print('moving a cell! ' + entityId)
var magnitudeAV = maxAngularVelocity;
var directionAV = {
x: Math.random() - 0.5,
y: Math.random() - 0.5,
z: Math.random() - 0.5
};
// print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x);
Entities.editEntity(entityId, {
angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV))
});
}
function update(deltaTime) {
// print('deltaTime',deltaTime)
if (!initialized) {
print("checking for servers...");
if (Entities.serversExist() && Entities.canRez()) {
print("servers exist -- makeAll...");
Entities.setPacketsPerSecond(6000);
print("PPS:" + Entities.getPacketsPerSecond());
initialized = true;
}
return;
}
if (THROTTLE === true) {
sinceLastUpdate = sinceLastUpdate + deltaTime * 1000;
if (sinceLastUpdate > THROTTLE_RATE) {
// print('SHOULD FIND CELLS!!!')
sinceLastUpdate = 0;
findCells();
} else {
// print('returning in update ' + sinceLastUpdate)
return;
}
}
}
function unload() {
Script.update.disconnect(update);
}
Script.update.connect(update);
Script.scriptEnding.connect(unload);

View file

@ -0,0 +1,108 @@
// Copyright 2016 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 basePosition = {
x: 3000,
y: 13500,
z: 3000
};
var initialized = false;
EntityViewer.setPosition(basePosition);
EntityViewer.setKeyholeRadius(60000);
var octreeQueryInterval = Script.setInterval(function() {
EntityViewer.queryOctree();
}, 200);
var THROTTLE = true;
var THROTTLE_RATE = 5000;
var sinceLastUpdate = 0;
//print('vesicle script')
function findVesicles() {
var results = Entities.findEntities(basePosition, 60000);
if (results.length === 0) {
// print('no entities found');
return;
}
results.forEach(function(v) {
var name = Entities.getEntityProperties(v, 'name').name;
if (name === 'vesicle') {
//print('found a vesicle!!' + v)
Script.setTimeout(function() {
moveVesicle(v);
}, Math.random() * THROTTLE_RATE);
}
});
}
var minVelocity = 1;
var maxVelocity = 5;
var minAngularVelocity = 0.01;
var maxAngularVelocity = 0.03;
function moveVesicle(entityId) {
// print('moving a vesicle! ' + entityId)
var magnitudeV = maxVelocity;
var directionV = {
x: Math.random() - 0.5,
y: Math.random() - 0.5,
z: Math.random() - 0.5
};
// print("POS magnitude is " + magnitudeV + " and direction is " + directionV.x);
var magnitudeAV = maxAngularVelocity;
var directionAV = {
x: Math.random() - 0.5,
y: Math.random() - 0.5,
z: Math.random() - 0.5
};
// print("ROT magnitude is " + magnitudeAV + " and direction is " + directionAV.x);
Entities.editEntity(entityId, {
velocity: Vec3.multiply(magnitudeV, Vec3.normalize(directionV)),
angularVelocity: Vec3.multiply(magnitudeAV, Vec3.normalize(directionAV))
});
}
function update(deltaTime) {
if (!initialized) {
print("checking for servers...");
if (Entities.serversExist() && Entities.canRez()) {
print("servers exist -- makeAll...");
Entities.setPacketsPerSecond(6000);
print("PPS:" + Entities.getPacketsPerSecond());
initialized = true;
}
return;
}
if (THROTTLE === true) {
sinceLastUpdate = sinceLastUpdate + deltaTime * 1000;
if (sinceLastUpdate > THROTTLE_RATE) {
sinceLastUpdate = 0;
findVesicles();
} else {
return;
}
}
}
function unload() {
Script.update.disconnect(update);
}
Script.update.connect(update);
Script.scriptEnding.connect(unload);