mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 03:44:02 +02:00
Merge branch 'master' into tony/anim-sync-blend
This commit is contained in:
commit
a9ed033b20
50 changed files with 506 additions and 244 deletions
|
@ -19,7 +19,7 @@ Script.include("../libraries/utils.js");
|
|||
//
|
||||
// add lines where the hand ray picking is happening
|
||||
//
|
||||
var DEBUG_HAND_RAY_PICKING = false;
|
||||
var WANT_DEBUG = false;
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
@ -49,6 +49,7 @@ var PICK_MAX_DISTANCE = 500; // max length of pick-ray
|
|||
// near grabbing
|
||||
//
|
||||
|
||||
var GRAB_RADIUS = 0.3; // if the ray misses but an object is this close, it will still be selected
|
||||
var NEAR_GRABBING_ACTION_TIMEFRAME = 0.05; // how quickly objects move to their new position
|
||||
var NEAR_GRABBING_VELOCITY_SMOOTH_RATIO = 1.0; // adjust time-averaging of held object's velocity. 1.0 to disable.
|
||||
var NEAR_PICK_MAX_DISTANCE = 0.3; // max length of pick-ray for close grabbing to be selected
|
||||
|
@ -193,22 +194,23 @@ function MyController(hand, triggerAction) {
|
|||
};
|
||||
|
||||
this.setState = function(newState) {
|
||||
// print("STATE: " + this.state + " --> " + newState);
|
||||
if (WANT_DEBUG) {
|
||||
print("STATE: " + this.state + " --> " + newState);
|
||||
}
|
||||
this.state = newState;
|
||||
}
|
||||
|
||||
|
||||
this.debugLine = function(closePoint, farPoint, color){
|
||||
Entities.addEntity({
|
||||
type: "Line",
|
||||
name: "Debug Line",
|
||||
dimensions: LINE_ENTITY_DIMENSIONS,
|
||||
visible: true,
|
||||
position: closePoint,
|
||||
linePoints: [ZERO_VEC, farPoint],
|
||||
color: color,
|
||||
lifetime: 0.1
|
||||
});
|
||||
Entities.addEntity({
|
||||
type: "Line",
|
||||
name: "Debug Line",
|
||||
dimensions: LINE_ENTITY_DIMENSIONS,
|
||||
visible: true,
|
||||
position: closePoint,
|
||||
linePoints: [ZERO_VEC, farPoint],
|
||||
color: color,
|
||||
lifetime: 0.1
|
||||
});
|
||||
}
|
||||
|
||||
this.lineOn = function(closePoint, farPoint, color) {
|
||||
|
@ -226,14 +228,13 @@ function MyController(hand, triggerAction) {
|
|||
});
|
||||
} else {
|
||||
var age = Entities.getEntityProperties(this.pointer, "age").age;
|
||||
Entities.editEntity(this.pointer, {
|
||||
this.pointer = Entities.editEntity(this.pointer, {
|
||||
position: closePoint,
|
||||
linePoints: [ZERO_VEC, farPoint],
|
||||
color: color,
|
||||
lifetime: age + LIFETIME
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.lineOff = function() {
|
||||
|
@ -282,7 +283,6 @@ function MyController(hand, triggerAction) {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
// the trigger is being pressed, do a ray test
|
||||
var handPosition = this.getHandPosition();
|
||||
var distantPickRay = {
|
||||
|
@ -290,29 +290,17 @@ function MyController(hand, triggerAction) {
|
|||
direction: Quat.getUp(this.getHandRotation()),
|
||||
length: PICK_MAX_DISTANCE
|
||||
};
|
||||
var palmPickRay = {
|
||||
origin: handPosition,
|
||||
direction: Quat.getFront(this.getHandRotation()),
|
||||
length: NEAR_PICK_MAX_DISTANCE
|
||||
};
|
||||
|
||||
var otherPickRay = {
|
||||
origin: handPosition,
|
||||
direction: Quat.getRight(this.getHandRotation()),
|
||||
length: NEAR_PICK_MAX_DISTANCE
|
||||
};
|
||||
|
||||
|
||||
this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
|
||||
|
||||
// don't pick 60x per second. do this check after updating the line so it's not jumpy.
|
||||
// don't pick 60x per second.
|
||||
var pickRays = [];
|
||||
var now = Date.now();
|
||||
if (now - this.lastPickTime < MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) {
|
||||
return;
|
||||
if (now - this.lastPickTime > MSECS_PER_SEC / PICKS_PER_SECOND_PER_HAND) {
|
||||
pickRays = [distantPickRay];
|
||||
this.lastPickTime = now;
|
||||
}
|
||||
this.lastPickTime = now;
|
||||
|
||||
var pickRays = [distantPickRay, palmPickRay, otherPickRay];
|
||||
for (var index=0; index < pickRays.length; ++index) {
|
||||
var pickRay = pickRays[index];
|
||||
var directionNormalized = Vec3.normalize(pickRay.direction);
|
||||
|
@ -322,12 +310,13 @@ function MyController(hand, triggerAction) {
|
|||
direction: pickRay.direction
|
||||
};
|
||||
|
||||
if (DEBUG_HAND_RAY_PICKING)
|
||||
if (WANT_DEBUG) {
|
||||
this.debugLine(pickRayBacked.origin, Vec3.multiply(pickRayBacked.direction, NEAR_PICK_MAX_DISTANCE), {
|
||||
red: 0,
|
||||
green: 255,
|
||||
blue: 0
|
||||
})
|
||||
}
|
||||
|
||||
var intersection = Entities.findRayIntersection(pickRayBacked, true);
|
||||
|
||||
|
@ -336,7 +325,6 @@ function MyController(hand, triggerAction) {
|
|||
var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection);
|
||||
this.grabbedEntity = intersection.entityID;
|
||||
|
||||
|
||||
//this code will disabled the beam for the opposite hand of the one that grabbed it if the entity says so
|
||||
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA);
|
||||
if (grabbableData["turnOffOppositeBeam"] === true) {
|
||||
|
@ -345,7 +333,6 @@ function MyController(hand, triggerAction) {
|
|||
} else {
|
||||
disabledHand = RIGHT_HAND;
|
||||
}
|
||||
|
||||
} else {
|
||||
disabledHand = 'none';
|
||||
}
|
||||
|
@ -380,6 +367,37 @@ function MyController(hand, triggerAction) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.grabbedEntity === null) {
|
||||
// forward ray test failed, try sphere test.
|
||||
var nearbyEntities = Entities.findEntities(handPosition, GRAB_RADIUS);
|
||||
var minDistance = PICK_MAX_DISTANCE;
|
||||
var i, props, distance, grabbableData;
|
||||
for (i = 0; i < nearbyEntities.length; i++) {
|
||||
var grabbableDataForCandidate =
|
||||
getEntityCustomData(GRABBABLE_DATA_KEY, nearbyEntities[i], DEFAULT_GRABBABLE_DATA);
|
||||
if (grabbableDataForCandidate.grabbable === false) {
|
||||
continue;
|
||||
}
|
||||
var propsForCandidate =
|
||||
Entities.getEntityProperties(nearbyEntities[i], ["position", "name", "collisionsWillMove", "locked"]);
|
||||
distance = Vec3.distance(propsForCandidate.position, handPosition);
|
||||
if (distance < minDistance && propsForCandidate.name !== "pointer") {
|
||||
this.grabbedEntity = nearbyEntities[i];
|
||||
minDistance = distance;
|
||||
props = propsForCandidate;
|
||||
grabbableData = grabbableDataForCandidate;
|
||||
}
|
||||
}
|
||||
if (this.grabbedEntity === null) {
|
||||
return;
|
||||
} else if (props.locked === 0 && props.collisionsWillMove === 1) {
|
||||
this.setState(STATE_NEAR_GRABBING);
|
||||
} else if (props.collisionsWillMove === 0 && grabbableData.wantsTrigger) {
|
||||
// We have grabbed a non-physical object, so we want to trigger a non-colliding event as opposed to a grab event
|
||||
this.setState(STATE_NEAR_GRABBING_NON_COLLIDING);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.distanceHolding = function() {
|
||||
|
@ -441,7 +459,8 @@ function MyController(hand, triggerAction) {
|
|||
this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR);
|
||||
|
||||
// the action was set up on a previous call. update the targets.
|
||||
var radius = Math.max(Vec3.distance(this.currentObjectPosition, handControllerPosition) * DISTANCE_HOLDING_RADIUS_FACTOR, DISTANCE_HOLDING_RADIUS_FACTOR);
|
||||
var radius = Math.max(Vec3.distance(this.currentObjectPosition, handControllerPosition) *
|
||||
DISTANCE_HOLDING_RADIUS_FACTOR, DISTANCE_HOLDING_RADIUS_FACTOR);
|
||||
// how far did avatar move this timestep?
|
||||
var currentPosition = MyAvatar.position;
|
||||
var avatarDeltaPosition = Vec3.subtract(currentPosition, this.currentAvatarPosition);
|
||||
|
@ -491,7 +510,10 @@ function MyController(hand, triggerAction) {
|
|||
this.currentObjectTime = now;
|
||||
|
||||
// this doubles hand rotation
|
||||
var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation, handRotation, DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR), Quat.inverse(this.handPreviousRotation));
|
||||
var handChange = Quat.multiply(Quat.slerp(this.handPreviousRotation,
|
||||
handRotation,
|
||||
DISTANCE_HOLDING_ROTATION_EXAGGERATION_FACTOR),
|
||||
Quat.inverse(this.handPreviousRotation));
|
||||
this.handPreviousRotation = handRotation;
|
||||
this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation);
|
||||
|
||||
|
@ -526,7 +548,8 @@ function MyController(hand, triggerAction) {
|
|||
|
||||
this.lineOff();
|
||||
|
||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, ["position", "rotation", "gravity", "ignoreForCollisions"]);
|
||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity,
|
||||
["position", "rotation", "gravity", "ignoreForCollisions"]);
|
||||
this.activateEntity(this.grabbedEntity, grabbedProperties);
|
||||
|
||||
var handRotation = this.getHandRotation();
|
||||
|
@ -764,9 +787,9 @@ function MyController(hand, triggerAction) {
|
|||
|
||||
this.release = function() {
|
||||
|
||||
if(this.hand!==disabledHand){
|
||||
if(this.hand !== disabledHand){
|
||||
//release the disabled hand when we let go with the main one
|
||||
disabledHand='none';
|
||||
disabledHand = 'none';
|
||||
}
|
||||
this.lineOff();
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
//
|
||||
// breakdanceCore.js
|
||||
// examples/toys
|
||||
//
|
||||
// This is the core breakdance game library, it can be used as part of an entity script, or an omniTool module, or bootstapped on it's own
|
||||
// Created by Brad Hefta-Gaub on August 24, 2015
|
|
@ -7,10 +7,10 @@
|
|||
//
|
||||
|
||||
// FIXME Script paths have to be relative to the caller, in this case libraries/OmniTool.js
|
||||
Script.include("../toys/magBalls/constants.js");
|
||||
Script.include("../toys/magBalls/graph.js");
|
||||
Script.include("../toys/magBalls/edgeSpring.js");
|
||||
Script.include("../toys/magBalls/magBalls.js");
|
||||
Script.include("../entityScripts/magBalls/constants.js");
|
||||
Script.include("../entityScripts/magBalls/graph.js");
|
||||
Script.include("../entityScripts/magBalls/edgeSpring.js");
|
||||
Script.include("../entityScripts/magBalls/magBalls.js");
|
||||
Script.include("avatarRelativeOverlays.js");
|
||||
|
||||
OmniToolModuleType = "MagBallsController"
|
146
examples/toybox/AC_scripts/toybox_sounds.js
Normal file
146
examples/toybox/AC_scripts/toybox_sounds.js
Normal file
|
@ -0,0 +1,146 @@
|
|||
//
|
||||
// toys/AC_scripts/toybox_sounds.js
|
||||
//
|
||||
// This script adds several sounds to the correct locations for toybox.
|
||||
// By James B. Pollack @imgntn 10/21/2015
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var soundMap = [{
|
||||
name: 'river water',
|
||||
url: "http://hifi-public.s3.amazonaws.com/ryan/Water_Lap_River_Edge_Gentle.L.wav",
|
||||
audioOptions: {
|
||||
position: {
|
||||
x: 580,
|
||||
y: 493,
|
||||
z: 528
|
||||
},
|
||||
volume: 0.4,
|
||||
loop: true
|
||||
}
|
||||
}, {
|
||||
name: 'windmill',
|
||||
url: "http://hifi-public.s3.amazonaws.com/ryan/WINDMILL_Mono.wav",
|
||||
audioOptions: {
|
||||
position: {
|
||||
x: 530,
|
||||
y: 516,
|
||||
z: 518
|
||||
},
|
||||
volume: 0.08,
|
||||
loop: true
|
||||
}
|
||||
}, {
|
||||
name: 'insects',
|
||||
url: "http://hifi-public.s3.amazonaws.com/ryan/insects3.wav",
|
||||
audioOptions: {
|
||||
position: {
|
||||
x: 560,
|
||||
y: 495,
|
||||
z: 474
|
||||
},
|
||||
volume: 0.25,
|
||||
loop: true
|
||||
}
|
||||
}, {
|
||||
name: 'fireplace',
|
||||
url: "http://hifi-public.s3.amazonaws.com/ryan/demo/0619_Fireplace__Tree_B.L.wav",
|
||||
audioOptions: {
|
||||
position: {
|
||||
x: 551.61,
|
||||
y: 494.88,
|
||||
z: 502.00
|
||||
},
|
||||
volume: 0.25,
|
||||
loop: true
|
||||
}
|
||||
}, {
|
||||
name: 'cat purring',
|
||||
url: "http://hifi-public.s3.amazonaws.com/ryan/Cat_Purring_Deep_Low_Snor.wav",
|
||||
audioOptions: {
|
||||
position: {
|
||||
x: 551.48,
|
||||
y: 495.60,
|
||||
z: 502.08
|
||||
},
|
||||
volume: 0.25,
|
||||
loop: true
|
||||
}
|
||||
}, {
|
||||
name: 'dogs barking',
|
||||
url: "http://hifi-public.s3.amazonaws.com/ryan/dogs_barking_1.L.wav",
|
||||
audioOptions: {
|
||||
position: {
|
||||
x: 551.61,
|
||||
y: 494.88,
|
||||
z: 502.00
|
||||
},
|
||||
volume: 0.15,
|
||||
loop: false
|
||||
},
|
||||
playAtInterval: 60 * 1000
|
||||
}];
|
||||
|
||||
function loadSounds() {
|
||||
soundMap.forEach(function(soundData) {
|
||||
soundData.sound = SoundCache.getSound(soundData.url);
|
||||
});
|
||||
}
|
||||
|
||||
function playSound(soundData) {
|
||||
if (soundData.injector) {
|
||||
// try/catch in case the injector QObject has been deleted already
|
||||
try {
|
||||
soundData.injector.stop();
|
||||
} catch (e) {}
|
||||
}
|
||||
soundData.injector = Audio.playSound(soundData.sound, soundData.audioOptions);
|
||||
}
|
||||
|
||||
function checkDownloaded(soundData) {
|
||||
if (soundData.sound.downloaded) {
|
||||
|
||||
Script.clearInterval(soundData.downloadTimer);
|
||||
|
||||
if (soundData.hasOwnProperty('playAtInterval')) {
|
||||
soundData.playingInterval = Script.setInterval(function() {
|
||||
playSound(soundData)
|
||||
}, soundData.playAtInterval);
|
||||
} else {
|
||||
playSound(soundData);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function startCheckDownloadedTimers() {
|
||||
soundMap.forEach(function(soundData) {
|
||||
soundData.downloadTimer = Script.setInterval(function() {
|
||||
checkDownloaded(soundData);
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(function() {
|
||||
soundMap.forEach(function(soundData) {
|
||||
|
||||
if (soundData.hasOwnProperty("injector")) {
|
||||
soundData.injector.stop();
|
||||
}
|
||||
|
||||
if (soundData.hasOwnProperty("downloadTimer")) {
|
||||
Script.clearInterval(soundData.downloadTimer);
|
||||
}
|
||||
|
||||
if (soundData.hasOwnProperty("playingInterval")) {
|
||||
Script.clearInterval(soundData.playingInterval);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
loadSounds();
|
||||
startCheckDownloadedTimers();
|
|
@ -36,6 +36,10 @@ var hoop = Entities.addEntity({
|
|||
y: 3.99,
|
||||
z: 3.79
|
||||
},
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
grabbable: false
|
||||
}
|
||||
})
|
||||
compoundShapeURL: hoopCollisionHullURL
|
||||
});
|
||||
|
||||
});
|
|
@ -22,8 +22,6 @@ var DIAMETER = 0.30;
|
|||
var RESET_DISTANCE = 1;
|
||||
var MINIMUM_MOVE_LENGTH = 0.05;
|
||||
|
||||
var GRABBABLE_DATA_KEY = "grabbableKey";
|
||||
|
||||
var rackStartPosition =
|
||||
Vec3.sum(MyAvatar.position,
|
||||
Vec3.multiplyQbyV(MyAvatar.orientation, {
|
||||
|
@ -53,19 +51,17 @@ var rack = Entities.addEntity({
|
|||
ignoreForCollisions: false,
|
||||
collisionSoundURL: collisionSoundURL,
|
||||
compoundShapeURL: rackCollisionHullURL,
|
||||
// scriptURL: rackScriptURL
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
grabbable: false
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
setEntityCustomData(GRABBABLE_DATA_KEY, rack, {
|
||||
grabbable: false
|
||||
});
|
||||
|
||||
var nonCollidingBalls = [];
|
||||
var collidingBalls = [];
|
||||
var balls = [];
|
||||
var originalBallPositions = [];
|
||||
|
||||
function createCollidingBalls() {
|
||||
function createBalls() {
|
||||
var position = rackStartPosition;
|
||||
|
||||
var i;
|
||||
|
@ -76,9 +72,9 @@ function createCollidingBalls() {
|
|||
z: position.z + (DIAMETER) - (DIAMETER * i)
|
||||
};
|
||||
|
||||
var collidingBall = Entities.addEntity({
|
||||
var ball = Entities.addEntity({
|
||||
type: "Model",
|
||||
name: 'Colliding Basketball',
|
||||
name: 'Hifi-Basketball',
|
||||
shapeType: 'Sphere',
|
||||
position: ballPosition,
|
||||
dimensions: {
|
||||
|
@ -96,16 +92,21 @@ function createCollidingBalls() {
|
|||
collisionsWillMove: true,
|
||||
ignoreForCollisions: false,
|
||||
modelURL: basketballURL,
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
collidingBalls.push(collidingBall);
|
||||
balls.push(ball);
|
||||
originalBallPositions.push(position);
|
||||
}
|
||||
}
|
||||
|
||||
function testBallDistanceFromStart() {
|
||||
var resetCount = 0;
|
||||
collidingBalls.forEach(function(ball, index) {
|
||||
balls.forEach(function(ball, index) {
|
||||
var currentPosition = Entities.getEntityProperties(ball, "position").position;
|
||||
var originalPosition = originalBallPositions[index];
|
||||
var distance = Vec3.subtract(originalPosition, currentPosition);
|
||||
|
@ -117,8 +118,8 @@ function testBallDistanceFromStart() {
|
|||
if (moving < MINIMUM_MOVE_LENGTH) {
|
||||
resetCount++;
|
||||
if (resetCount === NUMBER_OF_BALLS) {
|
||||
deleteCollidingBalls();
|
||||
createCollidingBalls();
|
||||
deleteBalls();
|
||||
createBalls();
|
||||
}
|
||||
}
|
||||
}, 200)
|
||||
|
@ -128,19 +129,19 @@ function testBallDistanceFromStart() {
|
|||
|
||||
function deleteEntity(entityID) {
|
||||
if (entityID === rack) {
|
||||
deleteCollidingBalls();
|
||||
deleteBalls();
|
||||
Script.clearInterval(distanceCheckInterval);
|
||||
Entities.deletingEntity.disconnect(deleteEntity);
|
||||
}
|
||||
}
|
||||
|
||||
function deleteCollidingBalls() {
|
||||
while (collidingBalls.length > 0) {
|
||||
Entities.deleteEntity(collidingBalls.pop());
|
||||
function deleteBalls() {
|
||||
while (balls.length > 0) {
|
||||
Entities.deleteEntity(balls.pop());
|
||||
}
|
||||
}
|
||||
|
||||
createCollidingBalls();
|
||||
createBalls();
|
||||
Entities.deletingEntity.connect(deleteEntity);
|
||||
|
||||
var distanceCheckInterval = Script.setInterval(testBallDistanceFromStart, 1000);
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
(function () {
|
||||
var _this;
|
||||
var utilitiesScript = Script.resolvePath("../libraries/utils.js");
|
||||
var utilitiesScript = Script.resolvePath("../../libraries/utils.js");
|
||||
Script.include(utilitiesScript);
|
||||
LightSwitch = function () {
|
||||
_this = this;
|
|
@ -13,7 +13,7 @@
|
|||
// Script.include("../libraries/utils.js");
|
||||
//Need absolute path for now, for testing before PR merge and s3 cloning. Will change post-merge
|
||||
|
||||
Script.include("../libraries/utils.js");
|
||||
Script.include("../../libraries/utils.js");
|
||||
|
||||
this.spraySound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/sprayPaintSound.wav");
|
||||
|
|
@ -245,6 +245,8 @@ QByteArray AvatarActionHold::serialize() const {
|
|||
|
||||
dataStream << _expires + getEntityServerClockSkew();
|
||||
dataStream << _tag;
|
||||
dataStream << _kinematic;
|
||||
dataStream << _kinematicSetVelocity;
|
||||
});
|
||||
|
||||
return serializedActionArguments;
|
||||
|
@ -278,6 +280,8 @@ void AvatarActionHold::deserialize(QByteArray serializedArguments) {
|
|||
dataStream >> _expires;
|
||||
_expires -= getEntityServerClockSkew();
|
||||
dataStream >> _tag;
|
||||
dataStream >> _kinematic;
|
||||
dataStream >> _kinematicSetVelocity;
|
||||
|
||||
#if WANT_DEBUG
|
||||
qDebug() << "deserialize AvatarActionHold: " << _holderID
|
||||
|
|
|
@ -482,7 +482,7 @@ void EntityTreeRenderer::deleteReleasedModels() {
|
|||
}
|
||||
|
||||
RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
|
||||
bool precisionPicking, const QVector<QUuid>& entityIdsToInclude) {
|
||||
bool precisionPicking, const QVector<EntityItemID>& entityIdsToInclude) {
|
||||
RayToEntityIntersectionResult result;
|
||||
if (_tree) {
|
||||
EntityTreePointer entityTree = std::static_pointer_cast<EntityTree>(_tree);
|
||||
|
|
|
@ -130,7 +130,7 @@ private:
|
|||
|
||||
QList<Model*> _releasedModels;
|
||||
RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
|
||||
bool precisionPicking, const QVector<QUuid>& entityIdsToInclude = QVector<QUuid>());
|
||||
bool precisionPicking, const QVector<EntityItemID>& entityIdsToInclude = QVector<EntityItemID>());
|
||||
|
||||
EntityItemID _currentHoverOverEntityID;
|
||||
EntityItemID _currentClickingOnEntityID;
|
||||
|
|
|
@ -52,3 +52,19 @@ QScriptValue EntityItemIDtoScriptValue(QScriptEngine* engine, const EntityItemID
|
|||
void EntityItemIDfromScriptValue(const QScriptValue &object, EntityItemID& id) {
|
||||
quuidFromScriptValue(object, id);
|
||||
}
|
||||
|
||||
QVector<EntityItemID> qVectorEntityItemIDFromScriptValue(const QScriptValue& array) {
|
||||
if (!array.isArray()) {
|
||||
return QVector<EntityItemID>();
|
||||
}
|
||||
QVector<EntityItemID> newVector;
|
||||
int length = array.property("length").toInteger();
|
||||
newVector.reserve(length);
|
||||
for (int i = 0; i < length; i++) {
|
||||
QString uuidAsString = array.property(i).toString();
|
||||
EntityItemID fromString(uuidAsString);
|
||||
newVector << fromString;
|
||||
}
|
||||
return newVector;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,5 +43,6 @@ Q_DECLARE_METATYPE(EntityItemID);
|
|||
Q_DECLARE_METATYPE(QVector<EntityItemID>);
|
||||
QScriptValue EntityItemIDtoScriptValue(QScriptEngine* engine, const EntityItemID& properties);
|
||||
void EntityItemIDfromScriptValue(const QScriptValue &object, EntityItemID& properties);
|
||||
QVector<EntityItemID> qVectorEntityItemIDFromScriptValue(const QScriptValue& array);
|
||||
|
||||
#endif // hifi_EntityItemID_h
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
// There is a minor performance gain when comparing/copying an existing glm::vec3 rather than
|
||||
// creating a new one on the stack so we declare the ZERO_VEC3 constant as an optimization.
|
||||
const glm::vec3 ENTITY_ITEM_ZERO_VEC3 = glm::vec3(0.0f);
|
||||
const glm::vec3 ENTITY_ITEM_ONE_VEC3 = glm::vec3(1.0f, 1.0f, 1.0f);
|
||||
const glm::vec3 ENTITY_ITEM_HALF_VEC3 = ENTITY_ITEM_ONE_VEC3 / 2.0f;
|
||||
const glm::vec3 ENTITY_ITEM_ONE_VEC3 = glm::vec3(1.0f);
|
||||
const glm::vec3 ENTITY_ITEM_HALF_VEC3 = glm::vec3(0.5f);
|
||||
|
||||
const bool ENTITY_ITEM_DEFAULT_LOCKED = false;
|
||||
const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString("");
|
||||
|
|
|
@ -280,18 +280,18 @@ QVector<QUuid> EntityScriptingInterface::findEntitiesInBox(const glm::vec3& corn
|
|||
}
|
||||
|
||||
RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking, const QScriptValue& entityIdsToInclude) {
|
||||
QVector<QUuid> entities = qVectorQUuidFromScriptValue(entityIdsToInclude);
|
||||
QVector<EntityItemID> entities = qVectorEntityItemIDFromScriptValue(entityIdsToInclude);
|
||||
return findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking, entities);
|
||||
}
|
||||
|
||||
RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking, const QScriptValue& entityIdsToInclude) {
|
||||
const QVector<QUuid>& entities = qVectorQUuidFromScriptValue(entityIdsToInclude);
|
||||
const QVector<EntityItemID>& entities = qVectorEntityItemIDFromScriptValue(entityIdsToInclude);
|
||||
return findRayIntersectionWorker(ray, Octree::Lock, precisionPicking, entities);
|
||||
}
|
||||
|
||||
RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionWorker(const PickRay& ray,
|
||||
Octree::lockType lockType,
|
||||
bool precisionPicking, const QVector<QUuid>& entityIdsToInclude) {
|
||||
bool precisionPicking, const QVector<EntityItemID>& entityIdsToInclude) {
|
||||
|
||||
|
||||
RayToEntityIntersectionResult result;
|
||||
|
|
|
@ -186,7 +186,7 @@ private:
|
|||
|
||||
/// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode
|
||||
RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
|
||||
bool precisionPicking, const QVector<QUuid>& entityIdsToInclude);
|
||||
bool precisionPicking, const QVector<EntityItemID>& entityIdsToInclude);
|
||||
|
||||
EntityTreePointer _entityTree;
|
||||
EntitiesScriptEngineProvider* _entitiesScriptEngine = nullptr;
|
||||
|
|
|
@ -448,6 +448,53 @@ bool EntityTree::findNearPointOperation(OctreeElementPointer element, void* extr
|
|||
// if this element doesn't contain the point, then none of its children can contain the point, so stop searching
|
||||
return false;
|
||||
}
|
||||
// combines the ray cast arguments into a single object
|
||||
class RayArgs {
|
||||
public:
|
||||
glm::vec3 origin;
|
||||
glm::vec3 direction;
|
||||
OctreeElementPointer& element;
|
||||
float& distance;
|
||||
BoxFace& face;
|
||||
glm::vec3& surfaceNormal;
|
||||
const QVector<EntityItemID>& entityIdsToInclude;
|
||||
void** intersectedObject;
|
||||
bool found;
|
||||
bool precisionPicking;
|
||||
};
|
||||
|
||||
|
||||
bool findRayIntersectionOp(OctreeElementPointer element, void* extraData) {
|
||||
RayArgs* args = static_cast<RayArgs*>(extraData);
|
||||
bool keepSearching = true;
|
||||
EntityTreeElementPointer entityTreeElementPointer = std::dynamic_pointer_cast<EntityTreeElement>(element);
|
||||
if (entityTreeElementPointer ->findRayIntersection(args->origin, args->direction, keepSearching,
|
||||
args->element, args->distance, args->face, args->surfaceNormal, args->entityIdsToInclude,
|
||||
args->intersectedObject, args->precisionPicking)) {
|
||||
args->found = true;
|
||||
}
|
||||
return keepSearching;
|
||||
}
|
||||
|
||||
bool EntityTree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<EntityItemID>& entityIdsToInclude, void** intersectedObject,
|
||||
Octree::lockType lockType, bool* accurateResult, bool precisionPicking) {
|
||||
RayArgs args = { origin, direction, element, distance, face, surfaceNormal, entityIdsToInclude, intersectedObject, false, precisionPicking };
|
||||
distance = FLT_MAX;
|
||||
|
||||
bool requireLock = lockType == Octree::Lock;
|
||||
bool lockResult = withReadLock([&]{
|
||||
recurseTreeWithOperation(findRayIntersectionOp, &args);
|
||||
}, requireLock);
|
||||
|
||||
if (accurateResult) {
|
||||
*accurateResult = lockResult; // if user asked to accuracy or result, let them know this is accurate
|
||||
}
|
||||
|
||||
return args.found;
|
||||
}
|
||||
|
||||
|
||||
EntityItemPointer EntityTree::findClosestEntity(glm::vec3 position, float targetRadius) {
|
||||
FindNearPointArgs args = { position, targetRadius, false, NULL, FLT_MAX };
|
||||
|
|
|
@ -80,6 +80,14 @@ public:
|
|||
virtual int processEditPacketData(NLPacket& packet, const unsigned char* editData, int maxLength,
|
||||
const SharedNodePointer& senderNode);
|
||||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& node, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const QVector<EntityItemID>& entityIdsToInclude = QVector<EntityItemID>(),
|
||||
void** intersectedObject = NULL,
|
||||
Octree::lockType lockType = Octree::TryLock,
|
||||
bool* accurateResult = NULL,
|
||||
bool precisionPicking = false);
|
||||
|
||||
virtual bool rootElementHasData() const { return true; }
|
||||
|
||||
// the root at least needs to store the number of entities in the packet/buffer
|
||||
|
|
|
@ -493,9 +493,50 @@ bool EntityTreeElement::bestFitBounds(const glm::vec3& minPoint, const glm::vec3
|
|||
return false;
|
||||
}
|
||||
|
||||
bool EntityTreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<EntityItemID>& entityIdsToInclude,
|
||||
void** intersectedObject, bool precisionPicking) {
|
||||
|
||||
keepSearching = true; // assume that we will continue searching after this.
|
||||
|
||||
float distanceToElementCube = std::numeric_limits<float>::max();
|
||||
float distanceToElementDetails = distance;
|
||||
BoxFace localFace;
|
||||
glm::vec3 localSurfaceNormal;
|
||||
|
||||
// if the ray doesn't intersect with our cube, we can stop searching!
|
||||
if (!_cube.findRayIntersection(origin, direction, distanceToElementCube, localFace, localSurfaceNormal)) {
|
||||
keepSearching = false; // no point in continuing to search
|
||||
return false; // we did not intersect
|
||||
}
|
||||
|
||||
// by default, we only allow intersections with leaves with content
|
||||
if (!canRayIntersect()) {
|
||||
return false; // we don't intersect with non-leaves, and we keep searching
|
||||
}
|
||||
|
||||
// if the distance to the element cube is not less than the current best distance, then it's not possible
|
||||
// for any details inside the cube to be closer so we don't need to consider them.
|
||||
if (_cube.contains(origin) || distanceToElementCube < distance) {
|
||||
|
||||
if (findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails,
|
||||
face, localSurfaceNormal, entityIdsToInclude, intersectedObject, precisionPicking, distanceToElementCube)) {
|
||||
|
||||
if (distanceToElementDetails < distance) {
|
||||
distance = distanceToElementDetails;
|
||||
face = localFace;
|
||||
surfaceNormal = localSurfaceNormal;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching,
|
||||
OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const QVector<QUuid>& entityIdsToInclude, void** intersectedObject, bool precisionPicking, float distanceToElementCube) {
|
||||
const QVector<EntityItemID>& entityIdsToInclude, void** intersectedObject, bool precisionPicking, float distanceToElementCube) {
|
||||
|
||||
// only called if we do intersect our bounding cube, but find if we actually intersect with entities...
|
||||
int entityNumber = 0;
|
||||
|
@ -607,27 +648,99 @@ EntityItemPointer EntityTreeElement::getClosestEntity(glm::vec3 position) const
|
|||
|
||||
// TODO: change this to use better bounding shape for entity than sphere
|
||||
void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searchRadius, QVector<EntityItemPointer>& foundEntities) const {
|
||||
float compareRadius = searchRadius * searchRadius;
|
||||
forEachEntity([&](EntityItemPointer entity) {
|
||||
// For iteration like this, avoid the use of square roots by comparing distances squared
|
||||
float distanceSquared = glm::length2(entity->getPosition() - searchPosition);
|
||||
float otherRadius = entity->getRadius();
|
||||
if (distanceSquared < (compareRadius + (otherRadius * otherRadius))) {
|
||||
|
||||
AABox entityBox = entity->getAABox();
|
||||
|
||||
// if the sphere doesn't intersect with our world frame AABox, we don't need to consider the more complex case
|
||||
glm::vec3 penetration;
|
||||
if (entityBox.findSpherePenetration(searchPosition, searchRadius, penetration)) {
|
||||
|
||||
glm::vec3 dimensions = entity->getDimensions();
|
||||
|
||||
// FIXME - consider allowing the entity to determine penetration so that
|
||||
// entities could presumably dull actuall hull testing if they wanted to
|
||||
// FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better in particular
|
||||
// can we handle the ellipsoid case better? We only currently handle perfect spheres
|
||||
// with centered registration points
|
||||
if (entity->getShapeType() == SHAPE_TYPE_SPHERE &&
|
||||
(dimensions.x == dimensions.y && dimensions.y == dimensions.z)) {
|
||||
|
||||
// NOTE: entity->getRadius() doesn't return the true radius, it returns the radius of the
|
||||
// maximum bounding sphere, which is actually larger than our actual radius
|
||||
float entityTrueRadius = dimensions.x / 2.0f;
|
||||
|
||||
if (findSphereSpherePenetration(searchPosition, searchRadius,
|
||||
entity->getCenterPosition(), entityTrueRadius, penetration)) {
|
||||
foundEntities.push_back(entity);
|
||||
}
|
||||
} else {
|
||||
// determine the worldToEntityMatrix that doesn't include scale because
|
||||
// we're going to use the registration aware aa box in the entity frame
|
||||
glm::mat4 rotation = glm::mat4_cast(entity->getRotation());
|
||||
glm::mat4 translation = glm::translate(entity->getPosition());
|
||||
glm::mat4 entityToWorldMatrix = translation * rotation;
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
|
||||
glm::vec3 registrationPoint = entity->getRegistrationPoint();
|
||||
glm::vec3 corner = -(dimensions * registrationPoint);
|
||||
|
||||
AABox entityFrameBox(corner, dimensions);
|
||||
|
||||
glm::vec3 entityFrameSearchPosition = glm::vec3(worldToEntityMatrix * glm::vec4(searchPosition, 1.0f));
|
||||
if (entityFrameBox.findSpherePenetration(entityFrameSearchPosition, searchRadius, penetration)) {
|
||||
foundEntities.push_back(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void EntityTreeElement::getEntities(const AACube& cube, QVector<EntityItemPointer>& foundEntities) {
|
||||
forEachEntity([&](EntityItemPointer entity) {
|
||||
AABox entityBox = entity->getAABox();
|
||||
// FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better
|
||||
// FIXME - consider allowing the entity to determine penetration so that
|
||||
// entities could presumably dull actuall hull testing if they wanted to
|
||||
// FIXME - is there an easy way to translate the search cube into something in the
|
||||
// entity frame that can be easily tested against?
|
||||
// simple algorithm is probably:
|
||||
// if target box is fully inside search box == yes
|
||||
// if search box is fully inside target box == yes
|
||||
// for each face of search box:
|
||||
// translate the triangles of the face into the box frame
|
||||
// test the triangles of the face against the box?
|
||||
// if translated search face triangle intersect target box
|
||||
// add to result
|
||||
//
|
||||
|
||||
// If the entities AABox touches the search cube then consider it to be found
|
||||
if (entityBox.touches(cube)) {
|
||||
foundEntities.push_back(entity);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: change this to use better bounding shape for entity than sphere
|
||||
void EntityTreeElement::getEntities(const AACube& box, QVector<EntityItemPointer>& foundEntities) {
|
||||
AACube entityCube;
|
||||
void EntityTreeElement::getEntities(const AABox& box, QVector<EntityItemPointer>& foundEntities) {
|
||||
forEachEntity([&](EntityItemPointer entity) {
|
||||
float radius = entity->getRadius();
|
||||
// NOTE: we actually do cube-cube collision queries here, which is sloppy but good enough for now
|
||||
// TODO: decide whether to replace entityCube-cube query with sphere-cube (requires a square root
|
||||
// but will be slightly more accurate).
|
||||
entityCube.setBox(entity->getPosition() - glm::vec3(radius), 2.0f * radius);
|
||||
if (entityCube.touches(box)) {
|
||||
AABox entityBox = entity->getAABox();
|
||||
// FIXME - handle entity->getShapeType() == SHAPE_TYPE_SPHERE case better
|
||||
// FIXME - consider allowing the entity to determine penetration so that
|
||||
// entities could presumably dull actuall hull testing if they wanted to
|
||||
// FIXME - is there an easy way to translate the search cube into something in the
|
||||
// entity frame that can be easily tested against?
|
||||
// simple algorithm is probably:
|
||||
// if target box is fully inside search box == yes
|
||||
// if search box is fully inside target box == yes
|
||||
// for each face of search box:
|
||||
// translate the triangles of the face into the box frame
|
||||
// test the triangles of the face against the box?
|
||||
// if translated search face triangle intersect target box
|
||||
// add to result
|
||||
//
|
||||
|
||||
// If the entities AABox touches the search cube then consider it to be found
|
||||
if (entityBox.touches(box)) {
|
||||
foundEntities.push_back(entity);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -142,11 +142,14 @@ public:
|
|||
virtual bool deleteApproved() const { return !hasEntities(); }
|
||||
|
||||
virtual bool canRayIntersect() const { return hasEntities(); }
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& node, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<EntityItemID>& entityIdsToInclude,
|
||||
void** intersectedObject = NULL, bool precisionPicking = false);
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<QUuid>& entityIdsToInclude,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<EntityItemID>& entityIdsToInclude,
|
||||
void** intersectedObject, bool precisionPicking, float distanceToElementCube);
|
||||
|
||||
virtual bool findSpherePenetration(const glm::vec3& center, float radius,
|
||||
glm::vec3& penetration, void** penetratedObject) const;
|
||||
|
||||
|
@ -180,7 +183,12 @@ public:
|
|||
/// finds all entities that touch a box
|
||||
/// \param box the query box
|
||||
/// \param entities[out] vector of non-const EntityItemPointer
|
||||
void getEntities(const AACube& box, QVector<EntityItemPointer>& foundEntities);
|
||||
void getEntities(const AACube& cube, QVector<EntityItemPointer>& foundEntities);
|
||||
|
||||
/// finds all entities that touch a box
|
||||
/// \param box the query box
|
||||
/// \param entities[out] vector of non-const EntityItemPointer
|
||||
void getEntities(const AABox& box, QVector<EntityItemPointer>& foundEntities);
|
||||
|
||||
EntityItemPointer getEntityWithID(uint32_t id) const;
|
||||
EntityItemPointer getEntityWithEntityItemID(const EntityItemID& id) const;
|
||||
|
|
|
@ -108,7 +108,7 @@ bool PolyLineEntityItem::setStrokeWidths(const QVector<float>& strokeWidths) {
|
|||
|
||||
bool PolyLineEntityItem::setNormals(const QVector<glm::vec3>& normals) {
|
||||
_normals = normals;
|
||||
if (_points.size() < 2 || _normals.size() < 2) {
|
||||
if (_points.size() < 2 || _normals.size() < 2 || _strokeWidths.size() < 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,8 @@ bool PolyLineEntityItem::setNormals(const QVector<glm::vec3>& normals) {
|
|||
_vertices.clear();
|
||||
glm::vec3 v1, v2, tangent, binormal, point;
|
||||
|
||||
for (int i = 0; i < minVectorSize - 1; i++) {
|
||||
int finalIndex = minVectorSize -1;
|
||||
for (int i = 0; i < finalIndex; i++) {
|
||||
float width = _strokeWidths.at(i);
|
||||
point = _points.at(i);
|
||||
|
||||
|
@ -138,7 +139,7 @@ bool PolyLineEntityItem::setNormals(const QVector<glm::vec3>& normals) {
|
|||
_vertices << v1 << v2;
|
||||
}
|
||||
//for last point we can just assume binormals are same since it represents last two vertices of quad
|
||||
point = _points.at(minVectorSize - 1);
|
||||
point = _points.at(finalIndex);
|
||||
v1 = point + binormal;
|
||||
v2 = point - binormal;
|
||||
_vertices << v1 << v2;
|
||||
|
|
|
@ -694,50 +694,7 @@ OctreeElementPointer Octree::getOrCreateChildElementContaining(const AACube& box
|
|||
return getRoot()->getOrCreateChildElementContaining(box);
|
||||
}
|
||||
|
||||
// combines the ray cast arguments into a single object
|
||||
class RayArgs {
|
||||
public:
|
||||
glm::vec3 origin;
|
||||
glm::vec3 direction;
|
||||
OctreeElementPointer& element;
|
||||
float& distance;
|
||||
BoxFace& face;
|
||||
glm::vec3& surfaceNormal;
|
||||
const QVector<QUuid>& entityIdsToInclude;
|
||||
void** intersectedObject;
|
||||
bool found;
|
||||
bool precisionPicking;
|
||||
};
|
||||
|
||||
bool findRayIntersectionOp(OctreeElementPointer element, void* extraData) {
|
||||
RayArgs* args = static_cast<RayArgs*>(extraData);
|
||||
bool keepSearching = true;
|
||||
if (element->findRayIntersection(args->origin, args->direction, keepSearching,
|
||||
args->element, args->distance, args->face, args->surfaceNormal, args->entityIdsToInclude,
|
||||
args->intersectedObject, args->precisionPicking)) {
|
||||
args->found = true;
|
||||
}
|
||||
return keepSearching;
|
||||
}
|
||||
|
||||
bool Octree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<QUuid>& entityIdsToInclude, void** intersectedObject,
|
||||
Octree::lockType lockType, bool* accurateResult, bool precisionPicking) {
|
||||
RayArgs args = { origin, direction, element, distance, face, surfaceNormal, entityIdsToInclude, intersectedObject, false, precisionPicking};
|
||||
distance = FLT_MAX;
|
||||
|
||||
bool requireLock = lockType == Octree::Lock;
|
||||
bool lockResult = withReadLock([&]{
|
||||
recurseTreeWithOperation(findRayIntersectionOp, &args);
|
||||
}, requireLock);
|
||||
|
||||
if (accurateResult) {
|
||||
*accurateResult = lockResult; // if user asked to accuracy or result, let them know this is accurate
|
||||
}
|
||||
|
||||
return args.found;
|
||||
}
|
||||
|
||||
class SphereArgs {
|
||||
public:
|
||||
|
|
|
@ -298,13 +298,6 @@ public:
|
|||
TryLock
|
||||
} lockType;
|
||||
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
OctreeElementPointer& node, float& distance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
const QVector<QUuid>& entityIdsToInclude = QVector<QUuid>(),
|
||||
void** intersectedObject = NULL,
|
||||
Octree::lockType lockType = Octree::TryLock,
|
||||
bool* accurateResult = NULL,
|
||||
bool precisionPicking = false);
|
||||
|
||||
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject = NULL,
|
||||
Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL);
|
||||
|
|
|
@ -573,64 +573,6 @@ void OctreeElement::notifyUpdateHooks() {
|
|||
}
|
||||
}
|
||||
|
||||
bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<QUuid>& entityIdsToInclude,
|
||||
void** intersectedObject, bool precisionPicking) {
|
||||
|
||||
keepSearching = true; // assume that we will continue searching after this.
|
||||
|
||||
float distanceToElementCube = std::numeric_limits<float>::max();
|
||||
float distanceToElementDetails = distance;
|
||||
BoxFace localFace;
|
||||
glm::vec3 localSurfaceNormal;
|
||||
|
||||
// if the ray doesn't intersect with our cube, we can stop searching!
|
||||
if (!_cube.findRayIntersection(origin, direction, distanceToElementCube, localFace, localSurfaceNormal)) {
|
||||
keepSearching = false; // no point in continuing to search
|
||||
return false; // we did not intersect
|
||||
}
|
||||
|
||||
// by default, we only allow intersections with leaves with content
|
||||
if (!canRayIntersect()) {
|
||||
return false; // we don't intersect with non-leaves, and we keep searching
|
||||
}
|
||||
|
||||
// if the distance to the element cube is not less than the current best distance, then it's not possible
|
||||
// for any details inside the cube to be closer so we don't need to consider them.
|
||||
if (_cube.contains(origin) || distanceToElementCube < distance) {
|
||||
|
||||
if (findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails,
|
||||
face, localSurfaceNormal, entityIdsToInclude, intersectedObject, precisionPicking, distanceToElementCube)) {
|
||||
|
||||
if (distanceToElementDetails < distance) {
|
||||
distance = distanceToElementDetails;
|
||||
face = localFace;
|
||||
surfaceNormal = localSurfaceNormal;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<QUuid>& entityIdsToInclude,
|
||||
void** intersectedObject, bool precisionPicking, float distanceToElementCube) {
|
||||
|
||||
// we did hit this element, so calculate appropriate distances
|
||||
if (hasContent()) {
|
||||
element = shared_from_this();
|
||||
distance = distanceToElementCube;
|
||||
if (intersectedObject) {
|
||||
*intersectedObject = this;
|
||||
}
|
||||
keepSearching = false;
|
||||
return true; // we did intersect
|
||||
}
|
||||
return false; // we did not intersect
|
||||
}
|
||||
|
||||
bool OctreeElement::findSpherePenetration(const glm::vec3& center, float radius,
|
||||
glm::vec3& penetration, void** penetratedObject) const {
|
||||
|
|
|
@ -118,16 +118,6 @@ public:
|
|||
virtual bool deleteApproved() const { return true; }
|
||||
|
||||
virtual bool canRayIntersect() const { return isLeaf(); }
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& node, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<QUuid>& entityIdsToInclude,
|
||||
void** intersectedObject = NULL, bool precisionPicking = false);
|
||||
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<QUuid>& entityIdsToInclude,
|
||||
void** intersectedObject, bool precisionPicking, float distanceToElementCube);
|
||||
|
||||
/// \param center center of sphere in meters
|
||||
/// \param radius radius of sphere in meters
|
||||
/// \param[out] penetration pointing into cube from sphere
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <QUrl>
|
||||
#include <QUuid>
|
||||
#include <QRect>
|
||||
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include "RegisteredMetaTypes.h"
|
||||
|
|
|
@ -14,14 +14,15 @@
|
|||
|
||||
var _this;
|
||||
|
||||
var sprayPaintScriptURL = Script.resolvePath("../examples/toys/sprayPaintCan.js");
|
||||
var catScriptURL = Script.resolvePath("../examples/toys/cat.js");
|
||||
var flashlightScriptURL = Script.resolvePath('../examples/toys/flashlight/flashlight.js');
|
||||
var pingPongScriptURL = Script.resolvePath('../examples/toys/ping_pong_gun/pingPongGun.js');
|
||||
var wandScriptURL = Script.resolvePath("../examples/toys/bubblewand/wand.js");
|
||||
var dollScriptURL = Script.resolvePath("../examples/toys/doll/doll.js");
|
||||
var lightsScriptURL = Script.resolvePath("../examples/toys/lightSwitch.js");
|
||||
var targetsScriptURL = Script.resolvePath('../examples/toys/ping_pong_gun/wallTarget.js');
|
||||
var sprayPaintScriptURL = Script.resolvePath("../examples/toybox/spray_paint/sprayPaintCan.js");
|
||||
var catScriptURL = Script.resolvePath("../examples/toybox/cat/cat.js");
|
||||
var flashlightScriptURL = Script.resolvePath('../examples/toybox/flashlight/flashlight.js');
|
||||
var pingPongScriptURL = Script.resolvePath('../examples/toybox/ping_pong_gun/pingPongGun.js');
|
||||
var wandScriptURL = Script.resolvePath("../examples/toybox/bubblewand/wand.js");
|
||||
var dollScriptURL = Script.resolvePath("../examples/toybox/doll/doll.js");
|
||||
var lightsScriptURL = Script.resolvePath("../examples/toybox/lights/lightSwitch.js");
|
||||
var targetsScriptURL = Script.resolvePath('../examples/toybox/ping_pong_gun/wallTarget.js');
|
||||
|
||||
|
||||
ResetSwitch = function() {
|
||||
_this = this;
|
||||
|
@ -54,7 +55,6 @@
|
|||
|
||||
MasterReset = function() {
|
||||
var resetKey = "resetMe";
|
||||
var GRABBABLE_DATA_KEY = "grabbableKey";
|
||||
|
||||
var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
|
||||
|
@ -97,8 +97,6 @@
|
|||
z: 505.78
|
||||
});
|
||||
|
||||
|
||||
|
||||
createCombinedArmChair({
|
||||
x: 549.29,
|
||||
y: 494.9,
|
||||
|
@ -321,7 +319,7 @@
|
|||
resetMe: {
|
||||
resetMe: true
|
||||
},
|
||||
grabbable: {
|
||||
grabbableKey: {
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
|
@ -487,7 +485,6 @@
|
|||
grabbableKey: {
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
|
||||
})
|
||||
});
|
||||
|
||||
|
@ -533,6 +530,9 @@
|
|||
resetMe: true,
|
||||
on: true,
|
||||
type: "Hall Light"
|
||||
},
|
||||
grabbableKey: {
|
||||
wantsTrigger: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
@ -628,6 +628,9 @@
|
|||
resetMe: true,
|
||||
on: true,
|
||||
type: "Garage Light"
|
||||
},
|
||||
grabbableKey: {
|
||||
wantsTrigger: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
@ -759,6 +762,7 @@
|
|||
grabbableKey: {
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
|
||||
})
|
||||
};
|
||||
var dice1 = Entities.addEntity(diceProps);
|
||||
|
@ -851,6 +855,7 @@
|
|||
grabbableKey: {
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
|
||||
})
|
||||
});
|
||||
}
|
||||
|
@ -1176,7 +1181,7 @@
|
|||
y: 0.05,
|
||||
z: 0.25
|
||||
}
|
||||
} ];
|
||||
}];
|
||||
|
||||
var modelURL, entity;
|
||||
for (i = 0; i < blockTypes.length; i++) {
|
||||
|
|
|
@ -14,20 +14,19 @@
|
|||
var utilitiesScript = Script.resolvePath("../examples/libraries/utils.js");
|
||||
Script.include(utilitiesScript);
|
||||
|
||||
var sprayPaintScriptURL = Script.resolvePath("../examples/toys/sprayPaintCan.js");
|
||||
var catScriptURL = Script.resolvePath("../examples/toys/cat.js");
|
||||
var flashlightScriptURL = Script.resolvePath('../examples/toys/flashlight/flashlight.js');
|
||||
var pingPongScriptURL = Script.resolvePath('../examples/toys/ping_pong_gun/pingPongGun.js');
|
||||
var wandScriptURL = Script.resolvePath("../examples/toys/bubblewand/wand.js");
|
||||
var dollScriptURL = Script.resolvePath("../examples/toys/doll/doll.js");
|
||||
var lightsScriptURL = Script.resolvePath("../examples/toys/lightSwitch.js");
|
||||
var targetsScriptURL = Script.resolvePath('../examples/toys/ping_pong_gun/wallTarget.js');
|
||||
var sprayPaintScriptURL = Script.resolvePath("../examples/toybox/spray_paint/sprayPaintCan.js");
|
||||
var catScriptURL = Script.resolvePath("../examples/toybox/cat/cat.js");
|
||||
var flashlightScriptURL = Script.resolvePath('../examples/toybox/flashlight/flashlight.js');
|
||||
var pingPongScriptURL = Script.resolvePath('../examples/toybox/ping_pong_gun/pingPongGun.js');
|
||||
var wandScriptURL = Script.resolvePath("../examples/toybox/bubblewand/wand.js");
|
||||
var dollScriptURL = Script.resolvePath("../examples/toybox/doll/doll.js");
|
||||
var lightsScriptURL = Script.resolvePath("../examples/toybox/lights/lightSwitch.js");
|
||||
var targetsScriptURL = Script.resolvePath('../examples/toybox/ping_pong_gun/wallTarget.js');
|
||||
|
||||
|
||||
|
||||
MasterReset = function() {
|
||||
var resetKey = "resetMe";
|
||||
var GRABBABLE_DATA_KEY = "grabbableKey";
|
||||
|
||||
var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
|
||||
|
@ -294,7 +293,7 @@ MasterReset = function() {
|
|||
resetMe: {
|
||||
resetMe: true
|
||||
},
|
||||
grabbable: {
|
||||
grabbableKey: {
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
|
@ -505,6 +504,9 @@ MasterReset = function() {
|
|||
resetMe: true,
|
||||
on: true,
|
||||
type: "Hall Light"
|
||||
},
|
||||
grabbableKey: {
|
||||
wantsTrigger: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
@ -600,6 +602,9 @@ MasterReset = function() {
|
|||
resetMe: true,
|
||||
on: true,
|
||||
type: "Garage Light"
|
||||
},
|
||||
grabbableKey: {
|
||||
wantsTrigger: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue