mirror of
https://github.com/lubosz/overte.git
synced 2025-08-27 11:46:18 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into hdr
This commit is contained in:
commit
8dba66fb14
31 changed files with 4201 additions and 1195 deletions
54
examples/controllers/getHUDLookAtPositionTest.js
Normal file
54
examples/controllers/getHUDLookAtPositionTest.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// getHUDLookAtPositionTest.js
|
||||
// examples/controllers
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2015/12/15
|
||||
// Copyright 2015 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
|
||||
//
|
||||
|
||||
|
||||
// This script demonstrates the testing of the HMD.getHUDLookAtPosition--() functions.
|
||||
// If these functions are working correctly, we'd expect to see a 3D cube and a 2D square
|
||||
// follow around the center of the HMD view.
|
||||
|
||||
var cubePosition = { x: 0, y: 0, z: 0 };
|
||||
var cubeSize = 0.03;
|
||||
var cube = Overlays.addOverlay("cube", {
|
||||
position: cubePosition,
|
||||
size: cubeSize,
|
||||
color: { red: 255, green: 0, blue: 0},
|
||||
alpha: 1,
|
||||
solid: false
|
||||
});
|
||||
|
||||
var square = Overlays.addOverlay("text", {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 20,
|
||||
height: 20,
|
||||
color: { red: 255, green: 255, blue: 0},
|
||||
backgroundColor: { red: 255, green: 255, blue: 0},
|
||||
alpha: 1
|
||||
});
|
||||
|
||||
|
||||
Script.update.connect(function(deltaTime) {
|
||||
if (!HMD.active) {
|
||||
return;
|
||||
}
|
||||
var lookAt3D = HMD.getHUDLookAtPosition3D();
|
||||
Overlays.editOverlay(cube, { position: lookAt3D });
|
||||
|
||||
var lookAt2D = HMD.getHUDLookAtPosition2D();
|
||||
Overlays.editOverlay(square, { x: lookAt2D.x, y: lookAt2D.y });
|
||||
});
|
||||
|
||||
Script.scriptEnding.connect(function(){
|
||||
Overlays.deleteOverlay(cube);
|
||||
Overlays.deleteOverlay(square);
|
||||
});
|
||||
|
||||
|
|
@ -116,6 +116,11 @@ var DEFAULT_GRABBABLE_DATA = {
|
|||
invertSolidWhileHeld: false
|
||||
};
|
||||
|
||||
|
||||
// sometimes we want to exclude objects from being picked
|
||||
var USE_BLACKLIST = true;
|
||||
var blacklist = [];
|
||||
|
||||
//we've created various ways of visualizing looking for and moving distant objects
|
||||
var USE_ENTITY_LINES_FOR_SEARCHING = false;
|
||||
var USE_OVERLAY_LINES_FOR_SEARCHING = false;
|
||||
|
@ -226,6 +231,9 @@ function getSpatialOffsetPosition(hand, spatialKey) {
|
|||
position = spatialKey.relativePosition;
|
||||
}
|
||||
|
||||
// add the relative hand center offset
|
||||
var handSizeRatio = calculateHandSizeRatio();
|
||||
position = Vec3.multiply(position, handSizeRatio);
|
||||
return position;
|
||||
}
|
||||
|
||||
|
@ -277,12 +285,12 @@ function MyController(hand) {
|
|||
//for visualizations
|
||||
this.overlayLine = null;
|
||||
this.particleBeam = null;
|
||||
|
||||
|
||||
//for lights
|
||||
this.spotlight = null;
|
||||
this.pointlight = null;
|
||||
this.overlayLine = null;
|
||||
|
||||
|
||||
this.ignoreIK = false;
|
||||
this.offsetPosition = Vec3.ZERO;
|
||||
this.offsetRotation = Quat.IDENTITY;
|
||||
|
@ -387,7 +395,7 @@ function MyController(hand) {
|
|||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
grabbable: false
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
} else {
|
||||
|
@ -444,7 +452,7 @@ function MyController(hand) {
|
|||
this.createParticleBeam(position, finalRotation, color, speed, spread, lifespan);
|
||||
} else {
|
||||
this.updateParticleBeam(position, finalRotation, color, speed, spread, lifespan);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.handleDistantParticleBeam = function(handPosition, objectPosition, color) {
|
||||
|
@ -532,12 +540,12 @@ function MyController(hand) {
|
|||
Entities.editEntity(this.particleBeam, {
|
||||
rotation: orientation,
|
||||
position: position,
|
||||
visible: true,
|
||||
color: color,
|
||||
visible: true,
|
||||
color: color,
|
||||
emitSpeed: speed,
|
||||
speedSpread: spread,
|
||||
lifespan: lifespan
|
||||
})
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
|
@ -553,7 +561,7 @@ function MyController(hand) {
|
|||
x: 1,
|
||||
y: 0,
|
||||
z: 0
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)),
|
||||
|
@ -771,13 +779,28 @@ function MyController(hand) {
|
|||
})
|
||||
}
|
||||
|
||||
var intersection = Entities.findRayIntersection(pickRayBacked, true);
|
||||
Messages.sendMessage('Hifi-Light-Overlay-Ray-Check', JSON.stringify(pickRayBacked));
|
||||
|
||||
var intersection;
|
||||
|
||||
if (USE_BLACKLIST === true && blacklist.length !== 0) {
|
||||
intersection = Entities.findRayIntersection(pickRayBacked, true, [], blacklist);
|
||||
} else {
|
||||
intersection = Entities.findRayIntersection(pickRayBacked, true);
|
||||
}
|
||||
|
||||
|
||||
if (intersection.intersects) {
|
||||
|
||||
// the ray is intersecting something we can move.
|
||||
var intersectionDistance = Vec3.distance(pickRay.origin, intersection.intersection);
|
||||
|
||||
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, intersection.entityID, DEFAULT_GRABBABLE_DATA);
|
||||
var defaultDisableNearGrabData = {
|
||||
disableNearGrab: false
|
||||
};
|
||||
//sometimes we want things to stay right where they are when we let go.
|
||||
var disableNearGrabData = getEntityCustomData('handControllerKey', intersection.entityID, defaultDisableNearGrabData);
|
||||
|
||||
if (intersection.properties.name == "Grab Debug Entity") {
|
||||
continue;
|
||||
|
@ -799,7 +822,11 @@ function MyController(hand) {
|
|||
} else if (!intersection.properties.locked) {
|
||||
this.grabbedEntity = intersection.entityID;
|
||||
if (this.state == STATE_SEARCHING) {
|
||||
this.setState(STATE_NEAR_GRABBING);
|
||||
if (disableNearGrabData.disableNearGrab !== true) {
|
||||
this.setState(STATE_NEAR_GRABBING);
|
||||
} else {
|
||||
//disable near grab on this thing
|
||||
}
|
||||
} else { // equipping
|
||||
if (typeof grabbableData.spatialKey !== 'undefined') {
|
||||
// TODO
|
||||
|
@ -922,7 +949,18 @@ function MyController(hand) {
|
|||
this.setState(STATE_NEAR_TRIGGER);
|
||||
return;
|
||||
} else if (!props.locked && props.collisionsWillMove) {
|
||||
this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP)
|
||||
var defaultDisableNearGrabData = {
|
||||
disableNearGrab: false
|
||||
};
|
||||
//sometimes we want things to stay right where they are when we let go.
|
||||
var disableNearGrabData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultDisableNearGrabData);
|
||||
if (disableNearGrabData.disableNearGrab === true) {
|
||||
//do nothing because near grab is disabled for this object
|
||||
} else {
|
||||
this.setState(this.state == STATE_SEARCHING ? STATE_NEAR_GRABBING : STATE_EQUIP)
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -933,7 +971,7 @@ function MyController(hand) {
|
|||
}
|
||||
|
||||
if (USE_OVERLAY_LINES_FOR_SEARCHING === true) {
|
||||
this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR);
|
||||
this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR);
|
||||
}
|
||||
|
||||
if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) {
|
||||
|
@ -1081,22 +1119,54 @@ function MyController(hand) {
|
|||
this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation);
|
||||
|
||||
Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab");
|
||||
// mix in head motion
|
||||
if (MOVE_WITH_HEAD) {
|
||||
var objDistance = Vec3.length(objectToAvatar);
|
||||
var before = Vec3.multiplyQbyV(this.currentCameraOrientation, {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: objDistance
|
||||
});
|
||||
var after = Vec3.multiplyQbyV(Camera.orientation, {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: objDistance
|
||||
});
|
||||
var change = Vec3.subtract(before, after);
|
||||
this.currentCameraOrientation = Camera.orientation;
|
||||
this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change);
|
||||
|
||||
var defaultMoveWithHeadData = {
|
||||
disableMoveWithHead: false
|
||||
};
|
||||
|
||||
var handControllerData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultMoveWithHeadData);
|
||||
|
||||
if (handControllerData.disableMoveWithHead !== true) {
|
||||
// mix in head motion
|
||||
if (MOVE_WITH_HEAD) {
|
||||
var objDistance = Vec3.length(objectToAvatar);
|
||||
var before = Vec3.multiplyQbyV(this.currentCameraOrientation, {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: objDistance
|
||||
});
|
||||
var after = Vec3.multiplyQbyV(Camera.orientation, {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: objDistance
|
||||
});
|
||||
var change = Vec3.subtract(before, after);
|
||||
this.currentCameraOrientation = Camera.orientation;
|
||||
this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change);
|
||||
}
|
||||
} else {
|
||||
// print('should not head move!');
|
||||
}
|
||||
|
||||
|
||||
var defaultConstraintData = {
|
||||
axisStart: false,
|
||||
axisEnd: false,
|
||||
}
|
||||
|
||||
var constraintData = getEntityCustomData('lightModifierKey', this.grabbedEntity, defaultConstraintData);
|
||||
var clampedVector;
|
||||
var targetPosition;
|
||||
if (constraintData.axisStart !== false) {
|
||||
clampedVector = this.projectVectorAlongAxis(this.currentObjectPosition, constraintData.axisStart, constraintData.axisEnd);
|
||||
targetPosition = clampedVector;
|
||||
} else {
|
||||
targetPosition = {
|
||||
x: this.currentObjectPosition.x,
|
||||
y: this.currentObjectPosition.y,
|
||||
z: this.currentObjectPosition.z
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1119,7 +1189,7 @@ function MyController(hand) {
|
|||
}
|
||||
|
||||
Entities.updateAction(this.grabbedEntity, this.actionID, {
|
||||
targetPosition: this.currentObjectPosition,
|
||||
targetPosition: targetPosition,
|
||||
linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
|
||||
targetRotation: this.currentObjectRotation,
|
||||
angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
|
||||
|
@ -1127,96 +1197,122 @@ function MyController(hand) {
|
|||
});
|
||||
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
|
||||
};
|
||||
|
||||
this.nearGrabbing = function() {
|
||||
var now = Date.now();
|
||||
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
|
||||
this.projectVectorAlongAxis = function(position, axisStart, axisEnd) {
|
||||
|
||||
if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) {
|
||||
this.setState(STATE_RELEASE);
|
||||
Entities.callEntityMethod(this.grabbedEntity, "releaseGrab");
|
||||
return;
|
||||
}
|
||||
var aPrime = Vec3.subtract(position, axisStart);
|
||||
|
||||
this.turnOffVisualizations();
|
||||
|
||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
|
||||
this.activateEntity(this.grabbedEntity, grabbedProperties);
|
||||
if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) {
|
||||
Entities.editEntity(this.grabbedEntity, {
|
||||
collisionsWillMove: false
|
||||
});
|
||||
}
|
||||
var bPrime = Vec3.subtract(axisEnd, axisStart);
|
||||
|
||||
var handRotation = this.getHandRotation();
|
||||
var handPosition = this.getHandPosition();
|
||||
|
||||
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
|
||||
var objectRotation = grabbedProperties.rotation;
|
||||
var currentObjectPosition = grabbedProperties.position;
|
||||
var offset = Vec3.subtract(currentObjectPosition, handPosition);
|
||||
if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) {
|
||||
// if an object is "equipped" and has a spatialKey, use it.
|
||||
this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false;
|
||||
if (grabbableData.spatialKey.relativePosition) {
|
||||
this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey);
|
||||
var bPrimeMagnitude = Vec3.length(bPrime);
|
||||
|
||||
var dotProduct = Vec3.dot(aPrime, bPrime);
|
||||
|
||||
|
||||
var scalar = dotProduct / bPrimeMagnitude;
|
||||
|
||||
if (scalar < 0) {
|
||||
scalar = 0;
|
||||
}
|
||||
|
||||
if (scalar > 1) {
|
||||
scalar = 1;
|
||||
}
|
||||
|
||||
var projection = Vec3.sum(axisStart, Vec3.multiply(scalar, Vec3.normalize(bPrime)));
|
||||
|
||||
return projection
|
||||
|
||||
},
|
||||
|
||||
this.nearGrabbing = function() {
|
||||
var now = Date.now();
|
||||
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
|
||||
|
||||
if (this.state == STATE_NEAR_GRABBING && this.triggerSmoothedReleased()) {
|
||||
this.setState(STATE_RELEASE);
|
||||
Entities.callEntityMethod(this.grabbedEntity, "releaseGrab");
|
||||
return;
|
||||
}
|
||||
|
||||
this.lineOff();
|
||||
this.overlayLineOff();
|
||||
|
||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
|
||||
this.activateEntity(this.grabbedEntity, grabbedProperties);
|
||||
if (grabbedProperties.collisionsWillMove && NEAR_GRABBING_KINEMATIC) {
|
||||
Entities.editEntity(this.grabbedEntity, {
|
||||
collisionsWillMove: false
|
||||
});
|
||||
}
|
||||
|
||||
var handRotation = this.getHandRotation();
|
||||
var handPosition = this.getHandPosition();
|
||||
|
||||
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
|
||||
|
||||
if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) {
|
||||
// if an object is "equipped" and has a spatialKey, use it.
|
||||
this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false;
|
||||
this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey);
|
||||
this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey);
|
||||
} else {
|
||||
this.ignoreIK = false;
|
||||
|
||||
var objectRotation = grabbedProperties.rotation;
|
||||
this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
|
||||
|
||||
var currentObjectPosition = grabbedProperties.position;
|
||||
var offset = Vec3.subtract(currentObjectPosition, handPosition);
|
||||
this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset);
|
||||
}
|
||||
if (grabbableData.spatialKey.relativeRotation) {
|
||||
this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey);
|
||||
} else {
|
||||
this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
|
||||
}
|
||||
} else {
|
||||
this.ignoreIK = false;
|
||||
this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
|
||||
this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset);
|
||||
}
|
||||
|
||||
this.actionID = NULL_ACTION_ID;
|
||||
this.actionID = Entities.addAction("hold", this.grabbedEntity, {
|
||||
hand: this.hand === RIGHT_HAND ? "right" : "left",
|
||||
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
||||
relativePosition: this.offsetPosition,
|
||||
relativeRotation: this.offsetRotation,
|
||||
ttl: ACTION_TTL,
|
||||
kinematic: NEAR_GRABBING_KINEMATIC,
|
||||
kinematicSetVelocity: true,
|
||||
ignoreIK: this.ignoreIK
|
||||
});
|
||||
if (this.actionID === NULL_ACTION_ID) {
|
||||
this.actionID = null;
|
||||
} else {
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
if (this.state == STATE_NEAR_GRABBING) {
|
||||
this.setState(STATE_CONTINUE_NEAR_GRABBING);
|
||||
this.actionID = NULL_ACTION_ID;
|
||||
this.actionID = Entities.addAction("hold", this.grabbedEntity, {
|
||||
hand: this.hand === RIGHT_HAND ? "right" : "left",
|
||||
timeScale: NEAR_GRABBING_ACTION_TIMEFRAME,
|
||||
relativePosition: this.offsetPosition,
|
||||
relativeRotation: this.offsetRotation,
|
||||
ttl: ACTION_TTL,
|
||||
kinematic: NEAR_GRABBING_KINEMATIC,
|
||||
kinematicSetVelocity: true,
|
||||
ignoreIK: this.ignoreIK
|
||||
});
|
||||
if (this.actionID === NULL_ACTION_ID) {
|
||||
this.actionID = null;
|
||||
} else {
|
||||
// equipping
|
||||
Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]);
|
||||
this.startHandGrasp();
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
if (this.state == STATE_NEAR_GRABBING) {
|
||||
this.setState(STATE_CONTINUE_NEAR_GRABBING);
|
||||
} else {
|
||||
// equipping
|
||||
Entities.callEntityMethod(this.grabbedEntity, "startEquip", [JSON.stringify(this.hand)]);
|
||||
this.startHandGrasp();
|
||||
|
||||
this.setState(STATE_CONTINUE_EQUIP_BD);
|
||||
}
|
||||
|
||||
if (this.hand === RIGHT_HAND) {
|
||||
Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
|
||||
} else {
|
||||
Entities.callEntityMethod(this.grabbedEntity, "setLeftHand");
|
||||
}
|
||||
|
||||
Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]);
|
||||
|
||||
Entities.callEntityMethod(this.grabbedEntity, "startNearGrab");
|
||||
|
||||
this.setState(STATE_CONTINUE_EQUIP_BD);
|
||||
}
|
||||
|
||||
if (this.hand === RIGHT_HAND) {
|
||||
Entities.callEntityMethod(this.grabbedEntity, "setRightHand");
|
||||
} else {
|
||||
Entities.callEntityMethod(this.grabbedEntity, "setLeftHand");
|
||||
}
|
||||
this.currentHandControllerTipPosition =
|
||||
(this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition;
|
||||
|
||||
Entities.callEntityMethod(this.grabbedEntity, "setHand", [this.hand]);
|
||||
|
||||
Entities.callEntityMethod(this.grabbedEntity, "startNearGrab");
|
||||
|
||||
}
|
||||
|
||||
this.currentHandControllerTipPosition =
|
||||
(this.hand === RIGHT_HAND) ? MyAvatar.rightHandTipPosition : MyAvatar.leftHandTipPosition;
|
||||
|
||||
this.currentObjectTime = Date.now();
|
||||
};
|
||||
this.currentObjectTime = Date.now();
|
||||
};
|
||||
|
||||
this.continueNearGrabbing = function() {
|
||||
if (this.state == STATE_CONTINUE_NEAR_GRABBING && this.triggerSmoothedReleased()) {
|
||||
|
@ -1405,7 +1501,7 @@ function MyController(hand) {
|
|||
}
|
||||
|
||||
if (USE_ENTITY_LINES_FOR_MOVING === true) {
|
||||
this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
|
||||
this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
|
||||
}
|
||||
|
||||
Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger");
|
||||
|
@ -1486,7 +1582,34 @@ function MyController(hand) {
|
|||
|
||||
if (this.grabbedEntity !== null) {
|
||||
if (this.actionID !== null) {
|
||||
Entities.deleteAction(this.grabbedEntity, this.actionID);
|
||||
//add velocity whatnot
|
||||
var defaultReleaseVelocityData = {
|
||||
disableReleaseVelocity: false
|
||||
};
|
||||
//sometimes we want things to stay right where they are when we let go.
|
||||
var releaseVelocityData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultReleaseVelocityData);
|
||||
if (releaseVelocityData.disableReleaseVelocity === true) {
|
||||
Entities.deleteAction(this.grabbedEntity, this.actionID);
|
||||
|
||||
Entities.editEntity(this.grabbedEntity, {
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
angularVelocity: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
}
|
||||
})
|
||||
Entities.deleteAction(this.grabbedEntity, this.actionID);
|
||||
|
||||
} else {
|
||||
//don't make adjustments
|
||||
Entities.deleteAction(this.grabbedEntity, this.actionID);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1616,7 +1739,7 @@ Controller.enableMapping(MAPPING_NAME);
|
|||
var handToDisable = 'none';
|
||||
|
||||
function update() {
|
||||
if (handToDisable !== LEFT_HAND && handToDisable!=='both') {
|
||||
if (handToDisable !== LEFT_HAND && handToDisable !== 'both') {
|
||||
leftController.update();
|
||||
}
|
||||
if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') {
|
||||
|
@ -1626,6 +1749,7 @@ function update() {
|
|||
|
||||
Messages.subscribe('Hifi-Hand-Disabler');
|
||||
Messages.subscribe('Hifi-Hand-Grab');
|
||||
Messages.subscribe('Hifi-Hand-RayPick-Blacklist');
|
||||
|
||||
handleHandMessages = function(channel, message, sender) {
|
||||
if (sender === MyAvatar.sessionUUID) {
|
||||
|
@ -1641,13 +1765,31 @@ handleHandMessages = function(channel, message, sender) {
|
|||
}
|
||||
} else if (channel === 'Hifi-Hand-Grab') {
|
||||
try {
|
||||
var data = JSON.parse(message);
|
||||
var selectedController = (data.hand === 'left') ? leftController : rightController;
|
||||
selectedController.release();
|
||||
selectedController.setState(STATE_EQUIP);
|
||||
selectedController.grabbedEntity = data.entityID;
|
||||
|
||||
} catch (e) { }
|
||||
var data = JSON.parse(message);
|
||||
var selectedController = (data.hand === 'left') ? leftController : rightController;
|
||||
selectedController.release();
|
||||
selectedController.setState(STATE_EQUIP);
|
||||
selectedController.grabbedEntity = data.entityID;
|
||||
|
||||
} catch (e) {}
|
||||
|
||||
} else if (channel === 'Hifi-Hand-RayPick-Blacklist') {
|
||||
try {
|
||||
var data = JSON.parse(message);
|
||||
var action = data.action;
|
||||
var id = data.id;
|
||||
var index = blacklist.indexOf(id);
|
||||
|
||||
if (action === 'add' && index === -1) {
|
||||
blacklist.push(id);
|
||||
}
|
||||
if (action === 'remove') {
|
||||
if (index > -1) {
|
||||
blacklist.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,13 +40,18 @@ RaveStick = function(spawnPosition) {
|
|||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
spatialKey: {
|
||||
relativePosition: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: -0.1
|
||||
rightRelativePosition: {
|
||||
x: 0.02,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
leftRelativePosition: {
|
||||
x: -0.02,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0)
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0)
|
||||
},
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -53,7 +53,9 @@ LightOverlayManager = function() {
|
|||
if (visible != isVisible) {
|
||||
visible = isVisible;
|
||||
for (var id in entityOverlays) {
|
||||
Overlays.editOverlay(entityOverlays[id], { visible: visible });
|
||||
Overlays.editOverlay(entityOverlays[id], {
|
||||
visible: visible
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -61,8 +63,7 @@ LightOverlayManager = function() {
|
|||
// Allocate or get an unused overlay
|
||||
function getOverlay() {
|
||||
if (unusedOverlays.length == 0) {
|
||||
var overlay = Overlays.addOverlay("image3d", {
|
||||
});
|
||||
var overlay = Overlays.addOverlay("image3d", {});
|
||||
allOverlays.push(overlay);
|
||||
} else {
|
||||
var overlay = unusedOverlays.pop();
|
||||
|
@ -72,7 +73,9 @@ LightOverlayManager = function() {
|
|||
|
||||
function releaseOverlay(overlay) {
|
||||
unusedOverlays.push(overlay);
|
||||
Overlays.editOverlay(overlay, { visible: false });
|
||||
Overlays.editOverlay(overlay, {
|
||||
visible: false
|
||||
});
|
||||
}
|
||||
|
||||
function addEntity(entityID) {
|
||||
|
@ -88,7 +91,11 @@ LightOverlayManager = function() {
|
|||
visible: visible,
|
||||
alpha: 0.9,
|
||||
scale: 0.5,
|
||||
color: { red: 255, green: 255, blue: 255 }
|
||||
color: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -123,4 +130,4 @@ LightOverlayManager = function() {
|
|||
Overlays.deleteOverlay(allOverlays[i]);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
|
@ -271,3 +271,29 @@ hexToRgb = function(hex) {
|
|||
} : null;
|
||||
}
|
||||
|
||||
calculateHandSizeRatio = function() {
|
||||
// Get the ratio of the current avatar's hand to Owen's hand
|
||||
|
||||
var standardCenterHandPoint = 0.11288;
|
||||
var jointNames = MyAvatar.getJointNames();
|
||||
//get distance from handJoint up to leftHandIndex3 as a proxy for center of hand
|
||||
var wristToFingertipDistance = 0;;
|
||||
for (var i = 0; i < jointNames.length; i++) {
|
||||
var jointName = jointNames[i];
|
||||
print(jointName)
|
||||
if (jointName.indexOf("LeftHandIndex") !== -1) {
|
||||
// translations are relative to parent joint, so simply add them together
|
||||
// joints face down the y-axis
|
||||
var translation = MyAvatar.getDefaultJointTranslation(i).y;
|
||||
wristToFingertipDistance += translation;
|
||||
}
|
||||
}
|
||||
// Right now units are in cm, so convert to meters
|
||||
wristToFingertipDistance /= 100;
|
||||
|
||||
var centerHandPoint = wristToFingertipDistance/2;
|
||||
|
||||
// Compare against standard hand (Owen)
|
||||
var handSizeRatio = centerHandPoint/standardCenterHandPoint;
|
||||
return handSizeRatio;
|
||||
}
|
||||
|
|
29
examples/light_modifier/README.md
Normal file
29
examples/light_modifier/README.md
Normal file
|
@ -0,0 +1,29 @@
|
|||
This PR demonstrates one way in-world editing of objects might work.
|
||||
|
||||
Running this script will show light overlay icons in-world. Enter edit mode by running your distance beam through a light overlay. Exit using the red X.
|
||||
|
||||
When you distant grab the sliders, you can move them along their axis to change their values. You may also rotate / move the block to which the spotlight is attached.
|
||||
|
||||
To test: https://rawgit.com/imgntn/hifi/light_mod/examples/lights/lightLoader.js
|
||||
To reset, I recommend stopping all scripts then re-loading lightLoader.js
|
||||
|
||||
When you run the lightLoader.js script, several scripts will be loaded:
|
||||
- handControllerGrab.js (will not impart velocity when you move the parent or a slider, will not move sliders with head movement,will constrain movement for a slider to a given axis start and end, will support blacklisting of entities for raypicking during search for objects)
|
||||
- lightModifier.js (listens for message to create sliders for a given light. will start with slider set to the light's initial properties)
|
||||
- lightModifierTestScene.js (creates a light)
|
||||
- slider.js (attached to each slider entity)
|
||||
- lightParent.js (attached to a 3d model of a light, to which a light is parented, so you can move it around. or keep the current parent if a light already has a parent)
|
||||
- visiblePanel.js (the transparent panel)
|
||||
- closeButton.js (for closing the ui)
|
||||
- ../libraries/lightOverlayManager.js (shows 2d overlays for lights in the world)
|
||||
- ../libraries/entitySelectionTool.js (visualizes volume of the lights)
|
||||
|
||||
Current sliders are (top to bottom):
|
||||
red
|
||||
green
|
||||
blue
|
||||
intensity
|
||||
cutoff
|
||||
exponent
|
||||
|
||||

|
36
examples/light_modifier/closeButton.js
Normal file
36
examples/light_modifier/closeButton.js
Normal file
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// closeButton.js
|
||||
//
|
||||
// Created by James Pollack @imgntn on 12/15/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Entity script that closes sliders when interacted with.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function() {
|
||||
|
||||
function CloseButton() {
|
||||
return this;
|
||||
}
|
||||
|
||||
CloseButton.prototype = {
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
var entityProperties = Entities.getEntityProperties(this.entityID, "userData");
|
||||
this.initialProperties = entityProperties
|
||||
this.userData = JSON.parse(entityProperties.userData);
|
||||
},
|
||||
startNearGrab: function() {
|
||||
|
||||
},
|
||||
startFarTrigger: function() {
|
||||
Messages.sendMessage('Hifi-Light-Modifier-Cleanup', 'callCleanup')
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return new CloseButton();
|
||||
});
|
20
examples/light_modifier/lightLoader.js
Normal file
20
examples/light_modifier/lightLoader.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// lightLoader.js
|
||||
//
|
||||
// Created by James Pollack @imgntn on 12/15/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Loads a test scene showing sliders that you can grab and move to change entity properties.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var grabScript = Script.resolvePath('../controllers/handControllerGrab.js?' + Math.random(0 - 100));
|
||||
Script.load(grabScript);
|
||||
var lightModifier = Script.resolvePath('lightModifier.js?' + Math.random(0 - 100));
|
||||
Script.load(lightModifier);
|
||||
Script.setTimeout(function() {
|
||||
var lightModifierTestScene = Script.resolvePath('lightModifierTestScene.js?' + Math.random(0 - 100));
|
||||
Script.load(lightModifierTestScene);
|
||||
}, 750)
|
876
examples/light_modifier/lightModifier.js
Normal file
876
examples/light_modifier/lightModifier.js
Normal file
|
@ -0,0 +1,876 @@
|
|||
//
|
||||
// lightModifier.js
|
||||
//
|
||||
// Created by James Pollack @imgntn on 12/15/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Given a selected light, instantiate some entities that represent various values you can dynamically adjust by grabbing and moving.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
//some experimental options
|
||||
var ONLY_I_CAN_EDIT = false;
|
||||
var SLIDERS_SHOULD_STAY_WITH_AVATAR = false;
|
||||
var VERTICAL_SLIDERS = false;
|
||||
var SHOW_OVERLAYS = true;
|
||||
var SHOW_LIGHT_VOLUME = true;
|
||||
var USE_PARENTED_PANEL = true;
|
||||
var VISIBLE_PANEL = true;
|
||||
var USE_LABELS = true;
|
||||
var LEFT_LABELS = false;
|
||||
var RIGHT_LABELS = true;
|
||||
var ROTATE_CLOSE_BUTTON = false;
|
||||
|
||||
//variables for managing overlays
|
||||
var selectionDisplay;
|
||||
var selectionManager;
|
||||
var lightOverlayManager;
|
||||
|
||||
//for when we make a 3d model of a light a parent for the light
|
||||
var PARENT_SCRIPT_URL = Script.resolvePath('lightParent.js?' + Math.random(0 - 100));
|
||||
|
||||
if (SHOW_OVERLAYS === true) {
|
||||
|
||||
Script.include('../libraries/gridTool.js');
|
||||
Script.include('../libraries/entitySelectionTool.js?' + Math.random(0 - 100));
|
||||
Script.include('../libraries/lightOverlayManager.js');
|
||||
|
||||
var grid = Grid();
|
||||
gridTool = GridTool({
|
||||
horizontalGrid: grid
|
||||
});
|
||||
gridTool.setVisible(false);
|
||||
|
||||
selectionDisplay = SelectionDisplay;
|
||||
selectionManager = SelectionManager;
|
||||
lightOverlayManager = new LightOverlayManager();
|
||||
selectionManager.addEventListener(function() {
|
||||
selectionDisplay.updateHandles();
|
||||
lightOverlayManager.updatePositions();
|
||||
});
|
||||
lightOverlayManager.setVisible(true);
|
||||
}
|
||||
|
||||
var DEFAULT_PARENT_ID = '{00000000-0000-0000-0000-000000000000}'
|
||||
|
||||
var AXIS_SCALE = 1;
|
||||
var COLOR_MAX = 255;
|
||||
var INTENSITY_MAX = 0.05;
|
||||
var CUTOFF_MAX = 360;
|
||||
var EXPONENT_MAX = 1;
|
||||
|
||||
var SLIDER_SCRIPT_URL = Script.resolvePath('slider.js?' + Math.random(0, 100));
|
||||
var LIGHT_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/source4_very_good.fbx';
|
||||
var CLOSE_BUTTON_MODEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/red_x.fbx';
|
||||
var CLOSE_BUTTON_SCRIPT_URL = Script.resolvePath('closeButton.js?' + Math.random(0, 100));
|
||||
var TRANSPARENT_PANEL_URL = 'http://hifi-content.s3.amazonaws.com/james/light_modifier/transparent_box_alpha_15.fbx';
|
||||
var VISIBLE_PANEL_SCRIPT_URL = Script.resolvePath('visiblePanel.js?' + Math.random(0, 100));
|
||||
|
||||
var RED = {
|
||||
red: 255,
|
||||
green: 0,
|
||||
blue: 0
|
||||
};
|
||||
|
||||
var GREEN = {
|
||||
red: 0,
|
||||
green: 255,
|
||||
blue: 0
|
||||
};
|
||||
|
||||
var BLUE = {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 255
|
||||
};
|
||||
|
||||
var PURPLE = {
|
||||
red: 255,
|
||||
green: 0,
|
||||
blue: 255
|
||||
};
|
||||
|
||||
var WHITE = {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
};
|
||||
|
||||
var ORANGE = {
|
||||
red: 255,
|
||||
green: 165,
|
||||
blue: 0
|
||||
}
|
||||
|
||||
var SLIDER_DIMENSIONS = {
|
||||
x: 0.075,
|
||||
y: 0.075,
|
||||
z: 0.075
|
||||
};
|
||||
|
||||
var CLOSE_BUTTON_DIMENSIONS = {
|
||||
x: 0.1,
|
||||
y: 0.025,
|
||||
z: 0.1
|
||||
}
|
||||
|
||||
var LIGHT_MODEL_DIMENSIONS = {
|
||||
x: 0.58,
|
||||
y: 1.21,
|
||||
z: 0.57
|
||||
}
|
||||
|
||||
var PER_ROW_OFFSET = {
|
||||
x: 0,
|
||||
y: -0.2,
|
||||
z: 0
|
||||
};
|
||||
var sliders = [];
|
||||
var slidersRef = {
|
||||
'color_red': null,
|
||||
'color_green': null,
|
||||
'color_blue': null,
|
||||
intensity: null,
|
||||
cutoff: null,
|
||||
exponent: null
|
||||
};
|
||||
var light = null;
|
||||
|
||||
var basePosition;
|
||||
var avatarRotation;
|
||||
|
||||
function entitySlider(light, color, sliderType, displayText, row) {
|
||||
this.light = light;
|
||||
this.lightID = light.id.replace(/[{}]/g, "");
|
||||
this.initialProperties = light.initialProperties;
|
||||
this.color = color;
|
||||
this.sliderType = sliderType;
|
||||
this.displayText = displayText;
|
||||
this.verticalOffset = Vec3.multiply(row, PER_ROW_OFFSET);
|
||||
this.avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0);
|
||||
this.basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1.5, Quat.getFront(this.avatarRot)));
|
||||
this.basePosition.y += 1;
|
||||
basePosition = this.basePosition;
|
||||
avatarRot = this.avatarRot;
|
||||
|
||||
var message = {
|
||||
lightID: this.lightID,
|
||||
sliderType: this.sliderType,
|
||||
sliderValue: null
|
||||
};
|
||||
|
||||
if (this.sliderType === 'color_red') {
|
||||
message.sliderValue = this.initialProperties.color.red
|
||||
this.setValueFromMessage(message);
|
||||
}
|
||||
if (this.sliderType === 'color_green') {
|
||||
message.sliderValue = this.initialProperties.color.green
|
||||
this.setValueFromMessage(message);
|
||||
}
|
||||
if (this.sliderType === 'color_blue') {
|
||||
message.sliderValue = this.initialProperties.color.blue
|
||||
this.setValueFromMessage(message);
|
||||
}
|
||||
|
||||
if (this.sliderType === 'intensity') {
|
||||
message.sliderValue = this.initialProperties.intensity
|
||||
this.setValueFromMessage(message);
|
||||
}
|
||||
|
||||
if (this.sliderType === 'exponent') {
|
||||
message.sliderValue = this.initialProperties.exponent
|
||||
this.setValueFromMessage(message);
|
||||
}
|
||||
|
||||
if (this.sliderType === 'cutoff') {
|
||||
message.sliderValue = this.initialProperties.cutoff
|
||||
this.setValueFromMessage(message);
|
||||
}
|
||||
|
||||
this.setInitialSliderPositions();
|
||||
this.createAxis();
|
||||
this.createSliderIndicator();
|
||||
if (USE_LABELS === true) {
|
||||
this.createLabel()
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
//what's the ux for adjusting values? start with simple entities, try image overlays etc
|
||||
entitySlider.prototype = {
|
||||
createAxis: function() {
|
||||
//start of line
|
||||
var position;
|
||||
var extension;
|
||||
|
||||
if (VERTICAL_SLIDERS == true) {
|
||||
position = Vec3.sum(this.basePosition, Vec3.multiply(row, (Vec3.multiply(0.2, Quat.getRight(this.avatarRot)))));
|
||||
//line starts on bottom and goes up
|
||||
var upVector = Quat.getUp(this.avatarRot);
|
||||
extension = Vec3.multiply(AXIS_SCALE, upVector);
|
||||
} else {
|
||||
position = Vec3.sum(this.basePosition, this.verticalOffset);
|
||||
//line starts on left and goes to right
|
||||
//set the end of the line to the right
|
||||
var rightVector = Quat.getRight(this.avatarRot);
|
||||
extension = Vec3.multiply(AXIS_SCALE, rightVector);
|
||||
}
|
||||
|
||||
|
||||
this.axisStart = position;
|
||||
this.endOfAxis = Vec3.sum(position, extension);
|
||||
this.createEndOfAxisEntity();
|
||||
|
||||
var properties = {
|
||||
type: 'Line',
|
||||
name: 'Hifi-Slider-Axis::' + this.sliderType,
|
||||
color: this.color,
|
||||
collisionsWillMove: false,
|
||||
ignoreForCollisions: true,
|
||||
dimensions: {
|
||||
x: 3,
|
||||
y: 3,
|
||||
z: 3
|
||||
},
|
||||
position: position,
|
||||
linePoints: [{
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
}, extension],
|
||||
lineWidth: 5,
|
||||
};
|
||||
|
||||
this.axis = Entities.addEntity(properties);
|
||||
},
|
||||
createEndOfAxisEntity: function() {
|
||||
//we use this to track the end of the axis while parented to a panel
|
||||
var properties = {
|
||||
name: 'Hifi-End-Of-Axis',
|
||||
type: 'Box',
|
||||
collisionsWillMove: false,
|
||||
ignoreForCollisions: true,
|
||||
dimensions: {
|
||||
x: 0.01,
|
||||
y: 0.01,
|
||||
z: 0.01
|
||||
},
|
||||
color: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
},
|
||||
position: this.endOfAxis,
|
||||
parentID: this.axis,
|
||||
visible: false
|
||||
}
|
||||
|
||||
this.endOfAxisEntity = Entities.addEntity(this.endOfAxis);
|
||||
},
|
||||
createLabel: function() {
|
||||
|
||||
var LABEL_WIDTH = 0.25
|
||||
var PER_LETTER_SPACING = 0.1;
|
||||
var textWidth = this.displayText.length * PER_LETTER_SPACING;
|
||||
|
||||
var position;
|
||||
if (LEFT_LABELS === true) {
|
||||
var leftVector = Vec3.multiply(-1, Quat.getRight(this.avatarRot));
|
||||
|
||||
var extension = Vec3.multiply(textWidth, leftVector);
|
||||
|
||||
position = Vec3.sum(this.axisStart, extension);
|
||||
}
|
||||
|
||||
if (RIGHT_LABELS === true) {
|
||||
var rightVector = Quat.getRight(this.avatarRot);
|
||||
|
||||
var extension = Vec3.multiply(textWidth / 1.75, rightVector);
|
||||
|
||||
position = Vec3.sum(this.endOfAxis, extension);
|
||||
}
|
||||
|
||||
|
||||
var labelProperties = {
|
||||
name: 'Hifi-Slider-Label-' + this.sliderType,
|
||||
type: 'Text',
|
||||
dimensions: {
|
||||
x: textWidth,
|
||||
y: 0.2,
|
||||
z: 0.1
|
||||
},
|
||||
textColor: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
},
|
||||
text: this.displayText,
|
||||
lineHeight: 0.14,
|
||||
backgroundColor: {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 0
|
||||
},
|
||||
position: position,
|
||||
rotation: this.avatarRot,
|
||||
}
|
||||
print('BEFORE CREATE LABEL' + JSON.stringify(labelProperties))
|
||||
this.label = Entities.addEntity(labelProperties);
|
||||
print('AFTER CREATE LABEL')
|
||||
},
|
||||
createSliderIndicator: function() {
|
||||
var extensionVector;
|
||||
var position;
|
||||
if (VERTICAL_SLIDERS == true) {
|
||||
position = Vec3.sum(this.basePosition, Vec3.multiply(row, (Vec3.multiply(0.2, Quat.getRight(this.avatarRot)))));
|
||||
extensionVector = Quat.getUp(this.avatarRot);
|
||||
|
||||
} else {
|
||||
position = Vec3.sum(this.basePosition, this.verticalOffset);
|
||||
extensionVector = Quat.getRight(this.avatarRot);
|
||||
|
||||
}
|
||||
|
||||
var initialDistance;
|
||||
if (this.sliderType === 'color_red') {
|
||||
initialDistance = this.distanceRed;
|
||||
}
|
||||
if (this.sliderType === 'color_green') {
|
||||
initialDistance = this.distanceGreen;
|
||||
}
|
||||
if (this.sliderType === 'color_blue') {
|
||||
initialDistance = this.distanceBlue;
|
||||
}
|
||||
if (this.sliderType === 'intensity') {
|
||||
initialDistance = this.distanceIntensity;
|
||||
}
|
||||
if (this.sliderType === 'cutoff') {
|
||||
initialDistance = this.distanceCutoff;
|
||||
}
|
||||
if (this.sliderType === 'exponent') {
|
||||
initialDistance = this.distanceExponent;
|
||||
}
|
||||
|
||||
var extension = Vec3.multiply(initialDistance, extensionVector);
|
||||
var sliderPosition = Vec3.sum(position, extension);
|
||||
|
||||
var properties = {
|
||||
type: 'Sphere',
|
||||
name: 'Hifi-Slider-' + this.sliderType,
|
||||
dimensions: SLIDER_DIMENSIONS,
|
||||
collisionsWillMove: true,
|
||||
color: this.color,
|
||||
position: sliderPosition,
|
||||
script: SLIDER_SCRIPT_URL,
|
||||
ignoreForCollisions: true,
|
||||
userData: JSON.stringify({
|
||||
lightModifierKey: {
|
||||
lightID: this.lightID,
|
||||
sliderType: this.sliderType,
|
||||
axisStart: position,
|
||||
axisEnd: this.endOfAxis,
|
||||
},
|
||||
handControllerKey: {
|
||||
disableReleaseVelocity: true,
|
||||
disableMoveWithHead: true,
|
||||
disableNearGrab:true
|
||||
}
|
||||
}),
|
||||
};
|
||||
|
||||
this.sliderIndicator = Entities.addEntity(properties);
|
||||
},
|
||||
setValueFromMessage: function(message) {
|
||||
|
||||
//message is not for our light
|
||||
if (message.lightID !== this.lightID) {
|
||||
// print('not our light')
|
||||
return;
|
||||
}
|
||||
|
||||
//message is not our type
|
||||
if (message.sliderType !== this.sliderType) {
|
||||
// print('not our slider type')
|
||||
return
|
||||
}
|
||||
|
||||
var lightProperties = Entities.getEntityProperties(this.lightID);
|
||||
|
||||
if (this.sliderType === 'color_red') {
|
||||
Entities.editEntity(this.lightID, {
|
||||
color: {
|
||||
red: message.sliderValue,
|
||||
green: lightProperties.color.green,
|
||||
blue: lightProperties.color.blue
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (this.sliderType === 'color_green') {
|
||||
Entities.editEntity(this.lightID, {
|
||||
color: {
|
||||
red: lightProperties.color.red,
|
||||
green: message.sliderValue,
|
||||
blue: lightProperties.color.blue
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (this.sliderType === 'color_blue') {
|
||||
Entities.editEntity(this.lightID, {
|
||||
color: {
|
||||
red: lightProperties.color.red,
|
||||
green: lightProperties.color.green,
|
||||
blue: message.sliderValue,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (this.sliderType === 'intensity') {
|
||||
Entities.editEntity(this.lightID, {
|
||||
intensity: message.sliderValue
|
||||
});
|
||||
}
|
||||
|
||||
if (this.sliderType === 'cutoff') {
|
||||
Entities.editEntity(this.lightID, {
|
||||
cutoff: message.sliderValue
|
||||
});
|
||||
}
|
||||
|
||||
if (this.sliderType === 'exponent') {
|
||||
Entities.editEntity(this.lightID, {
|
||||
exponent: message.sliderValue
|
||||
});
|
||||
}
|
||||
},
|
||||
setInitialSliderPositions: function() {
|
||||
this.distanceRed = (this.initialProperties.color.red / COLOR_MAX) * AXIS_SCALE;
|
||||
this.distanceGreen = (this.initialProperties.color.green / COLOR_MAX) * AXIS_SCALE;
|
||||
this.distanceBlue = (this.initialProperties.color.blue / COLOR_MAX) * AXIS_SCALE;
|
||||
this.distanceIntensity = (this.initialProperties.intensity / INTENSITY_MAX) * AXIS_SCALE;
|
||||
this.distanceCutoff = (this.initialProperties.cutoff / CUTOFF_MAX) * AXIS_SCALE;
|
||||
this.distanceExponent = (this.initialProperties.exponent / EXPONENT_MAX) * AXIS_SCALE;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
var panel;
|
||||
var visiblePanel;
|
||||
|
||||
function makeSliders(light) {
|
||||
|
||||
if (USE_PARENTED_PANEL === true) {
|
||||
panel = createPanelEntity(MyAvatar.position);
|
||||
}
|
||||
|
||||
if (light.type === 'spotlight') {
|
||||
var USE_COLOR_SLIDER = true;
|
||||
var USE_INTENSITY_SLIDER = true;
|
||||
var USE_CUTOFF_SLIDER = true;
|
||||
var USE_EXPONENT_SLIDER = true;
|
||||
}
|
||||
if (light.type === 'pointlight') {
|
||||
var USE_COLOR_SLIDER = true;
|
||||
var USE_INTENSITY_SLIDER = true;
|
||||
var USE_CUTOFF_SLIDER = false;
|
||||
var USE_EXPONENT_SLIDER = false;
|
||||
}
|
||||
if (USE_COLOR_SLIDER === true) {
|
||||
slidersRef.color_red = new entitySlider(light, RED, 'color_red', 'Red', 1);
|
||||
slidersRef.color_green = new entitySlider(light, GREEN, 'color_green', 'Green', 2);
|
||||
slidersRef.color_blue = new entitySlider(light, BLUE, 'color_blue', 'Blue', 3);
|
||||
|
||||
sliders.push(slidersRef.color_red);
|
||||
sliders.push(slidersRef.color_green);
|
||||
sliders.push(slidersRef.color_blue);
|
||||
|
||||
}
|
||||
if (USE_INTENSITY_SLIDER === true) {
|
||||
slidersRef.intensity = new entitySlider(light, WHITE, 'intensity', 'Intensity', 4);
|
||||
sliders.push(slidersRef.intensity);
|
||||
}
|
||||
if (USE_CUTOFF_SLIDER === true) {
|
||||
slidersRef.cutoff = new entitySlider(light, PURPLE, 'cutoff', 'Cutoff', 5);
|
||||
sliders.push(slidersRef.cutoff);
|
||||
}
|
||||
if (USE_EXPONENT_SLIDER === true) {
|
||||
slidersRef.exponent = new entitySlider(light, ORANGE, 'exponent', 'Exponent', 6);
|
||||
sliders.push(slidersRef.exponent);
|
||||
}
|
||||
|
||||
createCloseButton(slidersRef.color_red.axisStart);
|
||||
|
||||
subscribeToSliderMessages();
|
||||
|
||||
if (USE_PARENTED_PANEL === true) {
|
||||
parentEntitiesToPanel(panel);
|
||||
}
|
||||
|
||||
if (SLIDERS_SHOULD_STAY_WITH_AVATAR === true) {
|
||||
parentPanelToAvatar(panel);
|
||||
}
|
||||
|
||||
if (VISIBLE_PANEL === true) {
|
||||
visiblePanel = createVisiblePanel();
|
||||
}
|
||||
};
|
||||
|
||||
function parentPanelToAvatar(panel) {
|
||||
//this is going to need some more work re: the sliders actually being grabbable. probably something to do with updating axis movement
|
||||
Entities.editEntity(panel, {
|
||||
parentID: MyAvatar.sessionUUID,
|
||||
//actually figure out which one to parent it to -- probably a spine or something.
|
||||
parentJointIndex: 1,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function parentEntitiesToPanel(panel) {
|
||||
|
||||
sliders.forEach(function(slider) {
|
||||
Entities.editEntity(slider.axis, {
|
||||
parentID: panel
|
||||
})
|
||||
Entities.editEntity(slider.sliderIndicator, {
|
||||
parentID: panel
|
||||
})
|
||||
})
|
||||
|
||||
closeButtons.forEach(function(button) {
|
||||
Entities.editEntity(button, {
|
||||
parentID: panel
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function createPanelEntity(position) {
|
||||
print('CREATING PANEL at ' + JSON.stringify(position));
|
||||
var panelProperties = {
|
||||
name: 'Hifi-Slider-Panel',
|
||||
type: 'Box',
|
||||
dimensions: {
|
||||
x: 0.1,
|
||||
y: 0.1,
|
||||
z: 0.1
|
||||
},
|
||||
visible: false,
|
||||
collisionsWillMove: false,
|
||||
ignoreForCollisions: true
|
||||
}
|
||||
|
||||
var panel = Entities.addEntity(panelProperties);
|
||||
return panel
|
||||
}
|
||||
|
||||
function createVisiblePanel() {
|
||||
var totalOffset = -PER_ROW_OFFSET.y * sliders.length;
|
||||
|
||||
var moveRight = Vec3.sum(basePosition, Vec3.multiply(AXIS_SCALE / 2, Quat.getRight(avatarRot)));
|
||||
|
||||
var moveDown = Vec3.sum(moveRight, Vec3.multiply((sliders.length + 1) / 2, PER_ROW_OFFSET))
|
||||
var panelProperties = {
|
||||
name: 'Hifi-Visible-Transparent-Panel',
|
||||
type: 'Model',
|
||||
modelURL: TRANSPARENT_PANEL_URL,
|
||||
dimensions: {
|
||||
x: AXIS_SCALE + 0.1,
|
||||
y: totalOffset,
|
||||
z: SLIDER_DIMENSIONS.z / 4
|
||||
},
|
||||
visible: true,
|
||||
collisionsWillMove: false,
|
||||
ignoreForCollisions: true,
|
||||
position: moveDown,
|
||||
rotation: avatarRot,
|
||||
script: VISIBLE_PANEL_SCRIPT_URL
|
||||
}
|
||||
|
||||
var panel = Entities.addEntity(panelProperties);
|
||||
|
||||
return panel
|
||||
}
|
||||
|
||||
|
||||
function createLightModel(position, rotation) {
|
||||
var blockProperties = {
|
||||
name: 'Hifi-Spotlight-Model',
|
||||
type: 'Model',
|
||||
shapeType: 'box',
|
||||
modelURL: LIGHT_MODEL_URL,
|
||||
dimensions: LIGHT_MODEL_DIMENSIONS,
|
||||
collisionsWillMove: true,
|
||||
position: position,
|
||||
rotation: rotation,
|
||||
script: PARENT_SCRIPT_URL,
|
||||
userData: JSON.stringify({
|
||||
handControllerKey: {
|
||||
disableReleaseVelocity: true
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
var block = Entities.addEntity(blockProperties);
|
||||
|
||||
return block
|
||||
}
|
||||
|
||||
var closeButtons = [];
|
||||
|
||||
function createCloseButton(axisStart) {
|
||||
var MARGIN = 0.10;
|
||||
var VERTICAL_OFFFSET = {
|
||||
x: 0,
|
||||
y: 0.15,
|
||||
z: 0
|
||||
};
|
||||
var leftVector = Vec3.multiply(-1, Quat.getRight(avatarRot));
|
||||
var extension = Vec3.multiply(MARGIN, leftVector);
|
||||
var position = Vec3.sum(axisStart, extension);
|
||||
|
||||
var buttonProperties = {
|
||||
name: 'Hifi-Close-Button',
|
||||
type: 'Model',
|
||||
modelURL: CLOSE_BUTTON_MODEL_URL,
|
||||
dimensions: CLOSE_BUTTON_DIMENSIONS,
|
||||
position: Vec3.sum(position, VERTICAL_OFFFSET),
|
||||
rotation: Quat.multiply(avatarRot, Quat.fromPitchYawRollDegrees(90, 0, 45)),
|
||||
//rotation: Quat.fromPitchYawRollDegrees(0, 0, 90),
|
||||
collisionsWillMove: false,
|
||||
ignoreForCollisions: true,
|
||||
script: CLOSE_BUTTON_SCRIPT_URL,
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
wantsTrigger: true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var button = Entities.addEntity(buttonProperties);
|
||||
|
||||
closeButtons.push(button);
|
||||
|
||||
if (ROTATE_CLOSE_BUTTON === true) {
|
||||
Script.update.connect(rotateCloseButtons);
|
||||
}
|
||||
}
|
||||
|
||||
function rotateCloseButtons() {
|
||||
closeButtons.forEach(function(button) {
|
||||
Entities.editEntity(button, {
|
||||
angularVelocity: {
|
||||
x: 0,
|
||||
y: 0.5,
|
||||
z: 0
|
||||
}
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
function subScribeToNewLights() {
|
||||
Messages.subscribe('Hifi-Light-Mod-Receiver');
|
||||
Messages.messageReceived.connect(handleLightModMessages);
|
||||
}
|
||||
|
||||
function subscribeToSliderMessages() {
|
||||
Messages.subscribe('Hifi-Slider-Value-Reciever');
|
||||
Messages.messageReceived.connect(handleValueMessages);
|
||||
}
|
||||
|
||||
function subscribeToLightOverlayRayCheckMessages() {
|
||||
Messages.subscribe('Hifi-Light-Overlay-Ray-Check');
|
||||
Messages.messageReceived.connect(handleLightOverlayRayCheckMessages);
|
||||
}
|
||||
|
||||
function subscribeToCleanupMessages() {
|
||||
Messages.subscribe('Hifi-Light-Modifier-Cleanup');
|
||||
Messages.messageReceived.connect(handleCleanupMessages);
|
||||
}
|
||||
|
||||
|
||||
function handleLightModMessages(channel, message, sender) {
|
||||
if (channel !== 'Hifi-Light-Mod-Receiver') {
|
||||
return;
|
||||
}
|
||||
if (sender !== MyAvatar.sessionUUID) {
|
||||
return;
|
||||
}
|
||||
var parsedMessage = JSON.parse(message);
|
||||
|
||||
makeSliders(parsedMessage.light);
|
||||
light = parsedMessage.light.id
|
||||
if (SHOW_LIGHT_VOLUME === true) {
|
||||
selectionManager.setSelections([parsedMessage.light.id]);
|
||||
}
|
||||
}
|
||||
|
||||
function handleValueMessages(channel, message, sender) {
|
||||
|
||||
if (channel !== 'Hifi-Slider-Value-Reciever') {
|
||||
return;
|
||||
}
|
||||
if (ONLY_I_CAN_EDIT === true && sender !== MyAvatar.sessionUUID) {
|
||||
return;
|
||||
}
|
||||
var parsedMessage = JSON.parse(message);
|
||||
|
||||
slidersRef[parsedMessage.sliderType].setValueFromMessage(parsedMessage);
|
||||
}
|
||||
|
||||
var currentLight;
|
||||
var block;
|
||||
var oldParent = null;
|
||||
var hasParent = false;
|
||||
|
||||
function handleLightOverlayRayCheckMessages(channel, message, sender) {
|
||||
if (channel !== 'Hifi-Light-Overlay-Ray-Check') {
|
||||
return;
|
||||
}
|
||||
if (ONLY_I_CAN_EDIT === true && sender !== MyAvatar.sessionUUID) {
|
||||
return;
|
||||
}
|
||||
|
||||
var pickRay = JSON.parse(message);
|
||||
|
||||
var doesIntersect = lightOverlayManager.findRayIntersection(pickRay);
|
||||
// print('DOES INTERSECT A LIGHT WE HAVE???' + doesIntersect.intersects);
|
||||
if (doesIntersect.intersects === true) {
|
||||
// print('FULL MESSAGE:::' + JSON.stringify(doesIntersect))
|
||||
|
||||
var lightID = doesIntersect.entityID;
|
||||
if (currentLight === lightID) {
|
||||
// print('ALREADY HAVE A BLOCK, EXIT')
|
||||
return;
|
||||
}
|
||||
|
||||
currentLight = lightID;
|
||||
var lightProperties = Entities.getEntityProperties(lightID);
|
||||
if (lightProperties.parentID !== DEFAULT_PARENT_ID) {
|
||||
//this light has a parent already. so lets call our block the parent and then make sure not to delete it at the end;
|
||||
oldParent = lightProperties.parentID;
|
||||
hasParent = true;
|
||||
block = lightProperties.parentID;
|
||||
if (lightProperties.parentJointIndex !== -1) {
|
||||
//should make sure to retain the parent too. but i don't actually know what the
|
||||
}
|
||||
} else {
|
||||
block = createLightModel(lightProperties.position, lightProperties.rotation);
|
||||
}
|
||||
|
||||
var light = {
|
||||
id: lightID,
|
||||
type: 'spotlight',
|
||||
initialProperties: lightProperties
|
||||
}
|
||||
|
||||
makeSliders(light);
|
||||
|
||||
if (SHOW_LIGHT_VOLUME === true) {
|
||||
selectionManager.setSelections([lightID]);
|
||||
}
|
||||
|
||||
Entities.editEntity(lightID, {
|
||||
parentID: block,
|
||||
parentJointIndex: -1
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function handleCleanupMessages(channel, message, sender) {
|
||||
|
||||
if (channel !== 'Hifi-Light-Modifier-Cleanup') {
|
||||
return;
|
||||
}
|
||||
if (ONLY_I_CAN_EDIT === true && sender !== MyAvatar.sessionUUID) {
|
||||
return;
|
||||
}
|
||||
if (message === 'callCleanup') {
|
||||
cleanup(true);
|
||||
}
|
||||
}
|
||||
|
||||
function updateSliderAxis() {
|
||||
sliders.forEach(function(slider) {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
function cleanup(fromMessage) {
|
||||
var i;
|
||||
for (i = 0; i < sliders.length; i++) {
|
||||
Entities.deleteEntity(sliders[i].axis);
|
||||
Entities.deleteEntity(sliders[i].sliderIndicator);
|
||||
Entities.deleteEntity(sliders[i].label);
|
||||
}
|
||||
|
||||
while (closeButtons.length > 0) {
|
||||
Entities.deleteEntity(closeButtons.pop());
|
||||
}
|
||||
|
||||
//if the light was already parented to something we will want to restore that. or come up with groups or something clever.
|
||||
if (oldParent !== null) {
|
||||
Entities.editEntity(currentLight, {
|
||||
parentID: oldParent,
|
||||
});
|
||||
} else {
|
||||
Entities.editEntity(currentLight, {
|
||||
parentID: null,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
if (fromMessage !== true) {
|
||||
Messages.messageReceived.disconnect(handleLightModMessages);
|
||||
Messages.messageReceived.disconnect(handleValueMessages);
|
||||
Messages.messageReceived.disconnect(handleLightOverlayRayCheckMessages);
|
||||
lightOverlayManager.setVisible(false);
|
||||
}
|
||||
|
||||
|
||||
Entities.deleteEntity(panel);
|
||||
Entities.deleteEntity(visiblePanel);
|
||||
|
||||
selectionManager.clearSelections();
|
||||
|
||||
if (ROTATE_CLOSE_BUTTON === true) {
|
||||
Script.update.disconnect(rotateCloseButtons);
|
||||
}
|
||||
|
||||
if (hasParent === false) {
|
||||
Entities.deleteEntity(block);
|
||||
}
|
||||
|
||||
oldParent = null;
|
||||
hasParent = false;
|
||||
currentLight = null;
|
||||
sliders = [];
|
||||
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
|
||||
Script.scriptEnding.connect(function() {
|
||||
lightOverlayManager.setVisible(false);
|
||||
})
|
||||
|
||||
|
||||
subscribeToLightOverlayRayCheckMessages();
|
||||
subScribeToNewLights();
|
||||
subscribeToCleanupMessages();
|
||||
|
||||
|
||||
|
||||
//other light properties
|
||||
// diffuseColor: { red: 255, green: 255, blue: 255 },
|
||||
// ambientColor: { red: 255, green: 255, blue: 255 },
|
||||
// specularColor: { red: 255, green: 255, blue: 255 },
|
||||
// constantAttenuation: 1,
|
||||
// linearAttenuation: 0,
|
||||
// quadraticAttenuation: 0,
|
||||
// exponent: 0,
|
||||
// cutoff: 180, // in degrees
|
73
examples/light_modifier/lightModifierTestScene.js
Normal file
73
examples/light_modifier/lightModifierTestScene.js
Normal file
|
@ -0,0 +1,73 @@
|
|||
//
|
||||
// lightModifierTestScene.js
|
||||
//
|
||||
// Created by James Pollack @imgntn on 12/15/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Given a selected light, instantiate some entities that represent various values you can dynamically adjust.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var PARENT_SCRIPT_URL = Script.resolvePath('lightParent.js?' + Math.random(0 - 100));
|
||||
var basePosition, avatarRot;
|
||||
avatarRot = Quat.fromPitchYawRollDegrees(0, MyAvatar.bodyYaw, 0.0);
|
||||
basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(0, Quat.getUp(avatarRot)));
|
||||
|
||||
var light;
|
||||
|
||||
function createLight() {
|
||||
var position = basePosition;
|
||||
position.y += 2;
|
||||
var lightTransform = evalLightWorldTransform(position, avatarRot);
|
||||
var lightProperties = {
|
||||
name: 'Hifi-Spotlight',
|
||||
type: "Light",
|
||||
isSpotlight: true,
|
||||
dimensions: {
|
||||
x: 2,
|
||||
y: 2,
|
||||
z: 8
|
||||
},
|
||||
color: {
|
||||
red: 255,
|
||||
green: 0,
|
||||
blue: 255
|
||||
},
|
||||
intensity: 0.035,
|
||||
exponent: 1,
|
||||
cutoff: 30,
|
||||
lifetime: -1,
|
||||
position: lightTransform.p,
|
||||
rotation: lightTransform.q
|
||||
};
|
||||
|
||||
light = Entities.addEntity(lightProperties);
|
||||
|
||||
}
|
||||
|
||||
function evalLightWorldTransform(modelPos, modelRot) {
|
||||
var MODEL_LIGHT_POSITION = {
|
||||
x: 0,
|
||||
y: -0.3,
|
||||
z: 0
|
||||
};
|
||||
var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, {
|
||||
x: 1,
|
||||
y: 0,
|
||||
z: 0
|
||||
});
|
||||
return {
|
||||
p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)),
|
||||
q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION)
|
||||
};
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
Entities.deleteEntity(light);
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
|
||||
createLight();
|
40
examples/light_modifier/lightParent.js
Normal file
40
examples/light_modifier/lightParent.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// lightParent.js
|
||||
//
|
||||
// Created by James Pollack @imgntn on 12/15/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Entity script that tells the light parent to update the selection tool when we move it.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function() {
|
||||
|
||||
function LightParent() {
|
||||
return this;
|
||||
}
|
||||
|
||||
LightParent.prototype = {
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
var entityProperties = Entities.getEntityProperties(this.entityID, "userData");
|
||||
this.initialProperties = entityProperties
|
||||
this.userData = JSON.parse(entityProperties.userData);
|
||||
},
|
||||
startNearGrab: function() {},
|
||||
startDistantGrab: function() {
|
||||
|
||||
},
|
||||
continueNearGrab: function() {
|
||||
this.continueDistantGrab();
|
||||
},
|
||||
continueDistantGrab: function() {
|
||||
Messages.sendMessage('entityToolUpdates', 'callUpdate');
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
return new LightParent();
|
||||
});
|
105
examples/light_modifier/slider.js
Normal file
105
examples/light_modifier/slider.js
Normal file
|
@ -0,0 +1,105 @@
|
|||
//
|
||||
// slider.js
|
||||
//
|
||||
// Created by James Pollack @imgntn on 12/15/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Entity script that sends a scaled value to a light based on its distance from the start of its constraint axis.
|
||||
//
|
||||
// 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 AXIS_SCALE = 1;
|
||||
var COLOR_MAX = 255;
|
||||
var INTENSITY_MAX = 0.05;
|
||||
var CUTOFF_MAX = 360;
|
||||
var EXPONENT_MAX = 1;
|
||||
|
||||
function Slider() {
|
||||
return this;
|
||||
}
|
||||
|
||||
Slider.prototype = {
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
var entityProperties = Entities.getEntityProperties(this.entityID, "userData");
|
||||
var parsedUserData = JSON.parse(entityProperties.userData);
|
||||
this.userData = parsedUserData.lightModifierKey;
|
||||
},
|
||||
startNearGrab: function() {
|
||||
this.setInitialProperties();
|
||||
},
|
||||
startDistantGrab: function() {
|
||||
this.setInitialProperties();
|
||||
},
|
||||
setInitialProperties: function() {
|
||||
this.initialProperties = Entities.getEntityProperties(this.entityID);
|
||||
},
|
||||
continueNearGrab: function() {
|
||||
// this.continueDistantGrab();
|
||||
},
|
||||
continueDistantGrab: function() {
|
||||
this.setSliderValueBasedOnDistance();
|
||||
},
|
||||
setSliderValueBasedOnDistance: function() {
|
||||
var currentPosition = Entities.getEntityProperties(this.entityID, "position").position;
|
||||
|
||||
var distance = Vec3.distance(this.userData.axisStart, currentPosition);
|
||||
|
||||
if (this.userData.sliderType === 'color_red' || this.userData.sliderType === 'color_green' || this.userData.sliderType === 'color_blue') {
|
||||
this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, 0, COLOR_MAX);
|
||||
}
|
||||
if (this.userData.sliderType === 'intensity') {
|
||||
this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, 0, INTENSITY_MAX);
|
||||
}
|
||||
if (this.userData.sliderType === 'cutoff') {
|
||||
this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, 0, CUTOFF_MAX);
|
||||
}
|
||||
if (this.userData.sliderType === 'exponent') {
|
||||
this.sliderValue = this.scaleValueBasedOnDistanceFromStart(distance, 0, EXPONENT_MAX);
|
||||
};
|
||||
|
||||
this.sendValueToSlider();
|
||||
},
|
||||
releaseGrab: function() {
|
||||
Entities.editEntity(this.entityID, {
|
||||
velocity: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
angularVelocity: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
}
|
||||
})
|
||||
|
||||
this.sendValueToSlider();
|
||||
},
|
||||
scaleValueBasedOnDistanceFromStart: function(value, min2, max2) {
|
||||
var min1 = 0;
|
||||
var max1 = AXIS_SCALE;
|
||||
var min2 = min2;
|
||||
var max2 = max2;
|
||||
return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
|
||||
},
|
||||
sendValueToSlider: function() {
|
||||
var _t = this;
|
||||
var message = {
|
||||
lightID: _t.userData.lightID,
|
||||
sliderType: _t.userData.sliderType,
|
||||
sliderValue: _t.sliderValue
|
||||
}
|
||||
Messages.sendMessage('Hifi-Slider-Value-Reciever', JSON.stringify(message));
|
||||
if (_t.userData.sliderType === 'cutoff') {
|
||||
Messages.sendMessage('entityToolUpdates', 'callUpdate');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return new Slider();
|
||||
});
|
40
examples/light_modifier/visiblePanel.js
Normal file
40
examples/light_modifier/visiblePanel.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// visiblePanel.js
|
||||
//
|
||||
// Created by James Pollack @imgntn on 12/15/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Entity script that disables picking on this panel.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function() {
|
||||
|
||||
function VisiblePanel() {
|
||||
return this;
|
||||
}
|
||||
|
||||
VisiblePanel.prototype = {
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
|
||||
var data = {
|
||||
action: 'add',
|
||||
id: this.entityID
|
||||
};
|
||||
Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data))
|
||||
},
|
||||
unload: function() {
|
||||
var data = {
|
||||
action: 'remove',
|
||||
id: this.entityID
|
||||
};
|
||||
Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data))
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return new VisiblePanel();
|
||||
});
|
|
@ -247,4 +247,4 @@ function cleanup() {
|
|||
|
||||
|
||||
// Uncomment this line to delete whiteboard and all associated entity on script close
|
||||
//Script.scriptEnding.connect(cleanup);
|
||||
// Script.scriptEnding.connect(cleanup);
|
||||
|
|
73
examples/rayPickingFilterExample.js
Normal file
73
examples/rayPickingFilterExample.js
Normal file
|
@ -0,0 +1,73 @@
|
|||
//
|
||||
// rayPickingFilterExample.js
|
||||
// examples
|
||||
//
|
||||
// Created by Eric Levin on 12/24/2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that demonstrates the use of filtering entities for ray picking
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(Camera.getOrientation())));
|
||||
|
||||
var whiteListBox = Entities.addEntity({
|
||||
type: "Box",
|
||||
color: {
|
||||
red: 10,
|
||||
green: 200,
|
||||
blue: 10
|
||||
},
|
||||
dimensions: {
|
||||
x: 0.2,
|
||||
y: 0.2,
|
||||
z: 0.2
|
||||
},
|
||||
position: center
|
||||
});
|
||||
|
||||
var blackListBox = Entities.addEntity({
|
||||
type: "Box",
|
||||
color: {
|
||||
red: 100,
|
||||
green: 10,
|
||||
blue: 10
|
||||
},
|
||||
dimensions: {
|
||||
x: 0.2,
|
||||
y: 0.2,
|
||||
z: 0.2
|
||||
},
|
||||
position: Vec3.sum(center, {
|
||||
x: 0,
|
||||
y: 0.3,
|
||||
z: 0
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
function castRay(event) {
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
// In this example every entity will be pickable except the entities in the blacklist array
|
||||
// the third argument is the whitelist array,and the fourth and final is the blacklist array
|
||||
var pickResults = Entities.findRayIntersection(pickRay, true, [], [blackListBox]);
|
||||
|
||||
// With below example, only entities added to whitelist will be pickable
|
||||
// var pickResults = Entities.findRayIntersection(pickRay, true, [whiteListBox], []);
|
||||
|
||||
if (pickResults.intersects) {
|
||||
print("INTERSECTION!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
Entities.deleteEntity(whiteListBox);
|
||||
Entities.deleteEntity(blackListBox);
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
Controller.mousePressEvent.connect(castRay);
|
|
@ -29,21 +29,14 @@
|
|||
this.equipped = false;
|
||||
this.forceMultiplier = 1;
|
||||
this.laserLength = 100;
|
||||
this.laserOffsets = {
|
||||
y: .095
|
||||
};
|
||||
this.firingOffsets = {
|
||||
z: 0.16
|
||||
}
|
||||
|
||||
this.fireSound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Guns/GUN-SHOT2.raw");
|
||||
this.ricochetSound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Guns/Ricochet.L.wav");
|
||||
this.playRichochetSoundChance = 0.1;
|
||||
this.fireVolume = 0.2;
|
||||
this.bulletForce = 10;
|
||||
|
||||
|
||||
|
||||
this.showLaser = false;
|
||||
|
||||
};
|
||||
|
||||
Pistol.prototype = {
|
||||
|
@ -58,20 +51,36 @@
|
|||
if (!this.equipped) {
|
||||
return;
|
||||
}
|
||||
this.toggleWithTriggerPressure();
|
||||
this.updateProps();
|
||||
if (this.showLaser) {
|
||||
this.updateLaser();
|
||||
}
|
||||
this.toggleWithTriggerPressure();
|
||||
|
||||
|
||||
},
|
||||
|
||||
updateProps: function() {
|
||||
var gunProps = Entities.getEntityProperties(this.entityID, ['position', 'rotation']);
|
||||
this.position = gunProps.position;
|
||||
this.rotation = gunProps.rotation;
|
||||
this.firingDirection = Quat.getFront(this.rotation);
|
||||
var upVec = Quat.getUp(this.rotation);
|
||||
this.barrelPoint = Vec3.sum(this.position, Vec3.multiply(upVec, this.laserOffsets.y));
|
||||
this.laserTip = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.laserLength));
|
||||
this.barrelPoint = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.firingOffsets.z))
|
||||
var pickRay = {
|
||||
origin: this.barrelPoint,
|
||||
direction: this.firingDirection
|
||||
};
|
||||
},
|
||||
toggleWithTriggerPressure: function() {
|
||||
this.triggerValue = Controller.getValue(TRIGGER_CONTROLS[this.hand]);
|
||||
|
||||
if (this.triggerValue < RELOAD_THRESHOLD) {
|
||||
// print('RELOAD');
|
||||
this.canShoot = true;
|
||||
}
|
||||
if (this.canShoot === true && this.triggerValue === 1) {
|
||||
// print('SHOOT');
|
||||
this.fire();
|
||||
this.canShoot = false;
|
||||
}
|
||||
|
@ -91,17 +100,10 @@
|
|||
|
||||
},
|
||||
updateLaser: function() {
|
||||
var gunProps = Entities.getEntityProperties(this.entityID, ['position', 'rotation']);
|
||||
var position = gunProps.position;
|
||||
var rotation = gunProps.rotation;
|
||||
this.firingDirection = Quat.getFront(rotation);
|
||||
var upVec = Quat.getUp(rotation);
|
||||
this.barrelPoint = Vec3.sum(position, Vec3.multiply(upVec, this.laserOffsets.y));
|
||||
var laserTip = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.laserLength));
|
||||
this.barrelPoint = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.firingOffsets.z))
|
||||
|
||||
Overlays.editOverlay(this.laser, {
|
||||
start: this.barrelPoint,
|
||||
end: laserTip,
|
||||
end: this.laserTip,
|
||||
alpha: 1
|
||||
});
|
||||
},
|
||||
|
@ -114,19 +116,6 @@
|
|||
});
|
||||
},
|
||||
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
// this.initControllerMapping();
|
||||
this.laser = Overlays.addOverlay("line3d", {
|
||||
start: ZERO_VECTOR,
|
||||
end: ZERO_VECTOR,
|
||||
color: COLORS.RED,
|
||||
alpha: 1,
|
||||
visible: true,
|
||||
lineWidth: 2
|
||||
});
|
||||
},
|
||||
|
||||
triggerPress: function(hand, value) {
|
||||
if (this.hand === hand && value === 1) {
|
||||
//We are pulling trigger on the hand we have the gun in, so fire
|
||||
|
@ -135,15 +124,16 @@
|
|||
},
|
||||
|
||||
fire: function() {
|
||||
var pickRay = {
|
||||
origin: this.barrelPoint,
|
||||
direction: this.firingDirection
|
||||
};
|
||||
|
||||
Audio.playSound(this.fireSound, {
|
||||
position: this.barrelPoint,
|
||||
volume: this.fireVolume
|
||||
});
|
||||
|
||||
var pickRay = {
|
||||
origin: this.barrelPoint,
|
||||
direction: this.firingDirection
|
||||
};
|
||||
this.createGunFireEffect(this.barrelPoint)
|
||||
var intersection = Entities.findRayIntersectionBlocking(pickRay, true);
|
||||
if (intersection.intersects) {
|
||||
|
@ -170,11 +160,11 @@
|
|||
},
|
||||
|
||||
createEntityHitEffect: function(position) {
|
||||
var flash = Entities.addEntity({
|
||||
var sparks = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
position: position,
|
||||
lifetime: 4,
|
||||
"name": "Flash Emitter",
|
||||
"name": "Sparks Emitter",
|
||||
"color": {
|
||||
red: 228,
|
||||
green: 128,
|
||||
|
@ -228,7 +218,7 @@
|
|||
});
|
||||
|
||||
Script.setTimeout(function() {
|
||||
Entities.editEntity(flash, {
|
||||
Entities.editEntity(sparks, {
|
||||
isEmitting: false
|
||||
});
|
||||
}, 100);
|
||||
|
@ -261,11 +251,11 @@
|
|||
"z": 0
|
||||
},
|
||||
"accelerationSpread": {
|
||||
"x": .2,
|
||||
"x": 0.2,
|
||||
"y": 0,
|
||||
"z": .2
|
||||
"z": 0.2
|
||||
},
|
||||
"radiusSpread": .04,
|
||||
"radiusSpread": 0.04,
|
||||
"particleRadius": 0.07,
|
||||
"radiusStart": 0.07,
|
||||
"radiusFinish": 0.07,
|
||||
|
@ -282,11 +272,46 @@
|
|||
});
|
||||
}, 100);
|
||||
|
||||
var flash = Entities.addEntity({
|
||||
Entities.editEntity(this.flash, {
|
||||
isEmitting: true
|
||||
});
|
||||
Script.setTimeout(function() {
|
||||
Entities.editEntity(_this.flash, {
|
||||
isEmitting: false
|
||||
});
|
||||
}, 100)
|
||||
|
||||
},
|
||||
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
this.laser = Overlays.addOverlay("line3d", {
|
||||
start: ZERO_VECTOR,
|
||||
end: ZERO_VECTOR,
|
||||
color: COLORS.RED,
|
||||
alpha: 1,
|
||||
visible: true,
|
||||
lineWidth: 2
|
||||
});
|
||||
this.laserOffsets = {
|
||||
y: 0.095
|
||||
};
|
||||
this.firingOffsets = {
|
||||
z: 0.16
|
||||
}
|
||||
var gunProps = Entities.getEntityProperties(this.entityID, ['position', 'rotation']);
|
||||
var position = gunProps.position;
|
||||
var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0);
|
||||
this.firingDirection = Quat.getFront(rotation);
|
||||
var upVec = Quat.getUp(rotation);
|
||||
this.barrelPoint = Vec3.sum(position, Vec3.multiply(upVec, this.laserOffsets.y));
|
||||
this.barrelPoint = Vec3.sum(this.barrelPoint, Vec3.multiply(this.firingDirection, this.firingOffsets.z))
|
||||
|
||||
this.flash = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
position: position,
|
||||
lifetime: 4,
|
||||
position: this.barrelPoint,
|
||||
"name": "Muzzle Flash",
|
||||
isEmitting: false,
|
||||
"color": {
|
||||
red: 228,
|
||||
green: 128,
|
||||
|
@ -339,16 +364,13 @@
|
|||
"textures": "http://ericrius1.github.io/PartiArt/assets/star.png"
|
||||
});
|
||||
|
||||
Script.setTimeout(function() {
|
||||
Entities.editEntity(flash, {
|
||||
isEmitting: false
|
||||
});
|
||||
}, 100)
|
||||
|
||||
}
|
||||
Script.setTimeout(function() {
|
||||
Entities.editEntity(_this.flash, {parentID: _this.entityID});
|
||||
}, 500)
|
||||
|
||||
},
|
||||
};
|
||||
|
||||
// entity scripts always need to return a newly constructed object of our type
|
||||
return new Pistol();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3486,78 +3486,86 @@ namespace render {
|
|||
|
||||
// Background rendering decision
|
||||
auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage();
|
||||
if (skyStage->getBackgroundMode() == model::SunSkyStage::NO_BACKGROUND) {
|
||||
auto backgroundMode = skyStage->getBackgroundMode();
|
||||
|
||||
if (backgroundMode == model::SunSkyStage::NO_BACKGROUND) {
|
||||
// this line intentionally left blank
|
||||
} else if (skyStage->getBackgroundMode() == model::SunSkyStage::SKY_DOME) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Stars)) {
|
||||
PerformanceTimer perfTimer("stars");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::payloadRender<BackgroundRenderData>() ... stars...");
|
||||
// should be the first rendering pass - w/o depth buffer / lighting
|
||||
|
||||
// compute starfield alpha based on distance from atmosphere
|
||||
float alpha = 1.0f;
|
||||
bool hasStars = true;
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) {
|
||||
// TODO: handle this correctly for zones
|
||||
const EnvironmentData& closestData = background->_environment->getClosestData(args->_viewFrustum->getPosition()); // was theCamera instead of _viewFrustum
|
||||
|
||||
if (closestData.getHasStars()) {
|
||||
const float APPROXIMATE_DISTANCE_FROM_HORIZON = 0.1f;
|
||||
const float DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON = 0.2f;
|
||||
|
||||
glm::vec3 sunDirection = (args->_viewFrustum->getPosition()/*getAvatarPosition()*/ - closestData.getSunLocation())
|
||||
/ closestData.getAtmosphereOuterRadius();
|
||||
float height = glm::distance(args->_viewFrustum->getPosition()/*theCamera.getPosition()*/, closestData.getAtmosphereCenter());
|
||||
if (height < closestData.getAtmosphereInnerRadius()) {
|
||||
// If we're inside the atmosphere, then determine if our keyLight is below the horizon
|
||||
alpha = 0.0f;
|
||||
|
||||
if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) {
|
||||
float directionY = glm::clamp(sunDirection.y,
|
||||
-APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON)
|
||||
+ APPROXIMATE_DISTANCE_FROM_HORIZON;
|
||||
alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON);
|
||||
}
|
||||
|
||||
|
||||
} else if (height < closestData.getAtmosphereOuterRadius()) {
|
||||
alpha = (height - closestData.getAtmosphereInnerRadius()) /
|
||||
(closestData.getAtmosphereOuterRadius() - closestData.getAtmosphereInnerRadius());
|
||||
|
||||
if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) {
|
||||
float directionY = glm::clamp(sunDirection.y,
|
||||
-APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON)
|
||||
+ APPROXIMATE_DISTANCE_FROM_HORIZON;
|
||||
alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hasStars = false;
|
||||
}
|
||||
} else {
|
||||
if (backgroundMode == model::SunSkyStage::SKY_BOX) {
|
||||
auto skybox = skyStage->getSkybox();
|
||||
if (skybox && skybox->getCubemap() && skybox->getCubemap()->isDefined()) {
|
||||
PerformanceTimer perfTimer("skybox");
|
||||
skybox->render(batch, *(args->_viewFrustum));
|
||||
} else {
|
||||
// If no skybox texture is available, render the SKY_DOME while it loads
|
||||
backgroundMode = model::SunSkyStage::SKY_DOME;
|
||||
}
|
||||
|
||||
// finally render the starfield
|
||||
if (hasStars) {
|
||||
background->_stars.render(args, alpha);
|
||||
}
|
||||
|
||||
// draw the sky dome
|
||||
if (/*!selfAvatarOnly &&*/ Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) {
|
||||
PerformanceTimer perfTimer("atmosphere");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... atmosphere...");
|
||||
|
||||
background->_environment->renderAtmospheres(batch, *(args->_viewFrustum));
|
||||
}
|
||||
|
||||
}
|
||||
} else if (skyStage->getBackgroundMode() == model::SunSkyStage::SKY_BOX) {
|
||||
PerformanceTimer perfTimer("skybox");
|
||||
auto skybox = skyStage->getSkybox();
|
||||
if (skybox) {
|
||||
skybox->render(batch, *(args->_viewFrustum));
|
||||
if (backgroundMode == model::SunSkyStage::SKY_DOME) {
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Stars)) {
|
||||
PerformanceTimer perfTimer("stars");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::payloadRender<BackgroundRenderData>() ... stars...");
|
||||
// should be the first rendering pass - w/o depth buffer / lighting
|
||||
|
||||
// compute starfield alpha based on distance from atmosphere
|
||||
float alpha = 1.0f;
|
||||
bool hasStars = true;
|
||||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) {
|
||||
// TODO: handle this correctly for zones
|
||||
const EnvironmentData& closestData = background->_environment->getClosestData(args->_viewFrustum->getPosition()); // was theCamera instead of _viewFrustum
|
||||
|
||||
if (closestData.getHasStars()) {
|
||||
const float APPROXIMATE_DISTANCE_FROM_HORIZON = 0.1f;
|
||||
const float DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON = 0.2f;
|
||||
|
||||
glm::vec3 sunDirection = (args->_viewFrustum->getPosition()/*getAvatarPosition()*/ - closestData.getSunLocation())
|
||||
/ closestData.getAtmosphereOuterRadius();
|
||||
float height = glm::distance(args->_viewFrustum->getPosition()/*theCamera.getPosition()*/, closestData.getAtmosphereCenter());
|
||||
if (height < closestData.getAtmosphereInnerRadius()) {
|
||||
// If we're inside the atmosphere, then determine if our keyLight is below the horizon
|
||||
alpha = 0.0f;
|
||||
|
||||
if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) {
|
||||
float directionY = glm::clamp(sunDirection.y,
|
||||
-APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON)
|
||||
+ APPROXIMATE_DISTANCE_FROM_HORIZON;
|
||||
alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON);
|
||||
}
|
||||
|
||||
|
||||
} else if (height < closestData.getAtmosphereOuterRadius()) {
|
||||
alpha = (height - closestData.getAtmosphereInnerRadius()) /
|
||||
(closestData.getAtmosphereOuterRadius() - closestData.getAtmosphereInnerRadius());
|
||||
|
||||
if (sunDirection.y > -APPROXIMATE_DISTANCE_FROM_HORIZON) {
|
||||
float directionY = glm::clamp(sunDirection.y,
|
||||
-APPROXIMATE_DISTANCE_FROM_HORIZON, APPROXIMATE_DISTANCE_FROM_HORIZON)
|
||||
+ APPROXIMATE_DISTANCE_FROM_HORIZON;
|
||||
alpha = (directionY / DOUBLE_APPROXIMATE_DISTANCE_FROM_HORIZON);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
hasStars = false;
|
||||
}
|
||||
}
|
||||
|
||||
// finally render the starfield
|
||||
if (hasStars) {
|
||||
background->_stars.render(args, alpha);
|
||||
}
|
||||
|
||||
// draw the sky dome
|
||||
if (/*!selfAvatarOnly &&*/ Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) {
|
||||
PerformanceTimer perfTimer("atmosphere");
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||
"Application::displaySide() ... atmosphere...");
|
||||
|
||||
background->_environment->renderAtmospheres(batch, *(args->_viewFrustum));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -487,7 +487,8 @@ void EntityTreeRenderer::deleteReleasedModels() {
|
|||
}
|
||||
|
||||
RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
|
||||
bool precisionPicking, const QVector<EntityItemID>& entityIdsToInclude) {
|
||||
bool precisionPicking, const QVector<EntityItemID>& entityIdsToInclude,
|
||||
const QVector<EntityItemID>& entityIdsToDiscard) {
|
||||
RayToEntityIntersectionResult result;
|
||||
if (_tree) {
|
||||
EntityTreePointer entityTree = std::static_pointer_cast<EntityTree>(_tree);
|
||||
|
@ -495,7 +496,7 @@ RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(cons
|
|||
OctreeElementPointer element;
|
||||
EntityItemPointer intersectedEntity = NULL;
|
||||
result.intersects = entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance,
|
||||
result.face, result.surfaceNormal, entityIdsToInclude,
|
||||
result.face, result.surfaceNormal, entityIdsToInclude, entityIdsToDiscard,
|
||||
(void**)&intersectedEntity, lockType, &result.accurate,
|
||||
precisionPicking);
|
||||
if (result.intersects && intersectedEntity) {
|
||||
|
|
|
@ -130,7 +130,8 @@ private:
|
|||
|
||||
QList<Model*> _releasedModels;
|
||||
RayToEntityIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType,
|
||||
bool precisionPicking, const QVector<EntityItemID>& entityIdsToInclude = QVector<EntityItemID>());
|
||||
bool precisionPicking, const QVector<EntityItemID>& entityIdsToInclude = QVector<EntityItemID>(),
|
||||
const QVector<EntityItemID>& entityIdsToDiscard = QVector<EntityItemID>());
|
||||
|
||||
EntityItemID _currentHoverOverEntityID;
|
||||
EntityItemID _currentClickingOnEntityID;
|
||||
|
|
|
@ -141,6 +141,11 @@ void RenderablePolyLineEntityItem::updateVertices() {
|
|||
_vertices << v1 << v2;
|
||||
}
|
||||
|
||||
// Guard against an empty polyline
|
||||
if (finalIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// For last point we can assume binormals are the same since it represents the last two vertices of quad
|
||||
point = _points.at(finalIndex);
|
||||
v1 = point + binormal;
|
||||
|
|
|
@ -357,19 +357,21 @@ QVector<QUuid> EntityScriptingInterface::findEntitiesInBox(const glm::vec3& corn
|
|||
return result;
|
||||
}
|
||||
|
||||
RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking, const QScriptValue& entityIdsToInclude) {
|
||||
QVector<EntityItemID> entities = qVectorEntityItemIDFromScriptValue(entityIdsToInclude);
|
||||
return findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking, entities);
|
||||
RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersection(const PickRay& ray, bool precisionPicking, const QScriptValue& entityIdsToInclude, const QScriptValue& entityIdsToDiscard) {
|
||||
QVector<EntityItemID> entitiesToInclude = qVectorEntityItemIDFromScriptValue(entityIdsToInclude);
|
||||
QVector<EntityItemID> entitiesToDiscard = qVectorEntityItemIDFromScriptValue(entityIdsToDiscard);
|
||||
return findRayIntersectionWorker(ray, Octree::TryLock, precisionPicking, entitiesToInclude, entitiesToDiscard);
|
||||
}
|
||||
|
||||
RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking, const QScriptValue& entityIdsToInclude) {
|
||||
const QVector<EntityItemID>& entities = qVectorEntityItemIDFromScriptValue(entityIdsToInclude);
|
||||
return findRayIntersectionWorker(ray, Octree::Lock, precisionPicking, entities);
|
||||
RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking, const QScriptValue& entityIdsToInclude, const QScriptValue& entityIdsToDiscard) {
|
||||
const QVector<EntityItemID>& entitiesToInclude = qVectorEntityItemIDFromScriptValue(entityIdsToInclude);
|
||||
const QVector<EntityItemID> entitiesToDiscard = qVectorEntityItemIDFromScriptValue(entityIdsToDiscard);
|
||||
return findRayIntersectionWorker(ray, Octree::Lock, precisionPicking, entitiesToInclude, entitiesToDiscard);
|
||||
}
|
||||
|
||||
RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionWorker(const PickRay& ray,
|
||||
Octree::lockType lockType,
|
||||
bool precisionPicking, const QVector<EntityItemID>& entityIdsToInclude) {
|
||||
bool precisionPicking, const QVector<EntityItemID>& entityIdsToInclude, const QVector<EntityItemID>& entityIdsToDiscard) {
|
||||
|
||||
|
||||
RayToEntityIntersectionResult result;
|
||||
|
@ -377,7 +379,7 @@ RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionWorke
|
|||
OctreeElementPointer element;
|
||||
EntityItemPointer intersectedEntity = NULL;
|
||||
result.intersects = _entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face,
|
||||
result.surfaceNormal, entityIdsToInclude, (void**)&intersectedEntity, lockType, &result.accurate,
|
||||
result.surfaceNormal, entityIdsToInclude, entityIdsToDiscard, (void**)&intersectedEntity, lockType, &result.accurate,
|
||||
precisionPicking);
|
||||
if (result.intersects && intersectedEntity) {
|
||||
result.entityID = intersectedEntity->getEntityItemID();
|
||||
|
|
|
@ -112,11 +112,11 @@ public slots:
|
|||
/// If the scripting context has visible entities, this will determine a ray intersection, the results
|
||||
/// may be inaccurate if the engine is unable to access the visible entities, in which case result.accurate
|
||||
/// will be false.
|
||||
Q_INVOKABLE RayToEntityIntersectionResult findRayIntersection(const PickRay& ray, bool precisionPicking = false, const QScriptValue& entityIdsToInclude = QScriptValue());
|
||||
Q_INVOKABLE RayToEntityIntersectionResult findRayIntersection(const PickRay& ray, bool precisionPicking = false, const QScriptValue& entityIdsToInclude = QScriptValue(), const QScriptValue& entityIdsToDiscard = QScriptValue());
|
||||
|
||||
/// If the scripting context has visible entities, this will determine a ray intersection, and will block in
|
||||
/// order to return an accurate result
|
||||
Q_INVOKABLE RayToEntityIntersectionResult findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking = false, const QScriptValue& entityIdsToInclude = QScriptValue());
|
||||
Q_INVOKABLE RayToEntityIntersectionResult findRayIntersectionBlocking(const PickRay& ray, bool precisionPicking = false, const QScriptValue& entityIdsToInclude = QScriptValue(), const QScriptValue& entityIdsToDiscard = QScriptValue());
|
||||
|
||||
Q_INVOKABLE void setLightsArePickable(bool value);
|
||||
Q_INVOKABLE bool getLightsArePickable() const;
|
||||
|
@ -189,7 +189,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<EntityItemID>& entityIdsToInclude);
|
||||
bool precisionPicking, const QVector<EntityItemID>& entityIdsToInclude, const QVector<EntityItemID>& entityIdsToDiscard);
|
||||
|
||||
EntityTreePointer _entityTree;
|
||||
EntitiesScriptEngineProvider* _entitiesScriptEngine = nullptr;
|
||||
|
|
|
@ -498,6 +498,7 @@ public:
|
|||
BoxFace& face;
|
||||
glm::vec3& surfaceNormal;
|
||||
const QVector<EntityItemID>& entityIdsToInclude;
|
||||
const QVector<EntityItemID>& entityIdsToDiscard;
|
||||
void** intersectedObject;
|
||||
bool found;
|
||||
bool precisionPicking;
|
||||
|
@ -510,7 +511,7 @@ bool findRayIntersectionOp(OctreeElementPointer element, void* extraData) {
|
|||
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->entityIdsToDiscard, args->intersectedObject, args->precisionPicking)) {
|
||||
args->found = true;
|
||||
}
|
||||
return keepSearching;
|
||||
|
@ -518,9 +519,9 @@ bool findRayIntersectionOp(OctreeElementPointer element, void* extraData) {
|
|||
|
||||
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,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<EntityItemID>& entityIdsToInclude, const QVector<EntityItemID>& entityIdsToDiscard, void** intersectedObject,
|
||||
Octree::lockType lockType, bool* accurateResult, bool precisionPicking) {
|
||||
RayArgs args = { origin, direction, element, distance, face, surfaceNormal, entityIdsToInclude, intersectedObject, false, precisionPicking };
|
||||
RayArgs args = { origin, direction, element, distance, face, surfaceNormal, entityIdsToInclude, entityIdsToDiscard, intersectedObject, false, precisionPicking };
|
||||
distance = FLT_MAX;
|
||||
|
||||
bool requireLock = lockType == Octree::Lock;
|
||||
|
|
|
@ -84,6 +84,7 @@ public:
|
|||
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>(),
|
||||
const QVector<EntityItemID>& entityIdsToDiscard = QVector<EntityItemID>(),
|
||||
void** intersectedObject = NULL,
|
||||
Octree::lockType lockType = Octree::TryLock,
|
||||
bool* accurateResult = NULL,
|
||||
|
|
|
@ -475,8 +475,8 @@ bool EntityTreeElement::bestFitBounds(const glm::vec3& minPoint, const glm::vec3
|
|||
|
||||
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) {
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<EntityItemID>& entityIdsToInclude,
|
||||
const QVector<EntityItemID>& entityIdsToDiscard, void** intersectedObject, bool precisionPicking) {
|
||||
|
||||
keepSearching = true; // assume that we will continue searching after this.
|
||||
|
||||
|
@ -501,7 +501,7 @@ bool EntityTreeElement::findRayIntersection(const glm::vec3& origin, const glm::
|
|||
if (_cube.contains(origin) || distanceToElementCube < distance) {
|
||||
|
||||
if (findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails,
|
||||
face, localSurfaceNormal, entityIdsToInclude, intersectedObject, precisionPicking, distanceToElementCube)) {
|
||||
face, localSurfaceNormal, entityIdsToInclude, entityIdsToDiscard, intersectedObject, precisionPicking, distanceToElementCube)) {
|
||||
|
||||
if (distanceToElementDetails < distance) {
|
||||
distance = distanceToElementDetails;
|
||||
|
@ -516,13 +516,13 @@ bool EntityTreeElement::findRayIntersection(const glm::vec3& origin, const glm::
|
|||
|
||||
bool EntityTreeElement::findDetailedRayIntersection(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, float distanceToElementCube) {
|
||||
const QVector<EntityItemID>& entityIdsToInclude, const QVector<EntityItemID>& entityIDsToDiscard, 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;
|
||||
bool somethingIntersected = false;
|
||||
forEachEntity([&](EntityItemPointer entity) {
|
||||
if (entityIdsToInclude.size() > 0 && !entityIdsToInclude.contains(entity->getID())) {
|
||||
if ( (entityIdsToInclude.size() > 0 && !entityIdsToInclude.contains(entity->getID())) || (entityIDsToDiscard.size() > 0 && entityIDsToDiscard.contains(entity->getID())) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -144,11 +144,13 @@ public:
|
|||
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,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, const QVector<EntityItemID>& entityIdsToInclude,
|
||||
const QVector<EntityItemID>& entityIdsToDiscard,
|
||||
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<EntityItemID>& entityIdsToInclude,
|
||||
const QVector<EntityItemID>& entityIdsToDiscard,
|
||||
void** intersectedObject, bool precisionPicking, float distanceToElementCube);
|
||||
virtual bool findSpherePenetration(const glm::vec3& center, float radius,
|
||||
glm::vec3& penetration, void** penetratedObject) const;
|
||||
|
|
|
@ -96,7 +96,12 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
// Render
|
||||
gpu::TexturePointer skymap = skybox.getCubemap();
|
||||
// FIXME: skymap->isDefined may not be threadsafe
|
||||
assert(skymap && skymap->isDefined());
|
||||
|
||||
glm::mat4 projMat;
|
||||
viewFrustum.evalProjectionMatrix(projMat);
|
||||
|
||||
|
@ -106,11 +111,6 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
|
|||
batch.setViewTransform(viewTransform);
|
||||
batch.setModelTransform(Transform()); // only for Mac
|
||||
|
||||
gpu::TexturePointer skymap;
|
||||
if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
|
||||
skymap = skybox.getCubemap();
|
||||
}
|
||||
|
||||
batch.setPipeline(thePipeline);
|
||||
batch.setUniformBuffer(SKYBOX_CONSTANTS_SLOT, skybox._dataBuffer);
|
||||
batch.setResourceTexture(SKYBOX_SKYMAP_SLOT, skymap);
|
||||
|
@ -118,6 +118,5 @@ void Skybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const Sky
|
|||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
|
||||
batch.setResourceTexture(SKYBOX_SKYMAP_SLOT, nullptr);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -48,6 +48,10 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum,
|
|||
}
|
||||
|
||||
if (skybox._procedural && skybox._procedural->_enabled && skybox._procedural->ready()) {
|
||||
gpu::TexturePointer skymap = skybox.getCubemap();
|
||||
// FIXME: skymap->isDefined may not be threadsafe
|
||||
assert(skymap && skymap->isDefined());
|
||||
|
||||
glm::mat4 projMat;
|
||||
viewFrustum.evalProjectionMatrix(projMat);
|
||||
|
||||
|
@ -56,10 +60,7 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum,
|
|||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewTransform);
|
||||
batch.setModelTransform(Transform()); // only for Mac
|
||||
|
||||
if (skybox.getCubemap() && skybox.getCubemap()->isDefined()) {
|
||||
batch.setResourceTexture(0, skybox.getCubemap());
|
||||
}
|
||||
batch.setResourceTexture(0, skybox.getCubemap());
|
||||
|
||||
skybox._procedural->prepare(batch, glm::vec3(0), glm::vec3(1));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
|
|
|
@ -169,7 +169,7 @@
|
|||
}
|
||||
|
||||
function createRaveStick(position) {
|
||||
var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/raveStick.fbx";
|
||||
var modelURL = "http://hifi-content.s3.amazonaws.com/eric/models/raveStick.fbx";
|
||||
var stick = Entities.addEntity({
|
||||
type: "Model",
|
||||
name: "raveStick",
|
||||
|
@ -205,71 +205,6 @@
|
|||
}
|
||||
})
|
||||
});
|
||||
var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0)
|
||||
var forwardVec = Quat.getFront(Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0)));
|
||||
forwardVec = Vec3.normalize(forwardVec);
|
||||
var forwardQuat = orientationOf(forwardVec);
|
||||
position = Vec3.sum(position, Vec3.multiply(Quat.getFront(rotation), 0.1));
|
||||
position.z += 0.1;
|
||||
position.x += -0.035;
|
||||
var color = {
|
||||
red: 0,
|
||||
green: 200,
|
||||
blue: 40
|
||||
};
|
||||
var props = {
|
||||
type: "ParticleEffect",
|
||||
position: position,
|
||||
parentID: stick,
|
||||
isEmitting: true,
|
||||
name: "raveBeam",
|
||||
colorStart: color,
|
||||
colorSpread: {
|
||||
red: 200,
|
||||
green: 10,
|
||||
blue: 10
|
||||
},
|
||||
color: {
|
||||
red: 200,
|
||||
green: 200,
|
||||
blue: 255
|
||||
},
|
||||
colorFinish: color,
|
||||
maxParticles: 100000,
|
||||
lifespan: 1,
|
||||
emitRate: 1000,
|
||||
emitOrientation: forwardQuat,
|
||||
emitSpeed: 0.2,
|
||||
speedSpread: 0.0,
|
||||
polarStart: 0,
|
||||
polarFinish: 0.0,
|
||||
azimuthStart: 0.1,
|
||||
azimuthFinish: 0.01,
|
||||
emitAcceleration: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
accelerationSpread: {
|
||||
x: 0.00,
|
||||
y: 0.00,
|
||||
z: 0.00
|
||||
},
|
||||
radiusStart: 0.03,
|
||||
radiusFinish: 0.025,
|
||||
alpha: 0.7,
|
||||
alphaSpread:0.1,
|
||||
alphaStart: 0.5,
|
||||
alphaFinish: 0.5,
|
||||
textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png",
|
||||
emitterShouldTrail: false,
|
||||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true
|
||||
}
|
||||
})
|
||||
}
|
||||
var beam = Entities.addEntity(props);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -148,7 +148,7 @@ MasterReset = function() {
|
|||
}
|
||||
|
||||
function createRaveStick(position) {
|
||||
var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/raveStick.fbx";
|
||||
var modelURL = "http://hifi-content.s3.amazonaws.com/eric/models/raveStick.fbx";
|
||||
var stick = Entities.addEntity({
|
||||
type: "Model",
|
||||
name: "raveStick",
|
||||
|
@ -173,10 +173,15 @@ MasterReset = function() {
|
|||
},
|
||||
grabbableKey: {
|
||||
spatialKey: {
|
||||
relativePosition: {
|
||||
x: 0,
|
||||
rightRelativePosition: {
|
||||
x: 0.02,
|
||||
y: 0,
|
||||
z: -0.1
|
||||
z: 0
|
||||
},
|
||||
leftRelativePosition: {
|
||||
x: -0.02,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0)
|
||||
},
|
||||
|
@ -184,72 +189,6 @@ MasterReset = function() {
|
|||
}
|
||||
})
|
||||
});
|
||||
var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0)
|
||||
var forwardVec = Quat.getFront(Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0)));
|
||||
forwardVec = Vec3.normalize(forwardVec);
|
||||
var forwardQuat = orientationOf(forwardVec);
|
||||
position = Vec3.sum(position, Vec3.multiply(Quat.getFront(rotation), 0.1));
|
||||
position.z += 0.1;
|
||||
position.x += -0.035;
|
||||
var color = {
|
||||
red: 0,
|
||||
green: 200,
|
||||
blue: 40
|
||||
};
|
||||
var props = {
|
||||
type: "ParticleEffect",
|
||||
position: position,
|
||||
parentID: stick,
|
||||
isEmitting: true,
|
||||
name: "raveBeam",
|
||||
colorStart: color,
|
||||
colorSpread: {
|
||||
red: 200,
|
||||
green: 10,
|
||||
blue: 10
|
||||
},
|
||||
color: {
|
||||
red: 200,
|
||||
green: 200,
|
||||
blue: 255
|
||||
},
|
||||
colorFinish: color,
|
||||
maxParticles: 100000,
|
||||
lifespan: 1,
|
||||
emitRate: 1000,
|
||||
emitOrientation: forwardQuat,
|
||||
emitSpeed: 0.2,
|
||||
speedSpread: 0.0,
|
||||
polarStart: 0,
|
||||
polarFinish: 0.0,
|
||||
azimuthStart: 0.1,
|
||||
azimuthFinish: 0.01,
|
||||
emitAcceleration: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
accelerationSpread: {
|
||||
x: 0.00,
|
||||
y: 0.00,
|
||||
z: 0.00
|
||||
},
|
||||
radiusStart: 0.03,
|
||||
radiusFinish: 0.025,
|
||||
alpha: 0.7,
|
||||
alphaSpread: 0.1,
|
||||
alphaStart: 0.5,
|
||||
alphaFinish: 0.5,
|
||||
textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png",
|
||||
emitterShouldTrail: false,
|
||||
userData: JSON.stringify({
|
||||
resetMe: {
|
||||
resetMe: true
|
||||
}
|
||||
})
|
||||
}
|
||||
var beam = Entities.addEntity(props);
|
||||
|
||||
}
|
||||
|
||||
function createGun(position) {
|
||||
|
@ -283,10 +222,15 @@ MasterReset = function() {
|
|||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
spatialKey: {
|
||||
relativePosition: {
|
||||
x: 0,
|
||||
rightRelativePosition: {
|
||||
x: 0.02,
|
||||
y: 0,
|
||||
z: -0.1
|
||||
z: -0.03
|
||||
},
|
||||
leftRelativePosition: {
|
||||
x: -0.02,
|
||||
y: 0,
|
||||
z: -0.03
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(100, 90, 0)
|
||||
},
|
||||
|
@ -1136,9 +1080,9 @@ MasterReset = function() {
|
|||
grabbableKey: {
|
||||
spatialKey: {
|
||||
relativePosition: {
|
||||
x: -0.05,
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0.0
|
||||
z: 0.06
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(0,-90, -90)
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue