Merge branch 'master' of https://github.com/worklist/hifi into 20736

Conflicts:
	examples/controllers/handControllerGrab.js
This commit is contained in:
Thijs Wenker 2015-12-23 02:37:38 +01:00
commit 505f4ce7e4
51 changed files with 2165 additions and 330 deletions

View file

@ -197,6 +197,10 @@ if (WIN32)
add_paths_to_fixup_libs("${QT_DIR}/bin")
endif ()
if (NOT DEFINED SERVER_ONLY)
set(SERVER_ONLY 0)
endif()
# add subdirectories for all targets
if (NOT ANDROID)
add_subdirectory(assignment-client)
@ -205,14 +209,16 @@ if (NOT ANDROID)
set_target_properties(domain-server PROPERTIES FOLDER "Apps")
add_subdirectory(ice-server)
set_target_properties(ice-server PROPERTIES FOLDER "Apps")
add_subdirectory(interface)
set_target_properties(interface PROPERTIES FOLDER "Apps")
add_subdirectory(stack-manager)
set_target_properties(stack-manager PROPERTIES FOLDER "Apps")
add_subdirectory(tests)
add_subdirectory(plugins)
if (NOT SERVER_ONLY)
add_subdirectory(interface)
set_target_properties(interface PROPERTIES FOLDER "Apps")
add_subdirectory(tests)
add_subdirectory(plugins)
endif()
add_subdirectory(tools)
endif ()
endif()
if (ANDROID OR DESKTOP_GVR)
add_subdirectory(gvr-interface)

View file

@ -1,5 +1,4 @@
// handControllerGrab.js
// examples
//
// Created by Eric Levin on 9/2/15
// Additions by James B. Pollack @imgntn on 9/24/2015
@ -7,6 +6,7 @@
// Copyright 2015 High Fidelity, Inc.
//
// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects.
// Also supports touch and equipping objects.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
@ -14,7 +14,6 @@
Script.include("../libraries/utils.js");
//
// add lines where the hand ray picking is happening
//
@ -54,6 +53,7 @@ var LINE_ENTITY_DIMENSIONS = {
y: 1000,
z: 1000
};
var LINE_LENGTH = 500;
var PICK_MAX_DISTANCE = 500; // max length of pick-ray
@ -116,6 +116,17 @@ var DEFAULT_GRABBABLE_DATA = {
invertSolidWhileHeld: false
};
//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;
var USE_PARTICLE_BEAM_FOR_SEARCHING = true;
var USE_ENTITY_LINES_FOR_MOVING = false;
var USE_OVERLAY_LINES_FOR_MOVING = false;
var USE_PARTICLE_BEAM_FOR_MOVING = true;
var USE_SPOTLIGHT = false;
var USE_POINTLIGHT = false;
// states for the state machine
var STATE_OFF = 0;
@ -137,6 +148,7 @@ var STATE_WAITING_FOR_BUMPER_RELEASE = 15;
var STATE_EQUIP_SPRING = 16;
function stateToName(state) {
switch (state) {
case STATE_OFF:
@ -218,6 +230,7 @@ function getSpatialOffsetPosition(hand, spatialKey) {
}
var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y);
function getSpatialOffsetRotation(hand, spatialKey) {
var rotation = Quat.IDENTITY;
@ -261,7 +274,13 @@ function MyController(hand) {
this.triggerValue = 0; // rolling average of trigger value
this.rawTriggerValue = 0;
this.rawBumperValue = 0;
//for visualizations
this.overlayLine = null;
this.particleBeam = null;
//for lights
this.spotlight = null;
this.pointlight = null;
this.overlayLine = null;
this.ignoreIK = false;
@ -329,7 +348,7 @@ function MyController(hand) {
print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand);
}
this.state = newState;
}
};
this.debugLine = function(closePoint, farPoint, color) {
Entities.addEntity({
@ -349,7 +368,38 @@ function MyController(hand) {
}
})
});
};
this.lineOn = function(closePoint, farPoint, color) {
// draw a line
if (this.pointer === null) {
this.pointer = Entities.addEntity({
type: "Line",
name: "grab pointer",
dimensions: LINE_ENTITY_DIMENSIONS,
visible: true,
position: closePoint,
linePoints: [ZERO_VEC, farPoint],
color: color,
lifetime: LIFETIME,
collisionsWillMove: false,
ignoreForCollisions: true,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}
})
});
} else {
var age = Entities.getEntityProperties(this.pointer, "age").age;
this.pointer = Entities.editEntity(this.pointer, {
position: closePoint,
linePoints: [ZERO_VEC, farPoint],
color: color,
lifetime: age + LIFETIME
});
}
};
this.overlayLineOn = function(closePoint, farPoint, color) {
if (this.overlayLine === null) {
@ -376,36 +426,209 @@ function MyController(hand) {
alpha: 1
});
}
}
};
this.lineOn = function(closePoint, farPoint, color) {
// draw a line
if (this.pointer === null) {
this.pointer = Entities.addEntity({
type: "Line",
name: "grab pointer",
dimensions: LINE_ENTITY_DIMENSIONS,
visible: true,
position: closePoint,
linePoints: [ZERO_VEC, farPoint],
color: color,
lifetime: LIFETIME,
collisionsWillMove: false,
ignoreForCollisions: true,
userData: JSON.stringify({
grabbableKey: {
grabbable: false
}
})
});
this.handleParticleBeam = function(position, orientation, color) {
var rotation = Quat.angleAxis(0, {
x: 1,
y: 0,
z: 0
});
var finalRotation = Quat.multiply(orientation, rotation);
var lifespan = LINE_LENGTH / 10;
var speed = 5;
var spread = 2;
if (this.particleBeam === null) {
this.createParticleBeam(position, finalRotation, color, speed, spread, lifespan);
} else {
var age = Entities.getEntityProperties(this.pointer, "age").age;
this.pointer = Entities.editEntity(this.pointer, {
position: closePoint,
linePoints: [ZERO_VEC, farPoint],
this.updateParticleBeam(position, finalRotation, color, speed, spread, lifespan);
}
};
this.handleDistantParticleBeam = function(handPosition, objectPosition, color) {
var handToObject = Vec3.subtract(objectPosition, handPosition);
var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject);
var distance = Vec3.distance(handPosition, objectPosition);
var speed = 5;
var spread = 0;
var lifespan = distance / speed;
if (this.particleBeam === null) {
this.createParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan);
} else {
this.updateParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan);
}
};
this.createParticleBeam = function(position, orientation, color, speed, spread, lifespan) {
var particleBeamProperties = {
type: "ParticleEffect",
isEmitting: true,
position: position,
visible: false,
"name": "Particle Beam",
"color": color,
"maxParticles": 2000,
"lifespan": lifespan,
"emitRate": 50,
"emitSpeed": speed,
"speedSpread": spread,
"emitOrientation": {
"x": -1,
"y": 0,
"z": 0,
"w": 1
},
"emitDimensions": {
"x": 0,
"y": 0,
"z": 0
},
"emitRadiusStart": 0.5,
"polarStart": 0,
"polarFinish": 0,
"azimuthStart": -3.1415927410125732,
"azimuthFinish": 3.1415927410125732,
"emitAcceleration": {
x: 0,
y: 0,
z: 0
},
"accelerationSpread": {
"x": 0,
"y": 0,
"z": 0
},
"particleRadius": 0.015,
"radiusSpread": 0.005,
// "radiusStart": 0.01,
// "radiusFinish": 0.01,
// "colorSpread": {
// "red": 0,
// "green": 0,
// "blue": 0
// },
// "colorStart": color,
// "colorFinish": color,
"alpha": 1,
"alphaSpread": 0,
"alphaStart": 1,
"alphaFinish": 1,
"additiveBlending": 0,
"textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png"
}
this.particleBeam = Entities.addEntity(particleBeamProperties);
};
this.updateParticleBeam = function(position, orientation, color, speed, spread, lifespan) {
Entities.editEntity(this.particleBeam, {
rotation: orientation,
position: position,
visible: true,
color: color,
lifetime: age + LIFETIME
emitSpeed: speed,
speedSpread: spread,
lifespan: lifespan
})
};
this.evalLightWorldTransform = function(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)
};
};
this.handleSpotlight = function(parentID, position) {
var LIFETIME = 100;
var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']);
var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation);
var lightProperties = {
type: "Light",
isSpotlight: true,
dimensions: {
x: 2,
y: 2,
z: 20
},
parentID: parentID,
color: {
red: 255,
green: 255,
blue: 255
},
intensity: 2,
exponent: 0.3,
cutoff: 20,
lifetime: LIFETIME,
position: lightTransform.p,
};
if (this.spotlight === null) {
this.spotlight = Entities.addEntity(lightProperties);
} else {
Entities.editEntity(this.spotlight, {
//without this, this light would maintain rotation with its parent
rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0),
})
}
};
this.handlePointLight = function(parentID, position) {
var LIFETIME = 100;
var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']);
var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation);
var lightProperties = {
type: "Light",
isSpotlight: false,
dimensions: {
x: 2,
y: 2,
z: 20
},
parentID: parentID,
color: {
red: 255,
green: 255,
blue: 255
},
intensity: 2,
exponent: 0.3,
cutoff: 20,
lifetime: LIFETIME,
position: lightTransform.p,
};
if (this.pointlight === null) {
this.pointlight = Entities.addEntity(lightProperties);
} else {
}
};
@ -423,6 +646,41 @@ function MyController(hand) {
this.overlayLine = null;
};
this.particleBeamOff = function() {
if (this.particleBeam !== null) {
Entities.editEntity(this.particleBeam, {
visible: false
})
}
}
this.turnLightsOff = function() {
if (this.spotlight !== null) {
Entities.deleteEntity(this.spotlight);
this.spotlight = null;
}
if (this.pointlight !== null) {
Entities.deleteEntity(this.pointlight);
this.pointlight = null;
}
};
this.turnOffVisualizations = function() {
if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) {
this.lineOff();
}
if (USE_OVERLAY_LINES_FOR_SEARCHING === true || USE_OVERLAY_LINES_FOR_MOVING === true) {
this.overlayLineOff();
}
if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) {
this.particleBeamOff();
}
};
this.triggerPress = function(value) {
_this.rawTriggerValue = value;
};
@ -431,7 +689,6 @@ function MyController(hand) {
_this.rawBumperValue = value;
};
this.updateSmoothedTrigger = function() {
var triggerValue = this.rawTriggerValue;
// smooth out trigger value
@ -454,12 +711,11 @@ function MyController(hand) {
this.bumperSqueezed = function() {
return _this.rawBumperValue > BUMPER_ON_VALUE;
}
};
this.bumperReleased = function() {
return _this.rawBumperValue < BUMPER_ON_VALUE;
}
};
this.off = function() {
if (this.triggerSmoothedSqueezed()) {
@ -472,7 +728,7 @@ function MyController(hand) {
this.setState(STATE_EQUIP_SEARCHING);
return;
}
}
};
this.search = function() {
this.grabbedEntity = null;
@ -671,8 +927,19 @@ function MyController(hand) {
}
}
//this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
//search line visualizations
if (USE_ENTITY_LINES_FOR_SEARCHING === true) {
this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
}
if (USE_OVERLAY_LINES_FOR_SEARCHING === true) {
this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR);
}
if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) {
this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR);
}
};
this.distanceHolding = function() {
@ -725,7 +992,7 @@ function MyController(hand) {
this.currentAvatarPosition = MyAvatar.position;
this.currentAvatarOrientation = MyAvatar.orientation;
this.overlayLineOff();
this.turnOffVisualizations();
};
this.continueDistanceHolding = function() {
@ -751,7 +1018,6 @@ function MyController(hand) {
return;
}
this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR);
// the action was set up on a previous call. update the targets.
var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) *
@ -815,17 +1081,43 @@ 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 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);
}
//visualizations
if (USE_ENTITY_LINES_FOR_MOVING === true) {
this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR);
}
if (USE_OVERLAY_LINES_FOR_MOVING === true) {
this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR);
}
if (USE_PARTICLE_BEAM_FOR_MOVING === true) {
this.handleDistantParticleBeam(handPosition, grabbedProperties.position, INTERSECT_COLOR)
// this.handleDistantParticleBeam(handPosition, this.currentObjectPosition, INTERSECT_COLOR)
}
if (USE_POINTLIGHT === true) {
this.handlePointLight(this.grabbedEntity);
}
if (USE_SPOTLIGHT === true) {
this.handleSpotlight(this.grabbedEntity);
}
Entities.updateAction(this.grabbedEntity, this.actionID, {
targetPosition: this.currentObjectPosition,
linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
@ -833,6 +1125,7 @@ function MyController(hand) {
angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
ttl: ACTION_TTL
});
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
};
@ -846,8 +1139,7 @@ function MyController(hand) {
return;
}
this.lineOff();
this.overlayLineOff();
this.turnOffVisualizations();
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
this.activateEntity(this.grabbedEntity, grabbedProperties);
@ -861,20 +1153,25 @@ function MyController(hand) {
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);
} else {
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;
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);
}
@ -988,8 +1285,8 @@ function MyController(hand) {
};
this.pullTowardEquipPosition = function() {
this.lineOff();
this.overlayLineOff();
this.turnOffVisualizations();
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
@ -1107,11 +1404,15 @@ function MyController(hand) {
}
}
if (USE_ENTITY_LINES_FOR_MOVING === true) {
this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
}
Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger");
};
_this.allTouchedIDs = {};
this.touchTest = function() {
var maxDistance = 0.05;
var leftHandPosition = MyAvatar.getLeftPalmPosition();
@ -1180,8 +1481,9 @@ function MyController(hand) {
this.release = function() {
this.lineOff();
this.overlayLineOff();
this.turnLightsOff();
this.turnOffVisualizations();
if (this.grabbedEntity !== null) {
if (this.actionID !== null) {
Entities.deleteAction(this.grabbedEntity, this.actionID);
@ -1198,6 +1500,9 @@ function MyController(hand) {
this.cleanup = function() {
this.release();
this.endHandGrasp();
Entities.deleteEntity(this.particleBeam);
Entities.deleteEntity(this.spotLight);
Entities.deleteEntity(this.pointLight);
};
this.activateEntity = function(entityID, grabbedProperties) {
@ -1268,27 +1573,34 @@ function MyController(hand) {
}
//return an object with our updated settings
return result;
}
};
this.graspHandler = null
this.startHandGrasp = function() {
if (this.hand === RIGHT_HAND) {
this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']);
} else if (this.hand === LEFT_HAND) {
this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']);
}
}
};
this.endHandGrasp = function() {
// Tell the animation system we don't need any more callbacks.
MyAvatar.removeAnimationStateHandler(this.graspHandler);
}
};
}
};
var rightController = new MyController(RIGHT_HAND);
var leftController = new MyController(LEFT_HAND);
//preload the particle beams so that they are full length when you start searching
if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) {
rightController.createParticleBeam();
leftController.createParticleBeam();
}
var MAPPING_NAME = "com.highfidelity.handControllerGrab";
var mapping = Controller.newMapping(MAPPING_NAME);
@ -1300,13 +1612,14 @@ mapping.from([Controller.Standard.LB]).peek().to(leftController.bumperPress);
Controller.enableMapping(MAPPING_NAME);
//the section below allows the grab script to listen for messages that disable either one or both hands. useful for two handed items
var handToDisable = 'none';
function update() {
if (handToDisable !== LEFT_HAND && handToDisable!=='both') {
leftController.update();
}
if (handToDisable !== RIGHT_HAND && handToDisable!=='both') {
if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') {
rightController.update();
}
}
@ -1348,4 +1661,4 @@ function cleanup() {
}
Script.scriptEnding.connect(cleanup);
Script.update.connect(update);
Script.update.connect(update);

View file

@ -9,8 +9,6 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var whichHand = Controller.Standard.RightHand;
var whichTrigger = Controller.Standard.RT;
var DEBUGGING = false;
Math.clamp=function(a,b,c) {
@ -34,14 +32,14 @@ function moveReticleAbsolute(x, y) {
// some debugging to see if position is jumping around on us...
var distanceSinceLastMove = length(lastPos, globalPos);
if (distanceSinceLastMove > EXPECTED_CHANGE) {
print("------------------ distanceSinceLastMove:" + distanceSinceLastMove + "----------------------------");
debugPrint("------------------ distanceSinceLastMove:" + distanceSinceLastMove + "----------------------------");
}
if (Math.abs(dX) > EXPECTED_CHANGE) {
print("surpressing unexpectedly large change dX:" + dX + "----------------------------");
debugPrint("surpressing unexpectedly large change dX:" + dX + "----------------------------");
}
if (Math.abs(dY) > EXPECTED_CHANGE) {
print("surpressing unexpectedly large change dY:" + dY + "----------------------------");
debugPrint("surpressing unexpectedly large change dY:" + dY + "----------------------------");
}
globalPos.x = x;
@ -53,14 +51,165 @@ function moveReticleAbsolute(x, y) {
var MAPPING_NAME = "com.highfidelity.testing.reticleWithHandRotation";
var mapping = Controller.newMapping(MAPPING_NAME);
mapping.from(whichTrigger).peek().constrainToInteger().to(Controller.Actions.ReticleClick);
mapping.from(whichHand).peek().to(function(pose) {
mapping.from(Controller.Standard.LT).peek().constrainToInteger().to(Controller.Actions.ReticleClick);
mapping.from(Controller.Standard.RT).peek().constrainToInteger().to(Controller.Actions.ReticleClick);
mapping.enable();
var lastRotatedLeft = Vec3.UNIT_NEG_Y;
var lastRotatedRight = Vec3.UNIT_NEG_Y;
function debugPrint(message) {
if (DEBUGGING) {
print(message);
}
}
var MAX_WAKE_UP_DISTANCE = 0.005;
var MIN_WAKE_UP_DISTANCE = 0.001;
var INITIAL_WAKE_UP_DISTANCE = MIN_WAKE_UP_DISTANCE;
var INCREMENTAL_WAKE_UP_DISTANCE = 0.001;
var MAX_SLEEP_DISTANCE = 0.0004;
var MIN_SLEEP_DISTANCE = 0.00001; //0.00002;
var INITIAL_SLEEP_DISTANCE = MIN_SLEEP_DISTANCE;
var INCREMENTAL_SLEEP_DISTANCE = 0.000002; // 0.00002;
var leftAsleep = true;
var rightAsleep = true;
var leftWakeUpDistance = INITIAL_WAKE_UP_DISTANCE;
var rightWakeUpDistance = INITIAL_WAKE_UP_DISTANCE;
var leftSleepDistance = INITIAL_SLEEP_DISTANCE;
var rightSleepDistance = INITIAL_SLEEP_DISTANCE;
Script.update.connect(function(deltaTime) {
var poseRight = Controller.getPoseValue(Controller.Standard.RightHand);
var poseLeft = Controller.getPoseValue(Controller.Standard.LeftHand);
// NOTE: hack for now
var screenSizeX = 1920;
var screenSizeY = 1080;
var rotated = Vec3.multiplyQbyV(pose.rotation, Vec3.UNIT_NEG_Y); //
var rotatedRight = Vec3.multiplyQbyV(poseRight.rotation, Vec3.UNIT_NEG_Y);
var rotatedLeft = Vec3.multiplyQbyV(poseLeft.rotation, Vec3.UNIT_NEG_Y);
var suppressRight = false;
var suppressLeft = false;
// What I really want to do is to slowly increase the epsilon you have to move it
// to wake up, the longer you go without moving it
var leftDistance = Vec3.distance(rotatedLeft, lastRotatedLeft);
var rightDistance = Vec3.distance(rotatedRight, lastRotatedRight);
// check to see if hand should wakeup or sleep
if (leftAsleep) {
if (leftDistance > leftWakeUpDistance) {
leftAsleep = false;
leftSleepDistance = INITIAL_SLEEP_DISTANCE;
leftWakeUpDistance = INITIAL_WAKE_UP_DISTANCE;
} else {
// grow the wake up distance to make it harder to wake up
leftWakeUpDistance = Math.min(leftWakeUpDistance + INCREMENTAL_WAKE_UP_DISTANCE, MAX_WAKE_UP_DISTANCE);
}
} else {
// we are awake, determine if we should fall asleep, if we haven't moved
// at least as much as our sleep distance then we sleep
if (leftDistance < leftSleepDistance) {
leftAsleep = true;
leftSleepDistance = INITIAL_SLEEP_DISTANCE;
leftWakeUpDistance = INITIAL_WAKE_UP_DISTANCE;
} else {
// if we moved more than the sleep amount, but we moved less than the max sleep
// amount, then increase our liklihood of sleep.
if (leftDistance < MAX_SLEEP_DISTANCE) {
print("growing sleep....");
leftSleepDistance = Math.max(leftSleepDistance + INCREMENTAL_SLEEP_DISTANCE, MAX_SLEEP_DISTANCE);
} else {
// otherwise reset it to initial
leftSleepDistance = INITIAL_SLEEP_DISTANCE;
}
}
}
if (leftAsleep) {
suppressLeft = true;
debugPrint("suppressing left not moving enough");
}
// check to see if hand should wakeup or sleep
if (rightAsleep) {
if (rightDistance > rightWakeUpDistance) {
rightAsleep = false;
rightSleepDistance = INITIAL_SLEEP_DISTANCE;
rightWakeUpDistance = INITIAL_WAKE_UP_DISTANCE;
} else {
// grow the wake up distance to make it harder to wake up
rightWakeUpDistance = Math.min(rightWakeUpDistance + INCREMENTAL_WAKE_UP_DISTANCE, MAX_WAKE_UP_DISTANCE);
}
} else {
// we are awake, determine if we should fall asleep, if we haven't moved
// at least as much as our sleep distance then we sleep
if (rightDistance < rightSleepDistance) {
rightAsleep = true;
rightSleepDistance = INITIAL_SLEEP_DISTANCE;
rightWakeUpDistance = INITIAL_WAKE_UP_DISTANCE;
} else {
// if we moved more than the sleep amount, but we moved less than the max sleep
// amount, then increase our liklihood of sleep.
if (rightDistance < MAX_SLEEP_DISTANCE) {
print("growing sleep....");
rightSleepDistance = Math.max(rightSleepDistance + INCREMENTAL_SLEEP_DISTANCE, MAX_SLEEP_DISTANCE);
} else {
// otherwise reset it to initial
rightSleepDistance = INITIAL_SLEEP_DISTANCE;
}
}
}
if (rightAsleep) {
suppressRight = true;
debugPrint("suppressing right not moving enough");
}
// check to see if hand is on base station
if (Vec3.equal(rotatedLeft, Vec3.UNIT_NEG_Y)) {
suppressLeft = true;
debugPrint("suppressing left on base station");
}
if (Vec3.equal(rotatedRight, Vec3.UNIT_NEG_Y)) {
suppressRight = true;
debugPrint("suppressing right on base station");
}
// Keep track of last rotations, to detect resting (but not on base station hands) in the future
lastRotatedLeft = rotatedLeft;
lastRotatedRight = rotatedRight;
if (suppressLeft && suppressRight) {
debugPrint("both hands suppressed bail out early");
return;
}
if (suppressLeft) {
debugPrint("right only");
rotatedLeft = rotatedRight;
}
if (suppressRight) {
debugPrint("left only");
rotatedRight = rotatedLeft;
}
// Average the two hand positions, if either hand is on base station, the
// other hand becomes the only used hand and the average is the hand in use
var rotated = Vec3.multiply(Vec3.sum(rotatedRight,rotatedLeft), 0.5);
if (DEBUGGING) {
Vec3.print("rotatedRight:", rotatedRight);
Vec3.print("rotatedLeft:", rotatedLeft);
Vec3.print("rotated:", rotated);
}
var absolutePitch = rotated.y; // from 1 down to -1 up ... but note: if you rotate down "too far" it starts to go up again...
var absoluteYaw = -rotated.x; // from -1 left to 1 right
@ -97,7 +246,6 @@ mapping.from(whichHand).peek().to(function(pose) {
moveReticleAbsolute(x, y);
}
});
mapping.enable();
Script.scriptEnding.connect(function(){
mapping.disable();

View file

@ -0,0 +1,145 @@
//
// arcBall.js
// examples/arcBall
//
// Created by Eric Levin on 12/17/15.
// Copyright 2015 High Fidelity, Inc.
//
// This script creats a particle light ball which makes particle trails as you 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
//
Script.include("../../libraries/utils.js");
var scriptURL = Script.resolvePath("arcBallEntityScript.js?v1" + Math.random());
ArcBall = function(spawnPosition) {
var colorPalette = [{
red: 25,
green: 20,
blue: 162
}];
var containerBall = Entities.addEntity({
type: "Sphere",
name: "Arc Ball",
script: scriptURL,
position: Vec3.sum(spawnPosition, {
x: 0,
y: .7,
z: 0
}),
dimensions: {
x: .05,
y: .05,
z: .05
},
color: {
red: 100,
green: 10,
blue: 150
},
ignoreForCollisions: true,
damping: 0.8,
collisionsWillMove: true,
userData: JSON.stringify({
grabbableKey: {
spatialKey: {
// relativePosition: {
// x: 0,
// y: -0.5,
// z: 0.0
// },
},
// invertSolidWhileHeld: true
}
})
});
var light = Entities.addEntity({
type: 'Light',
name: "ballLight",
parentID: containerBall,
dimensions: {
x: 30,
y: 30,
z: 30
},
color: colorPalette[randInt(0, colorPalette.length)],
intensity: 5
});
var arcBall = Entities.addEntity({
type: "ParticleEffect",
parentID: containerBall,
isEmitting: true,
name: "Arc Ball Particle Effect",
colorStart: {
red: 200,
green: 20,
blue: 40
},
color: {
red: 200,
green: 200,
blue: 255
},
colorFinish: {
red: 25,
green: 20,
blue: 255
},
maxParticles: 100000,
lifespan: 2,
emitRate: 400,
emitSpeed: .1,
lifetime: -1,
speedSpread: 0.0,
emitDimensions: {
x: 0,
y: 0,
z: 0
},
polarStart: 0,
polarFinish: Math.PI,
azimuthStart: -Math.PI,
azimuthFinish: Math.PI,
emitAcceleration: {
x: 0,
y: 0,
z: 0
},
accelerationSpread: {
x: .00,
y: .00,
z: .00
},
particleRadius: 0.02,
radiusSpread: 0,
radiusStart: 0.03,
radiusFinish: 0.0003,
alpha: 0,
alphaSpread: .5,
alphaStart: 0,
alphaFinish: 0.5,
textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png",
emitterShouldTrail: true
})
function cleanup() {
Entities.deleteEntity(arcBall);
Entities.deleteEntity(containerBall);
Entities.deleteEntity(light);
}
this.cleanup = cleanup;
}

View file

@ -0,0 +1,155 @@
// arcBallEntityScript.js
//
// Script Type: Entity
// Created by Eric Levin on 12/17/15.
// Copyright 2015 High Fidelity, Inc.
//
// This entity script handles the logic for the arcBall rave toy
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
(function() {
Script.include("../../libraries/utils.js");
var _this;
var ArcBall = function() {
_this = this;
this.colorPalette = [{
red: 25,
green: 20,
blue: 162
}, {
red: 200,
green: 10,
blue: 10
}];
this.searchRadius = 10;
};
ArcBall.prototype = {
isGrabbed: false,
startDistantGrab: function() {
this.searchForNearbyArcBalls();
},
startNearGrab: function() {
this.searchForNearbyArcBalls();
},
searchForNearbyArcBalls: function() {
//Search for nearby balls and create an arc to it if one is found
var position = Entities.getEntityProperties(this.entityID, "position").position
var entities = Entities.findEntities(position, this.searchRadius);
entities.forEach(function(entity) {
var props = Entities.getEntityProperties(entity, ["position", "name"]);
if (props.name === "Arc Ball" && JSON.stringify(_this.entityID) !== JSON.stringify(entity)) {
_this.target = entity;
_this.createBeam(position, props.position);
}
});
},
createBeam: function(startPosition, endPosition) {
// Creates particle arc from start position to end position
var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation;
var sourceToTargetVec = Vec3.subtract(endPosition, startPosition);
var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec);
emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation);
var color = this.colorPalette[randInt(0, this.colorPalette.length)];
var props = {
type: "ParticleEffect",
name: "Particle Arc",
parentID: this.entityID,
parentJointIndex: -1,
// position: startPosition,
isEmitting: true,
colorStart: color,
color: {
red: 200,
green: 200,
blue: 255
},
colorFinish: color,
maxParticles: 100000,
lifespan: 1,
emitRate: 1000,
emitOrientation: emitOrientation,
emitSpeed: 1,
speedSpread: 0.02,
emitDimensions: {
x: .01,
y: .01,
z: .01
},
polarStart: 0,
polarFinish: 0,
azimuthStart: 0.02,
azimuthFinish: .01,
emitAcceleration: {
x: 0,
y: 0,
z: 0
},
accelerationSpread: {
x: 0,
y: 0,
z: 0
},
radiusStart: 0.01,
radiusFinish: 0.005,
radiusSpread: 0.005,
alpha: 0.5,
alphaSpread: 0.1,
alphaStart: 0.5,
alphaFinish: 0.5,
textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png",
emitterShouldTrail: true
}
this.particleArc = Entities.addEntity(props);
},
updateBeam: function() {
if(!this.target) {
return;
}
var startPosition = Entities.getEntityProperties(this.entityID, "position").position;
var targetPosition = Entities.getEntityProperties(this.target, "position").position;
var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation;
var sourceToTargetVec = Vec3.subtract(targetPosition, startPosition);
var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec);
Entities.editEntity(this.particleArc, {
emitOrientation: emitOrientation
});
},
continueNearGrab: function() {
this.updateBeam();
},
continueDistantGrab: function() {
this.updateBeam();
},
releaseGrab: function() {
Entities.editEntity(this.particleArc, {
isEmitting: false
});
this.target = null;
},
unload: function() {
if (this.particleArc) {
Entities.deleteEntity(this.particleArc);
}
},
preload: function(entityID) {
this.entityID = entityID;
},
};
return new ArcBall();
});

View file

@ -0,0 +1,91 @@
//
// flowArtsHutSpawner.js
// examples/flowArts
//
// Created by Eric Levin on 12/17/15.
// Copyright 2015 High Fidelity, Inc.
//
// This script creates a special flow arts hut with a bunch of flow art toys people can go in and play with
//
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../../libraries/utils.js");
Script.include("lightBall/lightBall.js");
Script.include("raveStick/raveStick.js");
Script.include("lightSaber/lightSaber.js");
Script.include("arcBall/arcBall.js");
var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation())));
basePosition.y = MyAvatar.position.y + 1;
// RAVE ITEMS
// var lightBall = new LightBall(basePosition);
var arcBall = new ArcBall(basePosition);
var arcBall2 = new ArcBall(Vec3.sum(basePosition, {x: -1, y: 0, z: 0}));
var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1}));
var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1}));
var modelURL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/RaveRoom.fbx";
var roomDimensions = {x: 30.58, y: 15.29, z: 30.58};
var raveRoom = Entities.addEntity({
type: "Model",
name: "Rave Hut Room",
modelURL: modelURL,
position: basePosition,
dimensions:roomDimensions,
visible: true
});
var floor = Entities.addEntity({
type: "Box",
name: "Rave Floor",
position: Vec3.sum(basePosition, {x: 0, y: -1.2, z: 0}),
dimensions: {x: roomDimensions.x, y: 0.6, z: roomDimensions.z},
color: {red: 50, green: 10, blue: 100},
shapeType: 'box'
});
var lightZone = Entities.addEntity({
type: "Zone",
name: "Rave Hut Zone",
shapeType: 'box',
keyLightIntensity: 0.4,
keyLightColor: {
red: 50,
green: 0,
blue: 50
},
keyLightAmbientIntensity: .2,
position: MyAvatar.position,
dimensions: {
x: 100,
y: 100,
z: 100
}
});
function cleanup() {
Entities.deleteEntity(raveRoom);
Entities.deleteEntity(lightZone);
Entities.deleteEntity(floor);
// lightBall.cleanup();
arcBall.cleanup();
arcBall2.cleanup();
raveStick.cleanup();
lightSaber.cleanup();
}
Script.scriptEnding.connect(cleanup);

View file

@ -0,0 +1,145 @@
//
// LightBall.js
// examples/lightBall
//
// Created by Eric Levin on 12/17/15.
// Copyright 2014 High Fidelity, Inc.
//
// This script creats a particle light ball which makes particle trails as you 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
//
Script.include("../../libraries/utils.js");
LightBall = function(spawnPosition) {
var colorPalette = [{
red: 25,
green: 20,
blue: 162
}];
var containerBall = Entities.addEntity({
type: "Sphere",
name: "containerBall",
position: Vec3.sum(spawnPosition, {
x: 0,
y: 0.5,
z: 0
}),
dimensions: {
x: 0.1,
y: 0.1,
z: 0.1
},
color: {
red: 15,
green: 10,
blue: 150
},
collisionsWillMove: true,
// gravity: {
// x: 0,
// y: -0.5,
// z: 0
// },
userData: JSON.stringify({
grabbableKey: {
spatialKey: {
relativePosition: {
x: 0,
y: 0.1,
z: 0
}
},
invertSolidWhileHeld: true
}
})
});
var light = Entities.addEntity({
type: 'Light',
name: "ballLight",
parentID: containerBall,
dimensions: {
x: 30,
y: 30,
z: 30
},
color: colorPalette[randInt(0, colorPalette.length)],
intensity: 5
});
var lightBall = Entities.addEntity({
type: "ParticleEffect",
parentID: containerBall,
isEmitting: true,
name: "particleBall",
colorStart: {
red: 200,
green: 20,
blue: 40
},
color: {
red: 200,
green: 200,
blue: 255
},
colorFinish: {
red: 25,
green: 20,
blue: 255
},
maxParticles: 100000,
lifespan: 2,
emitRate: 10000,
emitSpeed: 0.1,
lifetime: -1,
speedSpread: 0.0,
emitDimensions: {
x: 0,
y: 0,
z: 0
},
polarStart: 0,
polarFinish: Math.PI,
azimuthStart: -Math.PI,
azimuthFinish: Math.PI,
emitAcceleration: {
x: 0,
y: 0,
z: 0
},
accelerationSpread: {
x: 0.00,
y: 0.00,
z: 0.00
},
particleRadius: 0.02,
radiusSpread: 0,
radiusStart: 0.03,
radiusFinish: 0.0003,
alpha: 0,
alphaSpread: 0.5,
alphaStart: 0,
alphaFinish: 0.5,
textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png",
emitterShouldTrail: true
})
function cleanup() {
Entities.deleteEntity(lightBall);
Entities.deleteEntity(containerBall);
Entities.deleteEntity(light);
}
this.cleanup = cleanup;
}

View file

@ -0,0 +1,67 @@
//
// LightSaber.js
// examples
//
// Created by Eric Levin on 12/17/15.
// Copyright 2015 High Fidelity, Inc.
//
// This script creates a lightsaber which activates on grab
//
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../../libraries/utils.js");
var modelURL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/lightSaber.fbx";
var scriptURL = Script.resolvePath("lightSaberEntityScript.js");
LightSaber = function(spawnPosition) {
var saberHandle = Entities.addEntity({
type: "Model",
name: "LightSaber Handle",
modelURL: modelURL,
position: spawnPosition,
shapeType: 'box',
collisionsWillMove: true,
script: scriptURL,
dimensions: {
x: 0.06,
y: 0.06,
z: 0.31
},
userData: JSON.stringify({
grabbableKey: {
spatialKey: {
relativePosition: {
x: 0,
y: 0,
z: -0.1
},
relativeRotation: Quat.fromPitchYawRollDegrees(180, 90, 0)
},
invertSolidWhileHeld: true
}
})
});
var light = Entities.addEntity({
type: 'Light',
name: "raveLight",
parentID: saberHandle,
dimensions: {
x: 30,
y: 30,
z: 30
},
color: {red: 200, green: 10, blue: 200},
intensity: 5
});
function cleanup() {
Entities.deleteEntity(saberHandle);
}
this.cleanup = cleanup;
}

View file

@ -0,0 +1,116 @@
// lightSaberEntityScript.js
//
// Script Type: Entity
// Created by Eric Levin on 12/17/15.
// Copyright 2015 High Fidelity, Inc.
//
// This entity script creates the logic for displaying the lightsaber beam.
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
(function() {
Script.include("../../libraries/utils.js");
var _this;
// this is the "constructor" for the entity as a JS object we don't do much here
var LightSaber = function() {
_this = this;
this.colorPalette = [{
red: 0,
green: 200,
blue: 40
}, {
red: 200,
green: 10,
blue: 40
}];
};
LightSaber.prototype = {
isGrabbed: false,
startNearGrab: function() {
Entities.editEntity(this.beam, {
isEmitting: true,
visible: true
});
},
releaseGrab: function() {
Entities.editEntity(this.beam, {
visible: false,
isEmitting: false
});
},
preload: function(entityID) {
this.entityID = entityID;
this.createBeam();
},
unload: function() {
Entities.deleteEntity(this.beam);
},
createBeam: function() {
this.props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]);
var forwardVec = Quat.getFront(Quat.multiply(this.props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0)));
var forwardQuat = Quat.rotationBetween(Vec3.UNIT_Z, forwardVec);
var position = this.props.position;
var color = this.colorPalette[randInt(0, this.colorPalette.length)];
var props = {
type: "ParticleEffect",
name: "LightSaber Beam",
position: position,
parentID: this.entityID,
isEmitting: false,
colorStart: color,
color: {
red: 200,
green: 200,
blue: 255
},
colorFinish: color,
maxParticles: 100000,
lifespan: 2,
emitRate: 1000,
emitOrientation: forwardQuat,
emitSpeed: 0.7,
speedSpread: 0.0,
emitDimensions: {
x: 0,
y: 0,
z: 0
},
polarStart: 0,
polarFinish: 0,
azimuthStart: 0.1,
azimuthFinish: 0.01,
emitAcceleration: {
x: 0,
y: 0,
z: 0
},
accelerationSpread: {
x: .00,
y: .00,
z: .00
},
radiusStart: 0.03,
adiusFinish: 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
}
this.beam = Entities.addEntity(props);
}
};
// entity scripts always need to return a newly constructed object of our type
return new LightSaber();
});

View file

@ -0,0 +1,191 @@
//
// lightTrails.js
// examples
//
// Created by Eric Levin on 5/14/15.
// Copyright 2015 High Fidelity, Inc.
//
// This script creates light trails as you move your hydra hands
//
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../libraries/utils.js");
var eraseTrail = true;
var ugLSD = 25;
// var eraseTrail = false;
var LEFT = 0;
var RIGHT = 1;
var MAX_POINTS_PER_LINE = 50;
var LIFETIME = 6000;
var DRAWING_DEPTH = 0.8;
var LINE_DIMENSIONS = 100;
var MIN_POINT_DISTANCE = 0.02;
var colorPalette = [{
red: 250,
green: 137,
blue: 162
}, {
red: 204,
green: 244,
blue: 249
}, {
red: 146,
green: 206,
blue: 116
}, {
red: 240,
green: 87,
blue: 129
}];
var STROKE_WIDTH = 0.04;
function controller(side, triggerAction) {
this.triggerHeld = false;
this.triggerThreshold = 0.9;
this.side = side;
this.triggerAction = triggerAction;
var texture = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/trails.png";
this.light = Entities.addEntity({
type: 'Light',
position: MyAvatar.position,
dimensions: {
x: 30,
y: 30,
z: 30
},
color: colorPalette[randInt(0, colorPalette.length)],
intensity: 5
});
this.trail = Entities.addEntity({
type: "PolyLine",
dimensions: {
x: LINE_DIMENSIONS,
y: LINE_DIMENSIONS,
z: LINE_DIMENSIONS
},
color: {red: 255, green: 255, blue: 255},
textures: texture,
lifetime: LIFETIME
});
this.points = [];
this.normals = [];
this.strokeWidths = [];
var self = this;
this.trailEraseInterval = Script.setInterval(function() {
if (self.points.length > 0 && eraseTrail) {
self.points.shift();
self.normals.shift();
self.strokeWidths.shift();
Entities.editEntity(self.trail, {
linePoints: self.points,
strokeWidths: self.strokeWidths,
normals: self.normals
});
}
}, ugLSD);
this.setTrailPosition = function(position) {
this.trailPosition = position;
Entities.editEntity(this.trail, {
position: this.trailPosition
});
}
this.update = function(deltaTime) {
this.updateControllerState();
var newTrailPosOffset = Vec3.multiply(Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)), DRAWING_DEPTH);
var newTrailPos = Vec3.sum(this.palmPosition, newTrailPosOffset);
Entities.editEntity(this.light, {
position: newTrailPos
});
if (!this.drawing) {
this.setTrailPosition(newTrailPos);
this.drawing = true;
}
if (this.drawing) {
var localPoint = Vec3.subtract(newTrailPos, this.trailPosition);
if (Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) {
//Need a minimum distance to avoid binormal NANs
return;
}
if (this.points.length === MAX_POINTS_PER_LINE) {
this.points.shift();
this.normals.shift();
this.strokeWidths.shift();
}
this.points.push(localPoint);
var normal = computeNormal(newTrailPos, Camera.getPosition());
this.normals.push(normal);
this.strokeWidths.push(STROKE_WIDTH + Math.random() * 0.01);
Entities.editEntity(this.trail, {
linePoints: this.points,
normals: this.normals,
strokeWidths: this.strokeWidths,
});
}
}
this.updateControllerState = function() {
this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation;
this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation;
this.triggerValue = Controller.getActionValue(this.triggerAction);
}
this.cleanup = function() {
Entities.deleteEntity(this.trail);
Entities.deleteEntity(this.light);
Script.clearInterval(this.trailEraseInterval);
}
}
function computeNormal(p1, p2) {
return Vec3.normalize(Vec3.subtract(p2, p1));
}
function update(deltaTime) {
leftController.update(deltaTime);
rightController.update(deltaTime);
}
function scriptEnding() {
leftController.cleanup();
rightController.cleanup();
}
function vectorIsZero(v) {
return v.x === 0 && v.y === 0 && v.z === 0;
}
var rightController = new controller(RIGHT, Controller.findAction("RIGHT_HAND_CLICK"));
var leftController = new controller(LEFT, Controller.findAction("LEFT_HAND_CLICK"));
Script.update.connect(update);
Script.scriptEnding.connect(scriptEnding);
function map(value, min1, max1, min2, max2) {
return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
}

View file

@ -0,0 +1,90 @@
//
// RaveStick.js
// examples/flowArats/raveStick
//
// Created by Eric Levin on 12/17/15.
// Copyright 2015 High Fidelity, Inc.
//
// This script creates a rave stick which makes pretty light trails as you paint
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.include("../../libraries/utils.js");
var modelURL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/raveStick.fbx";
var scriptURL = Script.resolvePath("raveStickEntityScript.js");
RaveStick = function(spawnPosition) {
var colorPalette = [{
red: 0,
green: 200,
blue: 40
}, {
red: 200,
green: 10,
blue: 40
}];
var stick = Entities.addEntity({
type: "Model",
name: "raveStick",
modelURL: modelURL,
position: spawnPosition,
shapeType: 'box',
collisionsWillMove: true,
script: scriptURL,
dimensions: {
x: 0.06,
y: 0.06,
z: 0.31
},
userData: JSON.stringify({
grabbableKey: {
spatialKey: {
relativePosition: {
x: 0,
y: 0,
z: -0.1
},
relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0)
},
invertSolidWhileHeld: true
}
})
});
var light = Entities.addEntity({
type: 'Light',
name: "raveLight",
parentID: stick,
dimensions: {
x: 30,
y: 30,
z: 30
},
color: colorPalette[randInt(0, colorPalette.length)],
intensity: 5
});
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);
var position = Vec3.sum(spawnPosition, Vec3.multiply(Quat.getFront(rotation), 0.1));
position.z += 0.1;
position.x += -0.035;
var color = {
red: 0,
green: 200,
blue: 40
};
function cleanup() {
Entities.deleteEntity(stick);
Entities.deleteEntity(light);
}
this.cleanup = cleanup;
}

View file

@ -0,0 +1,141 @@
// raveStickEntityScript.js
//
// Script Type: Entity
// Created by Eric Levin on 12/16/15.
// Copyright 2015 High Fidelity, Inc.
//
// This entity script create light trails on a given object as it moves.
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
(function() {
Script.include("../../libraries/utils.js");
var _this;
var LIFETIME = 6000;
var DRAWING_DEPTH = 0.8;
var LINE_DIMENSIONS = 100;
var MAX_POINTS_PER_LINE = 50;
var MIN_POINT_DISTANCE = 0.02;
var STROKE_WIDTH = 0.05
var ugLSD = 35;
var RaveStick = function() {
_this = this;
this.colorPalette = [{
red: 0,
green: 200,
blue: 40
}, {
red: 200,
green: 10,
blue: 40
}];
var texture = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/trails.png";
this.trail = Entities.addEntity({
type: "PolyLine",
dimensions: {
x: LINE_DIMENSIONS,
y: LINE_DIMENSIONS,
z: LINE_DIMENSIONS
},
color: {
red: 255,
green: 255,
blue: 255
},
textures: texture,
lifetime: LIFETIME
});
this.points = [];
this.normals = [];
this.strokeWidths = [];
};
RaveStick.prototype = {
isGrabbed: false,
startNearGrab: function() {
this.trailBasePosition = Entities.getEntityProperties(this.entityID, "position").position;
Entities.editEntity(this.trail, {
position: this.trailBasePosition
});
this.points = [];
this.normals = [];
this.strokeWidths = [];
this.setupEraseInterval();
},
continueNearGrab: function() {
var props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]);
var forwardVec = Quat.getFront(Quat.multiply(props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0)));
forwardVec = Vec3.normalize(forwardVec);
var forwardQuat = orientationOf(forwardVec);
var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.04));
var localPoint = Vec3.subtract(position, this.trailBasePosition);
if (this.points.length >= 1 && Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) {
//Need a minimum distance to avoid binormal NANs
return;
}
if (this.points.length === MAX_POINTS_PER_LINE) {
this.points.shift();
this.normals.shift();
this.strokeWidths.shift();
}
this.points.push(localPoint);
var normal = Quat.getUp(props.rotation);
this.normals.push(normal);
this.strokeWidths.push(STROKE_WIDTH);
Entities.editEntity(this.trail, {
linePoints: this.points,
normals: this.normals,
strokeWidths: this.strokeWidths
});
},
setupEraseInterval: function() {
this.trailEraseInterval = Script.setInterval(function() {
if (_this.points.length > 0) {
_this.points.shift();
_this.normals.shift();
_this.strokeWidths.shift();
Entities.editEntity(_this.trail, {
linePoints: _this.points,
strokeWidths: _this.strokeWidths,
normals: _this.normals
});
}
}, ugLSD);
},
releaseGrab: function() {
if(!this.trailEraseInterval) {
return;
}
Script.setTimeout(function() {
Script.clearInterval(_this.trailEraseInterval);
_this.trailEraseInterval = null;
}, 3000);
},
preload: function(entityID) {
this.entityID = entityID;
},
unload: function() {
Entities.deleteEntity(this.beam);
Entities.deleteEntity(this.trail);
if (this.trailEraseInterval) {
Script.clearInterval(this.trailEraseInterval);
}
}
};
return new RaveStick();
function computeNormal(p1, p2) {
return Vec3.normalize(Vec3.subtract(p2, p1));
}
});

View file

@ -43,6 +43,8 @@ var MAX_STROKE_WIDTH = 0.04;
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(Camera.getOrientation())));
var textureURL = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/paintStroke.png";
function MyController(hand, triggerAction) {
@ -148,7 +150,8 @@ function MyController(hand, triggerAction) {
y: 50,
z: 50
},
lifetime: 200
lifetime: 200,
textures: textureURL
});
this.strokePoints = [];
this.strokeNormals = [];

View file

@ -29,6 +29,8 @@
var MIN_STROKE_WIDTH = 0.0005;
var MAX_STROKE_WIDTH = 0.03;
var textureURL = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/paintStroke.png";
var TRIGGER_CONTROLS = [
Controller.Standard.LT,
Controller.Standard.RT,
@ -168,6 +170,7 @@
type: "PolyLine",
name: "paintStroke",
color: this.strokeColor,
textures: "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/paintStroke.png",
dimensions: {
x: 50,
y: 50,

View file

@ -38,6 +38,14 @@ var pingPongGun = Entities.addEntity({
collisionSoundURL: COLLISION_SOUND_URL,
userData: JSON.stringify({
grabbableKey: {
spatialKey: {
relativePosition: {
x: -0.05,
y: 0,
z: 0.0
},
relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, -90)
},
invertSolidWhileHeld: true
}
})

View file

@ -240,8 +240,11 @@ void RenderableParticleEffectEntityItem::updateRenderItem() {
auto position = getPosition();
auto rotation = getRotation();
Transform transform;
transform.setTranslation(position);
transform.setRotation(rotation);
if (!getEmitterShouldTrail()) {
transform.setTranslation(position);
transform.setRotation(rotation);
}
render::PendingChanges pendingChanges;
pendingChanges.updateItem<ParticlePayloadData>(_renderItemId, [=](ParticlePayloadData& payload) {

View file

@ -23,6 +23,13 @@
#include "paintStroke_frag.h"
struct PolyLineUniforms {
glm::vec3 color;
};
EntityItemPointer RenderablePolyLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
EntityItemPointer entity{ new RenderablePolyLineEntityItem(entityID) };
entity->setProperties(properties);
@ -30,9 +37,12 @@ EntityItemPointer RenderablePolyLineEntityItem::factory(const EntityItemID& enti
}
RenderablePolyLineEntityItem::RenderablePolyLineEntityItem(const EntityItemID& entityItemID) :
PolyLineEntityItem(entityItemID) {
_numVertices = 0;
PolyLineEntityItem(entityItemID),
_numVertices(0)
{
_vertices = QVector<glm::vec3>(0.0f);
PolyLineUniforms uniforms;
_uniformBuffer = std::make_shared<gpu::Buffer>(sizeof(PolyLineUniforms), (const gpu::Byte*) &uniforms);
}
gpu::PipelinePointer RenderablePolyLineEntityItem::_pipeline;
@ -41,13 +51,11 @@ int32_t RenderablePolyLineEntityItem::PAINTSTROKE_GPU_SLOT;
void RenderablePolyLineEntityItem::createPipeline() {
static const int NORMAL_OFFSET = 12;
static const int COLOR_OFFSET = 24;
static const int TEXTURE_OFFSET = 28;
static const int TEXTURE_OFFSET = 24;
_format.reset(new gpu::Stream::Format());
_format->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
_format->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), NORMAL_OFFSET);
_format->setAttribute(gpu::Stream::COLOR, 0, gpu::Element::COLOR_RGBA_32, COLOR_OFFSET);
_format->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), TEXTURE_OFFSET);
auto VS = gpu::Shader::createVertex(std::string(paintStroke_vert));
@ -72,47 +80,28 @@ void RenderablePolyLineEntityItem::updateGeometry() {
_verticesBuffer.reset(new gpu::Buffer());
int vertexIndex = 0;
vec2 uv;
float tailStart = 0.0f;
float tailEnd = 0.25f;
float tailLength = tailEnd - tailStart;
float headStart = 0.76f;
float headEnd = 1.0f;
float headLength = headEnd - headStart;
float uCoord, vCoord;
int numTailStrips = 5;
int numHeadStrips = 10;
int startHeadIndex = _vertices.size() / 2 - numHeadStrips;
uCoord = 0.0f;
float uCoordInc = 1.0 / (_vertices.size() / 2);
for (int i = 0; i < _vertices.size() / 2; i++) {
uCoord = 0.26f;
vCoord = 0.0f;
//tail
if (i < numTailStrips) {
uCoord = float(i) / numTailStrips * tailLength + tailStart;
}
//head
if (i > startHeadIndex) {
uCoord = float((i + 1) - startHeadIndex) / numHeadStrips * headLength + headStart;
}
uv = vec2(uCoord, vCoord);
_verticesBuffer->append(sizeof(glm::vec3), (const gpu::Byte*)&_vertices.at(vertexIndex));
_verticesBuffer->append(sizeof(glm::vec3), (const gpu::Byte*)&_normals.at(i));
_verticesBuffer->append(sizeof(int), (gpu::Byte*)&_color);
_verticesBuffer->append(sizeof(glm::vec2), (gpu::Byte*)&uv);
vertexIndex++;
uv.y = 1.0f;
_verticesBuffer->append(sizeof(glm::vec3), (const gpu::Byte*)&_vertices.at(vertexIndex));
_verticesBuffer->append(sizeof(glm::vec3), (const gpu::Byte*)&_normals.at(i));
_verticesBuffer->append(sizeof(int), (gpu::Byte*)_color);
_verticesBuffer->append(sizeof(glm::vec2), (const gpu::Byte*)&uv);
vertexIndex++;
_numVertices += 2;
uCoord += uCoordInc;
}
_pointsChanged = false;
_normalsChanged = false;
@ -161,6 +150,16 @@ void RenderablePolyLineEntityItem::updateVertices() {
}
void RenderablePolyLineEntityItem::update(const quint64& now) {
PolyLineUniforms uniforms;
uniforms.color = toGlm(getXColor());
memcpy(&_uniformBuffer.edit<PolyLineUniforms>(), &uniforms, sizeof(PolyLineUniforms));
if (_pointsChanged || _strokeWidthsChanged || _normalsChanged) {
updateVertices();
updateGeometry();
}
}
void RenderablePolyLineEntityItem::render(RenderArgs* args) {
QWriteLocker lock(&_quadReadWriteLock);
@ -181,17 +180,13 @@ void RenderablePolyLineEntityItem::render(RenderArgs* args) {
PerformanceTimer perfTimer("RenderablePolyLineEntityItem::render");
Q_ASSERT(getType() == EntityTypes::PolyLine);
Q_ASSERT(args->_batch);
if (_pointsChanged || _strokeWidthsChanged || _normalsChanged) {
updateVertices();
updateGeometry();
}
gpu::Batch& batch = *args->_batch;
Transform transform = Transform();
transform.setTranslation(getPosition());
transform.setRotation(getRotation());
batch.setUniformBuffer(0, _uniformBuffer);
batch.setModelTransform(transform);
batch.setPipeline(_pipeline);
@ -200,7 +195,7 @@ void RenderablePolyLineEntityItem::render(RenderArgs* args) {
} else {
batch.setResourceTexture(PAINTSTROKE_GPU_SLOT, args->_whiteTexture);
}
batch.setInputFormat(_format);
batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride);

View file

@ -29,6 +29,8 @@ public:
RenderablePolyLineEntityItem(const EntityItemID& entityItemID);
virtual void render(RenderArgs* args);
virtual void update(const quint64& now) override;
virtual bool needsToCallUpdate() const { return true; };
SIMPLE_RENDERABLE();
@ -42,6 +44,7 @@ protected:
void updateGeometry();
void updateVertices();
gpu::BufferPointer _verticesBuffer;
gpu::BufferView _uniformBuffer;
unsigned int _numVertices;
QVector<glm::vec3> _vertices;

View file

@ -23,8 +23,6 @@ layout(location = 0) out vec4 _fragColor0;
layout(location = 1) out vec4 _fragColor1;
layout(location = 2) out vec4 _fragColor2;
// the glow intensity
uniform float glowIntensity;
// the alpha threshold
uniform float alphaThreshold;
uniform sampler2D normalFittingMap;
@ -318,8 +316,8 @@ const QString SHADER_TEMPLATE_V1 = SHADER_COMMON + R"SCRIBE(
void main(void) {
vec4 emissive = getProceduralColor();
float alpha = glowIntensity * emissive.a;
if (alpha != glowIntensity) {
float alpha = emissive.a;
if (alpha != 1.0) {
discard;
}

View file

@ -23,23 +23,24 @@ in vec3 interpolatedNormal;
in vec2 varTexcoord;
in vec4 varColor;
float rand(vec2 point){
return fract(sin(dot(point.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
struct PolyLineUniforms {
vec3 color;
};
uniform polyLineBuffer {
PolyLineUniforms polyline;
};
void main(void) {
vec4 texel = texture(originalTexture, varTexcoord);
int frontCondition = 1 -int(gl_FrontFacing) * 2;
vec3 color = varColor.rgb;
//vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess
vec3 color = varColor.rgb;
packDeferredFragmentTranslucent(
interpolatedNormal * frontCondition,
texel.a,
color *texel.rgb,
polyline.color * texel.rgb,
vec3(0.01, 0.01, 0.01),
10.0);
}

View file

@ -32,6 +32,7 @@ void main(void) {
// pass along the diffuse color
varColor = colorToLinearRGBA(inColor);
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();

View file

@ -195,7 +195,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_ALPHA_SPREAD, alphaSpread);
CHECK_PROPERTY_CHANGE(PROP_ALPHA_START, alphaStart);
CHECK_PROPERTY_CHANGE(PROP_ALPHA_FINISH, alphaFinish);
CHECK_PROPERTY_CHANGE(PROP_ADDITIVE_BLENDING, additiveBlending);
CHECK_PROPERTY_CHANGE(PROP_EMITTER_SHOULD_TRAIL, emitterShouldTrail);
CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL);
CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
CHECK_PROPERTY_CHANGE(PROP_VISIBLE, visible);
@ -354,7 +354,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_SPREAD, alphaSpread);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_START, alphaStart);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_FINISH, alphaFinish);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ADDITIVE_BLENDING, additiveBlending);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMITTER_SHOULD_TRAIL, emitterShouldTrail);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation);
}
@ -515,7 +515,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaSpread, float, setAlphaSpread);
COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaStart, float, setAlphaStart);
COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaFinish, float, setAlphaFinish);
COPY_PROPERTY_FROM_QSCRIPTVALUE(additiveBlending, bool, setAdditiveBlending);
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitterShouldTrail , bool, setEmitterShouldTrail);
COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(glowLevel, float, setGlowLevel);
@ -670,7 +670,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
ADD_PROPERTY_TO_MAP(PROP_ALPHA_SPREAD, AlphaSpread, alphaSpread, float);
ADD_PROPERTY_TO_MAP(PROP_ALPHA_START, AlphaStart, alphaStart, float);
ADD_PROPERTY_TO_MAP(PROP_ALPHA_FINISH, AlphaFinish, alphaFinish, float);
ADD_PROPERTY_TO_MAP(PROP_ADDITIVE_BLENDING, AdditiveBlending, additiveBlending, bool);
ADD_PROPERTY_TO_MAP(PROP_EMITTER_SHOULD_TRAIL, EmitterShouldTrail, emitterShouldTrail, bool);
ADD_PROPERTY_TO_MAP(PROP_MODEL_URL, ModelURL, modelURL, QString);
ADD_PROPERTY_TO_MAP(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString);
ADD_PROPERTY_TO_MAP(PROP_REGISTRATION_POINT, RegistrationPoint, registrationPoint, glm::vec3);
@ -980,7 +980,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, properties.getAlphaSpread());
APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, properties.getAlphaStart());
APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, properties.getAlphaFinish());
APPEND_ENTITY_PROPERTY(PROP_ADDITIVE_BLENDING, properties.getAdditiveBlending());
APPEND_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, properties.getEmitterShouldTrail());
}
if (properties.getType() == EntityTypes::Zone) {
@ -1265,7 +1265,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_SPREAD, float, setAlphaSpread);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_START, float, setAlphaStart);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_FINISH, float, setAlphaFinish);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ADDITIVE_BLENDING, bool, setAdditiveBlending);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail);
}
if (properties.getType() == EntityTypes::Zone) {
@ -1608,8 +1608,8 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (alphaFinishChanged()) {
out += "alphaFinish";
}
if (additiveBlendingChanged()) {
out += "additiveBlending";
if (emitterShouldTrailChanged()) {
out += "emitterShouldTrail";
}
if (modelURLChanged()) {
out += "modelURL";

View file

@ -161,7 +161,7 @@ public:
DEFINE_PROPERTY(PROP_RADIUS_SPREAD, RadiusSpread, radiusSpread, float, ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD);
DEFINE_PROPERTY(PROP_RADIUS_START, RadiusStart, radiusStart, float, ParticleEffectEntityItem::DEFAULT_RADIUS_START);
DEFINE_PROPERTY(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float, ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH);
DEFINE_PROPERTY(PROP_ADDITIVE_BLENDING, AdditiveBlending, additiveBlending, bool, ParticleEffectEntityItem::DEFAULT_ADDITIVE_BLENDING);
DEFINE_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, EmitterShouldTrail, emitterShouldTrail, bool, ParticleEffectEntityItem::DEFAULT_EMITTER_SHOULD_TRAIL);
DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID);
DEFINE_PROPERTY_GROUP(KeyLight, keyLight, KeyLightPropertyGroup);
DEFINE_PROPERTY_REF(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3, PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE);

View file

@ -149,7 +149,7 @@ enum EntityPropertyList {
PROP_ANIMATION_HOLD,
PROP_ANIMATION_START_AUTOMATICALLY,
PROP_ADDITIVE_BLENDING,
PROP_EMITTER_SHOULD_TRAIL,
PROP_PARENT_ID,
PROP_PARENT_JOINT_INDEX,

View file

@ -52,13 +52,13 @@ const float ParticleEffectEntityItem::MINIMUM_ALPHA = 0.0f;
const float ParticleEffectEntityItem::MAXIMUM_ALPHA = 1.0f;
const quint32 ParticleEffectEntityItem::DEFAULT_MAX_PARTICLES = 1000;
const quint32 ParticleEffectEntityItem::MINIMUM_MAX_PARTICLES = 1;
const quint32 ParticleEffectEntityItem::MAXIMUM_MAX_PARTICLES = 10000;
const quint32 ParticleEffectEntityItem::MAXIMUM_MAX_PARTICLES = 100000;
const float ParticleEffectEntityItem::DEFAULT_LIFESPAN = 3.0f;
const float ParticleEffectEntityItem::MINIMUM_LIFESPAN = 0.0f;
const float ParticleEffectEntityItem::MAXIMUM_LIFESPAN = 86400.0f; // 1 day
const float ParticleEffectEntityItem::DEFAULT_EMIT_RATE = 15.0f;
const float ParticleEffectEntityItem::MINIMUM_EMIT_RATE = 0.0f;
const float ParticleEffectEntityItem::MAXIMUM_EMIT_RATE = 1000.0f;
const float ParticleEffectEntityItem::MAXIMUM_EMIT_RATE = 100000.0f;
const float ParticleEffectEntityItem::DEFAULT_EMIT_SPEED = 5.0f;
const float ParticleEffectEntityItem::MINIMUM_EMIT_SPEED = 0.0f;
const float ParticleEffectEntityItem::MAXIMUM_EMIT_SPEED = 1000.0f; // Approx mach 3
@ -91,7 +91,7 @@ const float ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD = 0.0f;
const float ParticleEffectEntityItem::DEFAULT_RADIUS_START = DEFAULT_PARTICLE_RADIUS;
const float ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH = DEFAULT_PARTICLE_RADIUS;
const QString ParticleEffectEntityItem::DEFAULT_TEXTURES = "";
const bool ParticleEffectEntityItem::DEFAULT_ADDITIVE_BLENDING = false;
const bool ParticleEffectEntityItem::DEFAULT_EMITTER_SHOULD_TRAIL = false;
EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
@ -331,7 +331,7 @@ EntityItemProperties ParticleEffectEntityItem::getProperties(EntityPropertyFlags
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaStart, getAlphaStart);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaFinish, getAlphaFinish);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(additiveBlending, getAdditiveBlending);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitterShouldTrail, getEmitterShouldTrail);
return properties;
@ -370,7 +370,7 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaStart, setAlphaStart);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaFinish, setAlphaFinish);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(additiveBlending, setAdditiveBlending);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitterShouldTrail, setEmitterShouldTrail);
if (somethingChanged) {
bool wantDebug = false;
@ -463,7 +463,7 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch
}
if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING) {
READ_ENTITY_PROPERTY(PROP_ADDITIVE_BLENDING, bool, setAdditiveBlending);
READ_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail);
}
return bytesRead;
@ -503,7 +503,7 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea
requestedProperties += PROP_POLAR_FINISH;
requestedProperties += PROP_AZIMUTH_START;
requestedProperties += PROP_AZIMUTH_FINISH;
requestedProperties += PROP_ADDITIVE_BLENDING;
requestedProperties += PROP_EMITTER_SHOULD_TRAIL;
return requestedProperties;
}
@ -546,7 +546,7 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData,
APPEND_ENTITY_PROPERTY(PROP_POLAR_FINISH, getPolarFinish());
APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_START, getAzimuthStart());
APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, getAzimuthFinish());
APPEND_ENTITY_PROPERTY(PROP_ADDITIVE_BLENDING, getAdditiveBlending());
APPEND_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, getEmitterShouldTrail());
}
bool ParticleEffectEntityItem::isEmittingParticles() const {
@ -641,13 +641,17 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() {
Particle particle;
particle.seed = randFloatInRange(0.0f, 1.0f);
particle.seed = randFloatInRange(-1.0f, 1.0f);
if (getEmitterShouldTrail()) {
particle.position = getPosition();
}
// Position, velocity, and acceleration
if (_polarStart == 0.0f && _polarFinish == 0.0f && _emitDimensions.z == 0.0f) {
// Emit along z-axis from position
particle.velocity = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * Vectors::UNIT_Z);
particle.velocity = (_emitSpeed + 0.2f * _speedSpread) * (_emitOrientation * Vectors::UNIT_Z);
particle.acceleration = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread;
} else {
@ -658,11 +662,12 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() {
float elevationMinZ = sin(PI_OVER_TWO - _polarFinish);
float elevationMaxZ = sin(PI_OVER_TWO - _polarStart);
float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) * randFloat());
// float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) * randFloat());
float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) *randFloat());
float azimuth;
if (_azimuthFinish >= _azimuthStart) {
azimuth = _azimuthStart + (_azimuthFinish - _azimuthStart) * randFloat();
azimuth = _azimuthStart + (_azimuthFinish - _azimuthStart) * randFloat();
} else {
azimuth = _azimuthStart + (TWO_PI + _azimuthFinish - _azimuthStart) * randFloat();
}
@ -693,7 +698,12 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() {
radii.z > 0.0f ? z / (radii.z * radii.z) : 0.0f
));
particle.position = _emitOrientation * emitPosition;
if (getEmitterShouldTrail()) {
particle.position += _emitOrientation * emitPosition;
}
else {
particle.position = _emitOrientation * emitPosition;
}
}
particle.velocity = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * emitDirection);

View file

@ -213,10 +213,10 @@ public:
}
}
static const bool DEFAULT_ADDITIVE_BLENDING;
bool getAdditiveBlending() const { return _additiveBlending; }
void setAdditiveBlending(bool additiveBlending) {
_additiveBlending = additiveBlending;
static const bool DEFAULT_EMITTER_SHOULD_TRAIL;
bool getEmitterShouldTrail() const { return _emitterShouldTrail; }
void setEmitterShouldTrail(bool emitterShouldTrail) {
_emitterShouldTrail = emitterShouldTrail;
}
virtual bool supportsDetailedRayIntersection() const { return false; }
@ -286,7 +286,7 @@ protected:
float _timeUntilNextEmit { 0.0f };
bool _additiveBlending { DEFAULT_ADDITIVE_BLENDING };
bool _emitterShouldTrail { DEFAULT_EMITTER_SHOULD_TRAIL };
};
#endif // hifi_ParticleEffectEntityItem_h

View file

@ -89,6 +89,7 @@ bool PolyLineEntityItem::setProperties(const EntityItemProperties& properties) {
return somethingChanged;
}
bool PolyLineEntityItem::appendPoint(const glm::vec3& point) {
if (_points.size() > MAX_POINTS_PER_LINE - 1) {
qDebug() << "MAX POINTS REACHED!";
@ -104,6 +105,7 @@ bool PolyLineEntityItem::appendPoint(const glm::vec3& point) {
return true;
}
bool PolyLineEntityItem::setStrokeWidths(const QVector<float>& strokeWidths) {
_strokeWidths = strokeWidths;
_strokeWidthsChanged = true;

View file

@ -49,7 +49,7 @@ class PolyLineEntityItem : public EntityItem {
memcpy(_color, value, sizeof(_color));
}
void setColor(const xColor& value) {
_color[RED_INDEX] = value.red;
_color[GREEN_INDEX] = value.green;
_color[BLUE_INDEX] = value.blue;
@ -75,7 +75,9 @@ class PolyLineEntityItem : public EntityItem {
_texturesChangedFlag = true;
}
}
virtual bool needsToCallUpdate() const { return true; }
virtual ShapeType getShapeType() const { return SHAPE_TYPE_LINE; }
// never have a ray intersection pick a PolyLineEntityItem.

View file

@ -56,7 +56,7 @@ static const std::string DEEFAULT_ROUGHNESS_SHADER {
};
static const std::string DEEFAULT_NORMAL_SHADER {
"vec4 getFragmentColor() {"
" return vec4(texture(normalMap, uv).xyz, 1.0);"
" return vec4(normalize(texture(normalMap, uv).xyz), 1.0);"
" }"
};
static const std::string DEEFAULT_DEPTH_SHADER {

View file

@ -15,12 +15,6 @@ layout(location = 0) out vec4 _fragColor0;
layout(location = 1) out vec4 _fragColor1;
layout(location = 2) out vec4 _fragColor2;
// the glow intensity
uniform float glowIntensity;
// the alpha threshold
uniform float alphaThreshold;
uniform sampler2D normalFittingMap;
vec3 bestFitNormal(vec3 normal) {
@ -39,15 +33,18 @@ vec3 bestFitNormal(vec3 normal) {
return (cN * 0.5 + 0.5);
}
// the alpha threshold
const float alphaThreshold = 0.5;
float evalOpaqueFinalAlpha(float alpha, float mapAlpha) {
return mix(alpha * glowIntensity, 1.0 - alpha * glowIntensity, step(mapAlpha, alphaThreshold));
return mix(alpha, 1.0 - alpha, step(mapAlpha, alphaThreshold));
}
const vec3 DEFAULT_SPECULAR = vec3(0.1);
const float DEFAULT_SHININESS = 10;
void packDeferredFragment(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess) {
if (alpha != glowIntensity) {
if (alpha != 1.0) {
discard;
}
@ -57,7 +54,7 @@ void packDeferredFragment(vec3 normal, float alpha, vec3 diffuse, vec3 specular,
}
void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess, vec3 emissive) {
if (alpha != glowIntensity) {
if (alpha != 1.0) {
discard;
}
@ -67,7 +64,7 @@ void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 diffuse, vec3 s
}
void packDeferredFragmentTranslucent(vec3 normal, float alpha, vec3 diffuse, vec3 specular, float shininess) {
if (alpha <= alphaThreshold) {
if (alpha <= 0.0) {
discard;
}

View file

@ -40,8 +40,6 @@
#include "point_light_frag.h"
#include "spot_light_frag.h"
static const std::string glowIntensityShaderHandle = "glowIntensity";
struct LightLocations {
int radius;
int ambientSphere;
@ -134,8 +132,6 @@ gpu::PipelinePointer DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch
batch.setPipeline(pipeline);
gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader;
int glowIntensity = program->getUniforms().findLocation("glowIntensity");
batch._glUniform1f(glowIntensity, 1.0f);
if (!config.isTextured()) {
// If it is not textured, bind white texture and keep using textured pipeline

View file

@ -199,8 +199,6 @@ void MeshPartPayload::render(RenderArgs* args) const {
gpu::Batch& batch = *(args->_batch);
auto mode = args->_renderMode;
auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME
model::MaterialKey drawMaterialKey;
if (_drawMaterial) {
drawMaterialKey = _drawMaterial->getKey();
@ -217,7 +215,7 @@ void MeshPartPayload::render(RenderArgs* args) const {
}
ModelRender::Locations* locations = nullptr;
ModelRender::pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
ModelRender::pickPrograms(batch, mode, translucentMesh, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
args, locations);
@ -395,9 +393,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) const {
gpu::Batch& batch = *(args->_batch);
auto mode = args->_renderMode;
auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME
const FBXGeometry& geometry = _model->_geometry->getFBXGeometry();
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = _model->_geometry->getMeshes();
@ -467,7 +463,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) const {
}
ModelRender::Locations* locations = nullptr;
ModelRender::pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
ModelRender::pickPrograms(batch, mode, translucentMesh, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
args, locations);
if (!locations) { // the pipeline could not be found

View file

@ -228,10 +228,8 @@ void ModelRender::RenderPipelineLib::addRenderPipeline(ModelRender::RenderKey ke
void ModelRender::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, ModelRender::Locations& locations) {
locations.alphaThreshold = program->getUniforms().findLocation("alphaThreshold");
locations.texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices");
locations.emissiveParams = program->getUniforms().findLocation("emissiveParams");
locations.glowIntensity = program->getUniforms().findLocation("glowIntensity");
locations.normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap");
locations.diffuseTextureUnit = program->getTextures().findLocation("diffuseMap");
locations.normalTextureUnit = program->getTextures().findLocation("normalMap");
@ -244,14 +242,14 @@ void ModelRender::RenderPipelineLib::initLocations(gpu::ShaderPointer& program,
}
void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold,
void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent,
bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args,
Locations*& locations) {
PerformanceTimer perfTimer("Model::pickPrograms");
getRenderPipelineLib();
RenderKey key(mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe);
RenderKey key(mode, translucent, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe);
auto pipeline = _renderPipelineLib.find(key.getRaw());
if (pipeline == _renderPipelineLib.end()) {
qDebug() << "No good, couldn't find a pipeline from the key ?" << key.getRaw();
@ -266,15 +264,6 @@ void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, b
// Setup the One pipeline
batch.setPipeline((*pipeline).second._pipeline);
if ((locations->alphaThreshold > -1) && (mode != RenderArgs::SHADOW_RENDER_MODE)) {
batch._glUniform1f(locations->alphaThreshold, alphaThreshold);
}
if ((locations->glowIntensity > -1) && (mode != RenderArgs::SHADOW_RENDER_MODE)) {
const float DEFAULT_GLOW_INTENSITY = 1.0f; // FIXME - glow is removed
batch._glUniform1f(locations->glowIntensity, DEFAULT_GLOW_INTENSITY);
}
if ((locations->normalFittingMapUnit > -1)) {
batch.setResourceTexture(locations->normalFittingMapUnit,
DependencyManager::get<TextureCache>()->getNormalFittingTexture());

View file

@ -29,21 +29,19 @@ public:
class Locations {
public:
int alphaThreshold;
int texcoordMatrices;
int diffuseTextureUnit;
int normalTextureUnit;
int specularTextureUnit;
int emissiveTextureUnit;
int emissiveParams;
int glowIntensity;
int normalFittingMapUnit;
int skinClusterBufferUnit;
int materialBufferUnit;
int lightBufferUnit;
};
static void pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent, float alphaThreshold,
static void pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent,
bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args,
Locations*& locations);
@ -111,9 +109,9 @@ public:
) {}
RenderKey(RenderArgs::RenderMode mode,
bool translucent, float alphaThreshold, bool hasLightmap,
bool translucent, bool hasLightmap,
bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe) :
RenderKey(((translucent && (alphaThreshold == 0.0f) && (mode != RenderArgs::SHADOW_RENDER_MODE)) ? IS_TRANSLUCENT : 0)
RenderKey(((translucent && (mode != RenderArgs::SHADOW_RENDER_MODE)) ? IS_TRANSLUCENT : 0)
| (hasLightmap && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_LIGHTMAP : 0) // Lightmap, tangents and specular don't matter for depthOnly
| (hasTangents && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_TANGENTS : 0)
| (hasSpecular && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_SPECULAR : 0)

View file

@ -126,12 +126,6 @@ RenderDeferredTask::RenderDeferredTask() : Task() {
_jobs.push_back(Job(new HitEffect::JobModel("HitEffect")));
_jobs.back().setEnabled(false);
_drawHitEffectJobIndex = (int)_jobs.size() -1;
// Give ourselves 3 frmaes of timer queries
_timerQueries.push_back(std::make_shared<gpu::Query>());
_timerQueries.push_back(std::make_shared<gpu::Query>());
_timerQueries.push_back(std::make_shared<gpu::Query>());
_currentTimerQueryIndex = 0;
}
RenderDeferredTask::~RenderDeferredTask() {
@ -197,10 +191,6 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat);
{
const float OPAQUE_ALPHA_THRESHOLD = 0.5f;
args->_alphaThreshold = OPAQUE_ALPHA_THRESHOLD;
}
renderItems(sceneContext, renderContext, inItems, opaque.maxDrawn);
args->_batch = nullptr;
});
@ -226,10 +216,7 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat);
const float TRANSPARENT_ALPHA_THRESHOLD = 0.0f;
args->_alphaThreshold = TRANSPARENT_ALPHA_THRESHOLD;
renderItems(sceneContext, renderContext, inItems, transparent.maxDrawn);
args->_batch = nullptr;
});

View file

@ -114,5 +114,6 @@ void main (void)
vec3 finalColor = color + fMiePhase * secondaryColor;
outFragColor.a = finalColor.b;
outFragColor.rgb = pow(finalColor.rgb, vec3(1.0/2.2));
// outFragColor.rgb = pow(finalColor.rgb, vec3(1.0/2.2));
outFragColor.rgb = finalColor.rgb;
}

View file

@ -51,9 +51,9 @@ void main(void) {
if (emissiveAmount > 0.0) {
packDeferredFragmentLightmap(
normal, glowIntensity, diffuse, specular, shininess, specular);
normal, 1.0, diffuse, specular, shininess, specular);
} else {
packDeferredFragment(
normal, glowIntensity, diffuse, specular, shininess);
normal, 1.0, diffuse, specular, shininess);
}
}

View file

@ -29,7 +29,7 @@ void main(void) {
packDeferredFragment(
normalize(_normal.xyz),
glowIntensity * texel.a,
texel.a,
_color.rgb * texel.rgb,
DEFAULT_SPECULAR, DEFAULT_SHININESS);
}

View file

@ -27,7 +27,7 @@ void main(void) {
packDeferredFragmentLightmap(
normalize(_normal),
glowIntensity * texel.a,
texel.a,
_color.rgb,
DEFAULT_SPECULAR, DEFAULT_SHININESS,
texel.rgb);

View file

@ -14,9 +14,10 @@
using namespace render;
RenderContext::RenderContext(ItemsConfig items, Tone tone, int drawStatus, bool drawHitEffect, glm::vec4 deferredDebugSize, int deferredDebugMode)
: _args{ nullptr }, _items{ items }, _tone{ tone },
_drawStatus{ drawStatus }, _drawHitEffect{ drawHitEffect },
_deferredDebugSize{ deferredDebugSize }, _deferredDebugMode{ deferredDebugMode } {};
: _deferredDebugMode{ deferredDebugMode }, _deferredDebugSize{ deferredDebugSize },
_args{ nullptr },
_drawStatus{ drawStatus }, _drawHitEffect{ drawHitEffect },
_items{ items }, _tone{ tone } {}
void RenderContext::setOptions(bool occlusion, bool fxaa, bool showOwned) {
_occlusionStatus = occlusion;

View file

@ -91,15 +91,15 @@ public:
void setOptions(bool occlusion, bool fxaa, bool showOwned);
// Debugging
int _deferredDebugMode = -1;
glm::vec4 _deferredDebugSize { 0.0f, -1.0f, 1.0f, 1.0f };
int _deferredDebugMode;
glm::vec4 _deferredDebugSize;
protected:
RenderArgs* _args;
// Options
int _drawStatus = 0; // bitflag
bool _drawHitEffect = false;
int _drawStatus; // bitflag
bool _drawHitEffect;
bool _occlusionStatus = false;
bool _fxaaStatus = false;

View file

@ -115,8 +115,6 @@ public:
std::shared_ptr<gpu::Texture> _whiteTexture;
RenderDetails _details;
float _alphaThreshold = 0.5f;
};
#endif // hifi_RenderArgs_h

View file

@ -13,6 +13,9 @@
#ifdef HAVE_SIXENSE
#include <sixense.h>
#else
#define SIXENSE_FAILURE -1
#define SIXENSE_SUCCESS 0
#endif
#include <QCoreApplication>
@ -43,6 +46,14 @@ static const unsigned int BUTTON_TRIGGER = 1U << 8;
const glm::vec3 SixenseManager::DEFAULT_AVATAR_POSITION { -0.25f, -0.35f, -0.3f }; // in hydra frame
const float SixenseManager::CONTROLLER_THRESHOLD { 0.35f };
bool SixenseManager::_sixenseLoaded = false;
#define BAIL_IF_NOT_LOADED \
if (!_sixenseLoaded) { \
return; \
}
const QString SixenseManager::NAME = "Sixense";
const QString SixenseManager::HYDRA_ID_STRING = "Razer Hydra";
@ -89,11 +100,12 @@ void SixenseManager::activate() {
userInputMapper->registerDevice(_inputDevice);
loadSettings();
sixenseInit();
_sixenseLoaded = (sixenseInit() == SIXENSE_SUCCESS);
#endif
}
void SixenseManager::deactivate() {
BAIL_IF_NOT_LOADED
InputPlugin::deactivate();
#ifdef HAVE_SIXENSE
@ -114,12 +126,14 @@ void SixenseManager::deactivate() {
}
void SixenseManager::setSixenseFilter(bool filter) {
BAIL_IF_NOT_LOADED
#ifdef HAVE_SIXENSE
sixenseSetFilterEnabled(filter ? 1 : 0);
#endif
}
void SixenseManager::pluginUpdate(float deltaTime, bool jointsCaptured) {
BAIL_IF_NOT_LOADED
_inputDevice->update(deltaTime, jointsCaptured);
if (_inputDevice->_requestReset) {
_container->requestReset();
@ -128,6 +142,7 @@ void SixenseManager::pluginUpdate(float deltaTime, bool jointsCaptured) {
}
void SixenseManager::InputDevice::update(float deltaTime, bool jointsCaptured) {
BAIL_IF_NOT_LOADED
#ifdef HAVE_SIXENSE
_buttonPressedMap.clear();
@ -246,6 +261,7 @@ void SixenseManager::InputDevice::update(float deltaTime, bool jointsCaptured) {
}
void SixenseManager::InputDevice::setDebugDrawRaw(bool flag) {
BAIL_IF_NOT_LOADED
_debugDrawRaw = flag;
if (!flag) {
DebugDraw::getInstance().removeMyAvatarMarker("SIXENSE_RAW_LEFT");
@ -254,6 +270,7 @@ void SixenseManager::InputDevice::setDebugDrawRaw(bool flag) {
}
void SixenseManager::InputDevice::setDebugDrawCalibrated(bool flag) {
BAIL_IF_NOT_LOADED
_debugDrawCalibrated = flag;
if (!flag) {
DebugDraw::getInstance().removeMyAvatarMarker("SIXENSE_CALIBRATED_LEFT");
@ -281,6 +298,7 @@ static bool calibrationRequested(SixenseControllerData* controllers) {
}
void SixenseManager::InputDevice::updateCalibration(SixenseControllerData* controllers) {
BAIL_IF_NOT_LOADED
const SixenseControllerData* dataLeft = controllers;
const SixenseControllerData* dataRight = controllers + 1;
@ -365,11 +383,13 @@ void SixenseManager::InputDevice::updateCalibration(SixenseControllerData* contr
#endif // HAVE_SIXENSE
void SixenseManager::InputDevice::focusOutEvent() {
BAIL_IF_NOT_LOADED
_axisStateMap.clear();
_buttonPressedMap.clear();
};
void SixenseManager::InputDevice::handleButtonEvent(unsigned int buttons, bool left) {
BAIL_IF_NOT_LOADED
using namespace controller;
if (buttons & BUTTON_0) {
_buttonPressedMap.insert(left ? BACK : START);
@ -395,6 +415,7 @@ void SixenseManager::InputDevice::handleButtonEvent(unsigned int buttons, bool l
}
void SixenseManager::InputDevice::handlePoseEvent(float deltaTime, glm::vec3 position, glm::quat rotation, bool left) {
BAIL_IF_NOT_LOADED
#ifdef HAVE_SIXENSE
auto hand = left ? controller::StandardPoseChannel::LEFT_HAND : controller::StandardPoseChannel::RIGHT_HAND;

View file

@ -98,6 +98,8 @@ private:
static const QString NAME;
static const QString HYDRA_ID_STRING;
static bool _sixenseLoaded;
};
#endif // hifi_SixenseManager_h

View file

@ -63,6 +63,9 @@ void unloadSixense() {
// sixense.h wrapper for OSX dynamic linking
int sixenseInit() {
loadSixense();
if (!SIXENSE || !SIXENSE->isLoaded()) {
return SIXENSE_FAILURE;
}
return FORWARD();
}
int sixenseExit() {

View file

@ -6,8 +6,7 @@
# See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html
#
#if (NOT WIN32)
if (FALSE)
if (NOT WIN32)
set(TARGET_NAME oculusLegacy)
setup_hifi_plugin()

View file

@ -26,7 +26,7 @@
using namespace oglplus;
const QString OculusLegacyDisplayPlugin::NAME("Oculus Rift (0.5)");
const QString OculusLegacyDisplayPlugin::NAME("Oculus Rift (0.5) (Simulated)");
const QString & OculusLegacyDisplayPlugin::getName() const {
return NAME;
@ -39,12 +39,6 @@ uvec2 OculusLegacyDisplayPlugin::getRecommendedRenderSize() const {
return _desiredFramebufferSize;
}
void OculusLegacyDisplayPlugin::preRender() {
ovrHmd_GetEyePoses(_hmd, _frameIndex, _eyeOffsets, _eyePoses, &_trackingState);
ovrHmd_BeginFrame(_hmd, _frameIndex);
WindowOpenGLDisplayPlugin::preRender();
}
glm::mat4 OculusLegacyDisplayPlugin::getProjection(Eye eye, const glm::mat4& baseProjection) const {
return _eyeProjections[eye];
}
@ -57,13 +51,18 @@ glm::mat4 OculusLegacyDisplayPlugin::getEyeToHeadTransform(Eye eye) const {
return toGlm(_eyePoses[eye]);
}
// Should NOT be used for rendering as this will mess up timewarp. Use the getModelview() method above for
// any use of head poses for rendering, ensuring you use the correct eye
glm::mat4 OculusLegacyDisplayPlugin::getHeadPose() const {
glm::mat4 OculusLegacyDisplayPlugin::getHeadPose(uint32_t frameIndex) const {
static uint32_t lastFrameSeen = 0;
if (frameIndex > lastFrameSeen) {
Lock lock(_mutex);
_trackingState = ovrHmd_GetTrackingState(_hmd, ovr_GetTimeInSeconds());
ovrHmd_GetEyePoses(_hmd, frameIndex, _eyeOffsets, _eyePoses, &_trackingState);
lastFrameSeen = frameIndex;
}
return toGlm(_trackingState.HeadPose.ThePose);
}
bool OculusLegacyDisplayPlugin::isSupported() const {
if (!ovr_Initialize(nullptr)) {
return false;
@ -92,10 +91,13 @@ bool OculusLegacyDisplayPlugin::isSupported() const {
}
void OculusLegacyDisplayPlugin::activate() {
WindowOpenGLDisplayPlugin::activate();
if (!(ovr_Initialize(nullptr))) {
Q_ASSERT(false);
qFatal("Failed to Initialize SDK");
}
_hswDismissed = false;
_hmd = ovrHmd_Create(0);
if (!_hmd) {
@ -107,13 +109,13 @@ void OculusLegacyDisplayPlugin::activate() {
_eyeFovs[eye] = _hmd->MaxEyeFov[eye];
ovrEyeRenderDesc erd = _eyeRenderDescs[eye] = ovrHmd_GetRenderDesc(_hmd, eye, _eyeFovs[eye]);
ovrMatrix4f ovrPerspectiveProjection =
ovrMatrix4f_Projection(erd.Fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded);
ovrMatrix4f_Projection(erd.Fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded);
_eyeProjections[eye] = toGlm(ovrPerspectiveProjection);
ovrPerspectiveProjection =
ovrMatrix4f_Projection(erd.Fov, 0.001f, 10.0f, ovrProjection_RightHanded);
ovrMatrix4f_Projection(erd.Fov, 0.001f, 10.0f, ovrProjection_RightHanded);
_compositeEyeProjections[eye] = toGlm(ovrPerspectiveProjection);
_eyeOffsets[eye] = erd.HmdToEyeViewOffset;
eyeSizes[eye] = toGlm(ovrHmd_GetFovTextureSize(_hmd, eye, erd.Fov, 1.0f));
});
@ -121,38 +123,43 @@ void OculusLegacyDisplayPlugin::activate() {
combined.LeftTan = std::max(_eyeFovs[Left].LeftTan, _eyeFovs[Right].LeftTan);
combined.RightTan = std::max(_eyeFovs[Left].RightTan, _eyeFovs[Right].RightTan);
ovrMatrix4f ovrPerspectiveProjection =
ovrMatrix4f_Projection(combined, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded);
ovrMatrix4f_Projection(combined, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded);
_eyeProjections[Mono] = toGlm(ovrPerspectiveProjection);
_desiredFramebufferSize = uvec2(
eyeSizes[0].x + eyeSizes[1].x,
std::max(eyeSizes[0].y, eyeSizes[1].y));
_frameIndex = 0;
_desiredFramebufferSize = uvec2(eyeSizes[0].x + eyeSizes[1].x,
std::max(eyeSizes[0].y, eyeSizes[1].y));
if (!ovrHmd_ConfigureTracking(_hmd,
ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0)) {
ovrTrackingCap_Orientation | ovrTrackingCap_Position | ovrTrackingCap_MagYawCorrection, 0)) {
qFatal("Could not attach to sensor device");
}
}
WindowOpenGLDisplayPlugin::activate();
void OculusLegacyDisplayPlugin::deactivate() {
WindowOpenGLDisplayPlugin::deactivate();
ovrHmd_Destroy(_hmd);
_hmd = nullptr;
ovr_Shutdown();
}
int screen = getHmdScreen();
if (screen != -1) {
_container->setFullscreen(qApp->screens()[screen]);
}
_window->installEventFilter(this);
_window->makeCurrent();
// DLL based display plugins MUST initialize GLEW inside the DLL code.
void OculusLegacyDisplayPlugin::customizeContext() {
static std::once_flag once;
std::call_once(once, []{
glewExperimental = true;
glewInit();
glGetError();
});
WindowOpenGLDisplayPlugin::customizeContext();
#if 0
ovrGLConfig config; memset(&config, 0, sizeof(ovrRenderAPIConfig));
auto& header = config.Config.Header;
header.API = ovrRenderAPI_OpenGL;
header.BackBufferSize = _hmd->Resolution;
header.Multisample = 1;
int distortionCaps = 0
| ovrDistortionCap_TimeWarp
;
int distortionCaps = ovrDistortionCap_TimeWarp;
memset(_eyeTextures, 0, sizeof(ovrTexture) * 2);
ovr_for_each_eye([&](ovrEyeType eye) {
auto& header = _eyeTextures[eye].Header;
@ -164,74 +171,36 @@ void OculusLegacyDisplayPlugin::activate() {
header.RenderViewport.Pos.x = header.RenderViewport.Size.w;
}
});
#ifndef NDEBUG
#ifndef NDEBUG
ovrBool result =
#endif
ovrHmd_ConfigureRendering(_hmd, &config.Config, distortionCaps, _eyeFovs, _eyeRenderDescs);
#endif
ovrHmd_ConfigureRendering(_hmd, &config.Config, distortionCaps, _eyeFovs, _eyeRenderDescs);
assert(result);
}
void OculusLegacyDisplayPlugin::deactivate() {
_window->removeEventFilter(this);
WindowOpenGLDisplayPlugin::deactivate();
#endif
QScreen* riftScreen = nullptr;
if (_hmdScreen >= 0) {
riftScreen = qApp->screens()[_hmdScreen];
}
_container->unsetFullscreen(riftScreen);
ovrHmd_Destroy(_hmd);
_hmd = nullptr;
ovr_Shutdown();
}
// DLL based display plugins MUST initialize GLEW inside the DLL code.
void OculusLegacyDisplayPlugin::customizeContext() {
glewExperimental = true;
glewInit();
glGetError();
WindowOpenGLDisplayPlugin::customizeContext();
#if 0
void OculusLegacyDisplayPlugin::uncustomizeContext() {
WindowOpenGLDisplayPlugin::uncustomizeContext();
}
void OculusLegacyDisplayPlugin::preDisplay() {
_window->makeCurrent();
}
void OculusLegacyDisplayPlugin::display(GLuint finalTexture, const glm::uvec2& sceneSize) {
++_frameIndex;
void OculusLegacyDisplayPlugin::internalPresent() {
ovrHmd_BeginFrame(_hmd, 0);
ovr_for_each_eye([&](ovrEyeType eye) {
reinterpret_cast<ovrGLTexture&>(_eyeTextures[eye]).OGL.TexId = finalTexture;
reinterpret_cast<ovrGLTexture&>(_eyeTextures[eye]).OGL.TexId = _currentSceneTexture;
});
ovrHmd_EndFrame(_hmd, _eyePoses, _eyeTextures);
}
// Pass input events on to the application
bool OculusLegacyDisplayPlugin::eventFilter(QObject* receiver, QEvent* event) {
if (!_hswDismissed && (event->type() == QEvent::KeyPress)) {
static ovrHSWDisplayState hswState;
ovrHmd_GetHSWDisplayState(_hmd, &hswState);
if (hswState.Displayed) {
ovrHmd_DismissHSWDisplay(_hmd);
} else {
_hswDismissed = true;
}
}
return WindowOpenGLDisplayPlugin::eventFilter(receiver, event);
}
// FIXME mirroring tot he main window is diffucult on OSX because it requires that we
// trigger a swap, which causes the client to wait for the v-sync of the main screen running
// at 60 Hz. This would introduce judder. Perhaps we can push mirroring to a separate
// thread
// FIXME If we move to the 'batch rendering on a different thread' we can possibly do this.
// however, we need to make sure it doesn't block the event handling.
void OculusLegacyDisplayPlugin::finishFrame() {
_window->doneCurrent();
};
#endif
int OculusLegacyDisplayPlugin::getHmdScreen() const {
return _hmdScreen;
}
float OculusLegacyDisplayPlugin::getTargetFrameRate() {
return TARGET_RATE_OculusLegacy;
}

View file

@ -24,11 +24,8 @@ public:
virtual void activate() override;
virtual void deactivate() override;
virtual bool eventFilter(QObject* receiver, QEvent* event) override;
virtual int getHmdScreen() const override;
virtual float getTargetFrameRate() override { return TARGET_RATE_OculusLegacy; }
// Stereo specific methods
virtual bool isHmd() const override { return true; }
virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const override;
@ -36,23 +33,24 @@ public:
virtual glm::uvec2 getRecommendedUiSize() const override { return uvec2(1920, 1080); }
virtual void resetSensors() override;
virtual glm::mat4 getEyeToHeadTransform(Eye eye) const override;
virtual glm::mat4 getHeadPose() const override;
virtual glm::mat4 getHeadPose(uint32_t frameIndex) const override;
virtual float getTargetFrameRate() override;
protected:
virtual void customizeContext() override;
virtual void preRender() override;
virtual void preDisplay() override;
virtual void display(GLuint finalTexture, const glm::uvec2& sceneSize) override;
// Do not perform swap in finish
virtual void finishFrame() override;
#if 0
virtual void uncustomizeContext() override;
virtual void internalPresent() override;
#endif
private:
static const QString NAME;
ovrHmd _hmd;
ovrTrackingState _trackingState;
mutable ovrTrackingState _trackingState;
ovrEyeRenderDesc _eyeRenderDescs[2];
ovrPosef _eyePoses[2];
mutable ovrPosef _eyePoses[2];
ovrVector3f _eyeOffsets[2];
ovrFovPort _eyeFovs[2];
mat4 _eyeProjections[3];

View file

@ -22,7 +22,7 @@ in vec3 _color;
void main(void) {
packDeferredFragment(
normalize(_normal.xyz),
glowIntensity,
1.0,
_color.rgb,
DEFAULT_SPECULAR, DEFAULT_SHININESS);
}

View file

@ -24,6 +24,7 @@
var lightsScriptURL = Script.resolvePath("../examples/toybox/lights/lightSwitch.js");
var targetsScriptURL = Script.resolvePath('../examples/toybox/ping_pong_gun/wallTarget.js');
var bowScriptURL = Script.resolvePath('../examples/toybox/bow/bow.js');
var raveStickEntityScriptURL = Script.resolvePath("../examples/flowArts/raveStick/raveStickEntityScript.js");
var basketballResetterScriptURL = Script.resolvePath('basketballsResetter.js');
var targetsResetterScriptURL = Script.resolvePath('targetsResetter.js');
@ -106,6 +107,13 @@
z: 505.78
});
createRaveStick({
x: 547.4,
y: 495.4,
z: 504.5
});
createCombinedArmChair({
x: 549.29,
y: 494.9,
@ -160,6 +168,111 @@
});
}
function createRaveStick(position) {
var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/raveStick.fbx";
var stick = Entities.addEntity({
type: "Model",
name: "raveStick",
modelURL: modelURL,
position: position,
shapeType: 'box',
collisionsWillMove: true,
script: raveStickEntityScriptURL,
dimensions: {
x: 0.06,
y: 0.06,
z: 0.31
},
gravity: {
x: 0,
y: -3,
z: 0
},
userData: JSON.stringify({
resetMe: {
resetMe: true
},
grabbableKey: {
spatialKey: {
relativePosition: {
x: 0,
y: 0,
z: -0.1
},
relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0)
},
invertSolidWhileHeld: true
}
})
});
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) {
var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/gun.fbx";
@ -1012,7 +1125,7 @@
z: 503.39
};
var rotation = Quat.fromPitchYawRollDegrees(0, 36, 0);
var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0);
var pingPongGun = Entities.addEntity({
type: "Model",
@ -1040,6 +1153,14 @@
resetMe: true
},
grabbableKey: {
spatialKey: {
relativePosition: {
x: -0.05,
y: 0,
z: 0.0
},
relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, -90)
},
invertSolidWhileHeld: true
}

View file

@ -23,10 +23,12 @@ var wandScriptURL = Script.resolvePath("../examples/toybox/bubblewand/wand.js");
var dollScriptURL = Script.resolvePath("../examples/toybox/doll/doll.js");
var lightsScriptURL = Script.resolvePath("../examples/toybox/lights/lightSwitch.js");
var bowScriptURL = Script.resolvePath("../examples/toybox/bow/bow.js");
var raveStickEntityScriptURL = Script.resolvePath("../examples/flowArts/raveStick/raveStickEntityScript.js");
var targetsScriptURL = Script.resolvePath('../examples/toybox/ping_pong_gun/wallTarget.js');
var basketballResetterScriptURL = Script.resolvePath('basketballsResetter.js');
var targetsResetterScriptURL = Script.resolvePath('targetsResetter.js');
MasterReset = function() {
var resetKey = "resetMe";
@ -80,6 +82,12 @@ MasterReset = function() {
z: 505.78
});
createRaveStick({
x: 547.4,
y: 495.4,
z: 504.5
});
createCombinedArmChair({
@ -94,6 +102,8 @@ MasterReset = function() {
z: 504.53
});
createPingPongBallGun();
createTargets();
createTargetResetter();
@ -137,6 +147,110 @@ MasterReset = function() {
});
}
function createRaveStick(position) {
var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/rave/raveStick.fbx";
var stick = Entities.addEntity({
type: "Model",
name: "raveStick",
modelURL: modelURL,
position: position,
shapeType: 'box',
collisionsWillMove: true,
script: raveStickEntityScriptURL,
dimensions: {
x: 0.06,
y: 0.06,
z: 0.31
},
gravity: {
x: 0,
y: -3,
z: 0
},
userData: JSON.stringify({
resetMe: {
resetMe: true
},
grabbableKey: {
spatialKey: {
relativePosition: {
x: 0,
y: 0,
z: -0.1
},
relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0)
},
invertSolidWhileHeld: true
}
})
});
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) {
var modelURL = "https://s3.amazonaws.com/hifi-public/eric/models/gun.fbx";
@ -992,7 +1106,7 @@ MasterReset = function() {
z: 503.39
};
var rotation = Quat.fromPitchYawRollDegrees(0, 36, 0);
var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0);
var pingPongGun = Entities.addEntity({
type: "Model",
@ -1020,6 +1134,14 @@ MasterReset = function() {
resetMe: true
},
grabbableKey: {
spatialKey: {
relativePosition: {
x: -0.05,
y: 0,
z: 0.0
},
relativeRotation: Quat.fromPitchYawRollDegrees(0,-90, -90)
},
invertSolidWhileHeld: true
}
@ -1349,7 +1471,7 @@ MasterReset = function() {
resetMe: true
},
grabbableKey: {
invertSolidWhileHeld: true
invertSolidWhileHeld: true
}
})
});