Merge pull request #13715 from SamGondelman/parabolic

Enable parabolic teleport
This commit is contained in:
John Conklin II 2018-08-09 13:12:17 -07:00 committed by GitHub
commit 6481aea2f4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 68 additions and 66 deletions

View file

@ -115,8 +115,6 @@ ParabolaPointer::RenderState::RenderState(const OverlayID& startID, const Overla
_pathWidth = pathWidth;
if (render::Item::isValidID(_pathID)) {
auto renderItem = std::make_shared<ParabolaRenderItem>(pathColor, pathAlpha, pathWidth, isVisibleInSecondaryCamera, pathEnabled);
// TODO: update bounds properly
renderItem->editBound().setBox(glm::vec3(-16000.0f), 32000.0f);
transaction.resetItem(_pathID, std::make_shared<ParabolaRenderItem::Payload>(renderItem));
scene->enqueueTransaction(transaction);
}
@ -180,6 +178,7 @@ void ParabolaPointer::RenderState::update(const glm::vec3& origin, const glm::ve
item.setAcceleration(acceleration);
item.setParabolicDistance(parabolicDistance);
item.setWidth(width);
item.updateBounds();
});
scene->enqueueTransaction(transaction);
}
@ -302,10 +301,10 @@ void ParabolaPointer::RenderState::ParabolaRenderItem::setVisible(bool visible)
}
void ParabolaPointer::RenderState::ParabolaRenderItem::updateKey() {
// FIXME: There's no way to designate a render item as non-shadow-reciever, and since a parabola's bounding box covers the entire domain,
// it seems to block all shadows. I think this is a bug with shadows.
//auto builder = _parabolaData.color.a < 1.0f ? render::ItemKey::Builder::transparentShape() : render::ItemKey::Builder::opaqueShape();
auto builder = render::ItemKey::Builder::transparentShape();
auto builder = _parabolaData.color.a < 1.0f ? render::ItemKey::Builder::transparentShape() : render::ItemKey::Builder::opaqueShape();
// TODO: parabolas should cast shadows, but they're so thin that the cascaded shadow maps make them look pretty bad
//builder.withShadowCaster();
if (_enabled && _visible) {
builder.withVisible();
@ -322,6 +321,33 @@ void ParabolaPointer::RenderState::ParabolaRenderItem::updateKey() {
_key = builder.build();
}
void ParabolaPointer::RenderState::ParabolaRenderItem::updateBounds() {
glm::vec3 max = _origin;
glm::vec3 min = _origin;
glm::vec3 end = _origin + _parabolaData.velocity * _parabolaData.parabolicDistance +
0.5f * _parabolaData.acceleration * _parabolaData.parabolicDistance * _parabolaData.parabolicDistance;
max = glm::max(max, end);
min = glm::min(min, end);
for (int i = 0; i < 3; i++) {
if (fabsf(_parabolaData.velocity[i]) > EPSILON && fabsf(_parabolaData.acceleration[i]) > EPSILON) {
float maxT = -_parabolaData.velocity[i] / _parabolaData.acceleration[i];
if (maxT > 0.0f && maxT < _parabolaData.parabolicDistance) {
glm::vec3 maxPoint = _origin + _parabolaData.velocity * maxT + 0.5f * _parabolaData.acceleration * maxT * maxT;
max = glm::max(max, maxPoint);
min = glm::min(min, maxPoint);
}
}
}
glm::vec3 halfWidth = glm::vec3(0.5f * _parabolaData.width);
max += halfWidth;
min -= halfWidth;
_bound = AABox(min, max - min);
}
const gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::getParabolaPipeline() {
if (!_parabolaPipeline || !_transparentParabolaPipeline) {
gpu::ShaderPointer program = gpu::Shader::createProgram(shader::render_utils::program::parabola);

View file

@ -36,6 +36,7 @@ public:
void setVisible(bool visible);
void updateKey();
void updateUniformBuffer() { _uniformBuffer->setSubData(0, _parabolaData); }
void updateBounds();
void setColor(const glm::vec3& color) { _parabolaData.color = glm::vec4(color, _parabolaData.color.a); }
void setAlpha(const float& alpha) { _parabolaData.color.a = alpha; }

View file

@ -138,7 +138,7 @@ public:
* @property {Vec3} intersection The intersection point in world-space.
* @property {Vec3} surfaceNormal The surface normal at the intersected point. All NANs if type == INTERSECTED_HUD.
* @property {Variant} extraInfo Additional intersection details when available for Model objects.
* @property {StylusTip} parabola The PickParabola that was used. Valid even if there was no intersection.
* @property {PickParabola} parabola The PickParabola that was used. Valid even if there was no intersection.
*/
/**jsdoc

View file

@ -92,7 +92,7 @@ unsigned int PointerScriptingInterface::createStylus(const QVariant& properties)
* @typedef {object} Pointers.LaserPointerProperties
* @property {boolean} [faceAvatar=false] If true, the end of the Pointer will always rotate to face the avatar.
* @property {boolean} [centerEndY=true] If false, the end of the Pointer will be moved up by half of its height.
* @property {boolean} [lockEnd=false] If true, the end of the Pointer will lock on to the center of the object at which the laser is pointing.
* @property {boolean} [lockEnd=false] If true, the end of the Pointer will lock on to the center of the object at which the pointer is pointing.
* @property {boolean} [distanceScaleEnd=false] If true, the dimensions of the end of the Pointer will scale linearly with distance.
* @property {boolean} [scaleWithAvatar=false] If true, the width of the Pointer's path will scale linearly with your avatar's scale.
* @property {boolean} [followNormal=false] If true, the end of the Pointer will rotate to follow the normal of the intersected surface.
@ -207,9 +207,10 @@ unsigned int PointerScriptingInterface::createLaserPointer(const QVariant& prope
* The rendering properties of the parabolic path
*
* @typedef {object} Pointers.ParabolaProperties
* @property {Color} color The color of the parabola.
* @property {number} alpha The alpha of the parabola.
* @property {number} width The width of the parabola, in meters.
* @property {Color} color=255,255,255 The color of the parabola.
* @property {number} alpha=1.0 The alpha of the parabola.
* @property {number} width=0.01 The width of the parabola, in meters.
* @property {boolean} isVisibleInSecondaryCamera=false The width of the parabola, in meters.
*/
/**jsdoc
* A set of properties used to define the visual aspect of a Parabola Pointer in the case that the Pointer is not intersecting something. Same as a {@link Pointers.ParabolaPointerRenderState},
@ -232,10 +233,10 @@ unsigned int PointerScriptingInterface::createLaserPointer(const QVariant& prope
*/
/**jsdoc
* A set of properties that can be passed to {@link Pointers.createPointer} to create a new Pointer. Contains the relevant {@link Picks.PickProperties} to define the underlying Pick.
* @typedef {object} Pointers.LaserPointerProperties
* @typedef {object} Pointers.ParabolaPointerProperties
* @property {boolean} [faceAvatar=false] If true, the end of the Pointer will always rotate to face the avatar.
* @property {boolean} [centerEndY=true] If false, the end of the Pointer will be moved up by half of its height.
* @property {boolean} [lockEnd=false] If true, the end of the Pointer will lock on to the center of the object at which the laser is pointing.
* @property {boolean} [lockEnd=false] If true, the end of the Pointer will lock on to the center of the object at which the pointer is pointing.
* @property {boolean} [distanceScaleEnd=false] If true, the dimensions of the end of the Pointer will scale linearly with distance.
* @property {boolean} [scaleWithAvatar=false] If true, the width of the Pointer's path will scale linearly with your avatar's scale.
* @property {boolean} [followNormal=false] If true, the end of the Pointer will rotate to follow the normal of the intersected surface.

View file

@ -145,6 +145,7 @@ public:
*
* @property {number} Ray Ray Picks intersect a ray with the nearest object in front of them, along a given direction.
* @property {number} Stylus Stylus Picks provide "tapping" functionality on/into flat surfaces.
* @property {number} Parabola Parabola Picks intersect a parabola with the nearest object in front of them, with a given initial velocity and acceleration.
*/
/**jsdoc
* <table>
@ -154,6 +155,7 @@ public:
* <tbody>
* <tr><td><code>{@link PickType(0)|PickType.Ray}</code></td><td></td></tr>
* <tr><td><code>{@link PickType(0)|PickType.Stylus}</code></td><td></td></tr>
* <tr><td><code>{@link PickType(0)|PickType.Parabola}</code></td><td></td></tr>
* </tbody>
* </table>
* @typedef {number} PickType

View file

@ -22,7 +22,6 @@ Script.include("/~/system/libraries/controllers.js");
(function() { // BEGIN LOCAL_SCOPE
var TARGET_MODEL_URL = Script.resolvePath("../../assets/models/teleport-destination.fbx");
var TOO_CLOSE_MODEL_URL = Script.resolvePath("../../assets/models/teleport-cancel.fbx");
var SEAT_MODEL_URL = Script.resolvePath("../../assets/models/teleport-seat.fbx");
var TARGET_MODEL_DIMENSIONS = {
@ -49,8 +48,6 @@ Script.include("/~/system/libraries/controllers.js");
blue: 73
};
var COOL_IN_DURATION = 300;
var handInfo = {
right: {
controllerInput: Controller.Standard.RightHand
@ -61,37 +58,19 @@ Script.include("/~/system/libraries/controllers.js");
};
var cancelPath = {
type: "line3d",
color: COLORS_TELEPORT_CANCEL,
ignorePickIntersection: true,
alpha: 1,
solid: true,
drawInFront: true,
glow: 1.0
width: 0.025
};
var teleportPath = {
type: "line3d",
color: COLORS_TELEPORT_CAN_TELEPORT,
ignorePickIntersection: true,
alpha: 1,
solid: true,
drawInFront: true,
glow: 1.0
width: 0.025
};
var seatPath = {
type: "line3d",
color: COLORS_TELEPORT_SEAT,
ignorePickIntersection: true,
alpha: 1,
solid: true,
drawInFront: true,
glow: 1.0
};
var cancelEnd = {
type: "model",
url: TOO_CLOSE_MODEL_URL,
dimensions: TARGET_MODEL_DIMENSIONS,
ignorePickIntersection: true
width: 0.025
};
var teleportEnd = {
type: "model",
@ -107,20 +86,18 @@ Script.include("/~/system/libraries/controllers.js");
};
var teleportRenderStates = [{name: "cancel", path: cancelPath, end: cancelEnd},
var teleportRenderStates = [{name: "cancel", path: cancelPath},
{name: "teleport", path: teleportPath, end: teleportEnd},
{name: "seat", path: seatPath, end: seatEnd}];
var DEFAULT_DISTANCE = 50;
var DEFAULT_DISTANCE = 8.0;
var teleportDefaultRenderStates = [{name: "cancel", distance: DEFAULT_DISTANCE, path: cancelPath}];
var coolInTimeout = null;
var ignoredEntities = [];
var TELEPORTER_STATES = {
IDLE: 'idle',
COOL_IN: 'cool_in',
TARGETTING: 'targetting',
TARGETTING_INVALID: 'targetting_invalid'
};
@ -133,7 +110,7 @@ Script.include("/~/system/libraries/controllers.js");
SEAT: 'seat' // The current target is a seat
};
var speed = 7.0;
var speed = 12.0;
var accelerationAxis = {x: 0.0, y: -5.0, z: 0.0};
function Teleporter(hand) {
@ -151,8 +128,10 @@ Script.include("/~/system/libraries/controllers.js");
return otherModule;
};
this.teleportParabolaHandVisible = Pointers.createPointer(PickType.Ray, {
this.teleportParabolaHandVisible = Pointers.createPointer(PickType.Parabola, {
joint: (_this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
dirOffset: { x: 0, y: 1, z: 0.1 },
posOffset: { x: (_this.hand === RIGHT_HAND) ? 0.03 : -0.03, y: 0.2, z: 0.02 },
filter: Picks.PICK_ENTITIES,
faceAvatar: true,
scaleWithAvatar: true,
@ -161,10 +140,13 @@ Script.include("/~/system/libraries/controllers.js");
accelerationAxis: accelerationAxis,
rotateAccelerationWithAvatar: true,
renderStates: teleportRenderStates,
defaultRenderStates: teleportDefaultRenderStates
defaultRenderStates: teleportDefaultRenderStates,
maxDistance: 8.0
});
this.teleportParabolaHandInvisible = Pointers.createPointer(PickType.Ray, {
this.teleportParabolaHandInvisible = Pointers.createPointer(PickType.Parabola, {
joint: (_this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
dirOffset: { x: 0, y: 1, z: 0.1 },
posOffset: { x: (_this.hand === RIGHT_HAND) ? 0.03 : -0.03, y: 0.2, z: 0.02 },
filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE,
faceAvatar: true,
scaleWithAvatar: true,
@ -172,9 +154,10 @@ Script.include("/~/system/libraries/controllers.js");
speed: speed,
accelerationAxis: accelerationAxis,
rotateAccelerationWithAvatar: true,
renderStates: teleportRenderStates
renderStates: teleportRenderStates,
maxDistance: 8.0
});
this.teleportParabolaHeadVisible = Pointers.createPointer(PickType.Ray, {
this.teleportParabolaHeadVisible = Pointers.createPointer(PickType.Parabola, {
joint: "Avatar",
filter: Picks.PICK_ENTITIES,
faceAvatar: true,
@ -184,9 +167,10 @@ Script.include("/~/system/libraries/controllers.js");
accelerationAxis: accelerationAxis,
rotateAccelerationWithAvatar: true,
renderStates: teleportRenderStates,
defaultRenderStates: teleportDefaultRenderStates
defaultRenderStates: teleportDefaultRenderStates,
maxDistance: 8.0
});
this.teleportParabolaHeadInvisible = Pointers.createPointer(PickType.Ray, {
this.teleportParabolaHeadInvisible = Pointers.createPointer(PickType.Parabola, {
joint: "Avatar",
filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE,
faceAvatar: true,
@ -195,7 +179,8 @@ Script.include("/~/system/libraries/controllers.js");
speed: speed,
accelerationAxis: accelerationAxis,
rotateAccelerationWithAvatar: true,
renderStates: teleportRenderStates
renderStates: teleportRenderStates,
maxDistance: 8.0
});
this.cleanup = function() {
@ -216,16 +201,7 @@ Script.include("/~/system/libraries/controllers.js");
100);
this.enterTeleport = function() {
if (coolInTimeout !== null) {
Script.clearTimeout(coolInTimeout);
}
this.state = TELEPORTER_STATES.COOL_IN;
coolInTimeout = Script.setTimeout(function() {
if (_this.state === TELEPORTER_STATES.COOL_IN) {
_this.state = TELEPORTER_STATES.TARGETTING;
}
}, COOL_IN_DURATION);
this.state = TELEPORTER_STATES.TARGETTING;
};
this.isReady = function(controllerData, deltaTime) {
@ -287,11 +263,7 @@ Script.include("/~/system/libraries/controllers.js");
} else if (teleportLocationType === TARGET.INVALID || teleportLocationType === TARGET.INVISIBLE) {
this.setTeleportState(mode, "", "cancel");
} else if (teleportLocationType === TARGET.SURFACE) {
if (this.state === TELEPORTER_STATES.COOL_IN) {
this.setTeleportState(mode, "cancel", "");
} else {
this.setTeleportState(mode, "teleport", "");
}
this.setTeleportState(mode, "teleport", "");
} else if (teleportLocationType === TARGET.SEAT) {
this.setTeleportState(mode, "", "seat");
}
@ -304,7 +276,7 @@ Script.include("/~/system/libraries/controllers.js");
return makeRunningValues(true, [], []);
}
if (target === TARGET.NONE || target === TARGET.INVALID || this.state === TELEPORTER_STATES.COOL_IN) {
if (target === TARGET.NONE || target === TARGET.INVALID) {
// Do nothing
} else if (target === TARGET.SEAT) {
Entities.callEntityMethod(result.objectID, 'sit');