diff --git a/interface/src/raypick/ParabolaPointer.cpp b/interface/src/raypick/ParabolaPointer.cpp index 9371995a2a..fd6bdc7dbb 100644 --- a/interface/src/raypick/ParabolaPointer.cpp +++ b/interface/src/raypick/ParabolaPointer.cpp @@ -117,8 +117,6 @@ ParabolaPointer::RenderState::RenderState(const OverlayID& startID, const Overla _pathWidth = pathWidth; if (render::Item::isValidID(_pathID)) { auto renderItem = std::make_shared(pathColor, pathAlpha, pathWidth, isVisibleInSecondaryCamera, pathEnabled); - // TODO: update bounds properly - renderItem->editBound().setBox(glm::vec3(-16000.0f), 32000.0f); transaction.resetItem(_pathID, std::make_shared(renderItem)); scene->enqueueTransaction(transaction); } @@ -182,6 +180,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); } @@ -304,10 +303,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(); @@ -324,6 +323,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) { auto vs = parabola_vert::getShader(); diff --git a/interface/src/raypick/ParabolaPointer.h b/interface/src/raypick/ParabolaPointer.h index ee4977e1e4..93f9a7b055 100644 --- a/interface/src/raypick/ParabolaPointer.h +++ b/interface/src/raypick/ParabolaPointer.h @@ -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; } diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index 259c02d943..34f9841fe9 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -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. diff --git a/libraries/pointers/src/Pick.h b/libraries/pointers/src/Pick.h index dd59b50cc4..790c5dfd27 100644 --- a/libraries/pointers/src/Pick.h +++ b/libraries/pointers/src/Pick.h @@ -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 * @@ -154,6 +155,7 @@ public: * * * + * * *
{@link PickType(0)|PickType.Ray}
{@link PickType(0)|PickType.Stylus}
{@link PickType(0)|PickType.Parabola}
* @typedef {number} PickType