mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 09:44:21 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into 20736
Conflicts: examples/controllers/handControllerGrab.js
This commit is contained in:
commit
505f4ce7e4
51 changed files with 2165 additions and 330 deletions
|
@ -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)
|
||||
|
|
|
@ -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);
|
|
@ -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();
|
||||
|
|
145
examples/flowArts/arcBall/arcBall.js
Normal file
145
examples/flowArts/arcBall/arcBall.js
Normal 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;
|
||||
}
|
155
examples/flowArts/arcBall/arcBallEntityScript.js
Normal file
155
examples/flowArts/arcBall/arcBallEntityScript.js
Normal 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();
|
||||
});
|
91
examples/flowArts/flowArtsHutSpawner.js
Normal file
91
examples/flowArts/flowArtsHutSpawner.js
Normal 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);
|
145
examples/flowArts/lightBall/lightBall.js
Normal file
145
examples/flowArts/lightBall/lightBall.js
Normal 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;
|
||||
}
|
67
examples/flowArts/lightSaber/lightSaber.js
Normal file
67
examples/flowArts/lightSaber/lightSaber.js
Normal 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;
|
||||
}
|
116
examples/flowArts/lightSaber/lightSaberEntityScript.js
Normal file
116
examples/flowArts/lightSaber/lightSaberEntityScript.js
Normal 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();
|
||||
});
|
191
examples/flowArts/lightTrails.js
Normal file
191
examples/flowArts/lightTrails.js
Normal 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));
|
||||
}
|
90
examples/flowArts/raveStick/raveStick.js
Normal file
90
examples/flowArts/raveStick/raveStick.js
Normal 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;
|
||||
}
|
141
examples/flowArts/raveStick/raveStickEntityScript.js
Normal file
141
examples/flowArts/raveStick/raveStickEntityScript.js
Normal 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));
|
||||
}
|
||||
});
|
|
@ -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 = [];
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
})
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ void main(void) {
|
|||
// pass along the diffuse color
|
||||
varColor = colorToLinearRGBA(inColor);
|
||||
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ void main(void) {
|
|||
|
||||
packDeferredFragment(
|
||||
normalize(_normal.xyz),
|
||||
glowIntensity * texel.a,
|
||||
texel.a,
|
||||
_color.rgb * texel.rgb,
|
||||
DEFAULT_SPECULAR, DEFAULT_SHININESS);
|
||||
}
|
|
@ -27,7 +27,7 @@ void main(void) {
|
|||
|
||||
packDeferredFragmentLightmap(
|
||||
normalize(_normal),
|
||||
glowIntensity * texel.a,
|
||||
texel.a,
|
||||
_color.rgb,
|
||||
DEFAULT_SPECULAR, DEFAULT_SHININESS,
|
||||
texel.rgb);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -115,8 +115,6 @@ public:
|
|||
std::shared_ptr<gpu::Texture> _whiteTexture;
|
||||
|
||||
RenderDetails _details;
|
||||
|
||||
float _alphaThreshold = 0.5f;
|
||||
};
|
||||
|
||||
#endif // hifi_RenderArgs_h
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -98,6 +98,8 @@ private:
|
|||
|
||||
static const QString NAME;
|
||||
static const QString HYDRA_ID_STRING;
|
||||
|
||||
static bool _sixenseLoaded;
|
||||
};
|
||||
|
||||
#endif // hifi_SixenseManager_h
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -22,7 +22,7 @@ in vec3 _color;
|
|||
void main(void) {
|
||||
packDeferredFragment(
|
||||
normalize(_normal.xyz),
|
||||
glowIntensity,
|
||||
1.0,
|
||||
_color.rgb,
|
||||
DEFAULT_SPECULAR, DEFAULT_SHININESS);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
})
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue