From 318ef907b8b6af4983d69d6a3b2bdc42a99a630c Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 23 Jul 2018 16:41:26 -0700 Subject: [PATCH] parabola/polyvox, fixing some bugs --- interface/src/avatar/AvatarManager.cpp | 4 + interface/src/raypick/ParabolaPick.cpp | 2 +- interface/src/raypick/ParabolaPointer.cpp | 26 ++++-- interface/src/raypick/ParabolaPointer.h | 3 + interface/src/raypick/PathPointer.cpp | 4 +- interface/src/raypick/PathPointer.h | 4 +- interface/src/raypick/RayPick.cpp | 2 +- interface/src/ui/overlays/Overlays.cpp | 78 +++++------------ interface/src/ui/overlays/Overlays.h | 6 +- libraries/avatars/src/AvatarData.cpp | 11 ++- libraries/avatars/src/AvatarData.h | 4 + .../src/RenderablePolyVoxEntityItem.cpp | 84 ++++++++++++++++++- .../src/RenderablePolyVoxEntityItem.h | 10 ++- .../entities/src/EntityScriptingInterface.cpp | 69 +-------------- .../entities/src/EntityScriptingInterface.h | 2 - libraries/entities/src/PolyLineEntityItem.h | 2 +- libraries/entities/src/PolyVoxEntityItem.h | 2 +- libraries/render-utils/src/Model.cpp | 4 +- libraries/render-utils/src/parabola.slv | 5 +- libraries/shared/src/BoxBase.cpp | 46 ++++++++++ libraries/shared/src/BoxBase.h | 22 +++++ libraries/shared/src/GeometryUtil.cpp | 28 +++---- .../controllers/controllerModules/teleport.js | 16 ++-- 23 files changed, 257 insertions(+), 177 deletions(-) create mode 100644 libraries/shared/src/BoxBase.cpp diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 40530b7701..fab512f787 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -618,6 +618,8 @@ RayToAvatarIntersectionResult AvatarManager::findRayIntersectionVector(const Pic result.intersects = true; result.avatarID = avatar->getID(); result.distance = distance; + result.face = face; + result.surfaceNormal = surfaceNormal; result.extraInfo = extraInfo; } } @@ -688,6 +690,8 @@ ParabolaToAvatarIntersectionResult AvatarManager::findParabolaIntersectionVector result.intersects = true; result.avatarID = avatar->getID(); result.parabolicDistance = parabolicDistance; + result.face = face; + result.surfaceNormal = surfaceNormal; result.extraInfo = extraInfo; } } diff --git a/interface/src/raypick/ParabolaPick.cpp b/interface/src/raypick/ParabolaPick.cpp index 3d1b1c410d..be3fa57b0c 100644 --- a/interface/src/raypick/ParabolaPick.cpp +++ b/interface/src/raypick/ParabolaPick.cpp @@ -39,7 +39,7 @@ PickResultPointer ParabolaPick::getOverlayIntersection(const PickParabola& pick) PickResultPointer ParabolaPick::getAvatarIntersection(const PickParabola& pick) { ParabolaToAvatarIntersectionResult avatarRes = DependencyManager::get()->findParabolaIntersectionVector(pick, getIncludeItemsAs(), getIgnoreItemsAs()); if (avatarRes.intersects) { - return std::make_shared(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.parabolicDistance, avatarRes.intersection, pick, glm::vec3(NAN), avatarRes.extraInfo); + return std::make_shared(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.parabolicDistance, avatarRes.intersection, pick, avatarRes.surfaceNormal, avatarRes.extraInfo); } else { return std::make_shared(pick.toVariantMap()); } diff --git a/interface/src/raypick/ParabolaPointer.cpp b/interface/src/raypick/ParabolaPointer.cpp index 42612ef46d..6ae516bfa4 100644 --- a/interface/src/raypick/ParabolaPointer.cpp +++ b/interface/src/raypick/ParabolaPointer.cpp @@ -156,7 +156,6 @@ void ParabolaPointer::RenderState::editParabola(const glm::vec3& color, float al item.setIsVisibleInSecondaryCamera(isVisibleInSecondaryCamera); item.setEnabled(enabled); item.updateKey(); - item.updateUniformBuffer(); }); scene->enqueueTransaction(transaction); } @@ -182,7 +181,6 @@ void ParabolaPointer::RenderState::update(const glm::vec3& origin, const glm::ve item.setAcceleration(acceleration); item.setParabolicDistance(parabolicDistance); item.setWidth(width); - item.updateUniformBuffer(); }); scene->enqueueTransaction(transaction); } @@ -293,7 +291,6 @@ ParabolaPointer::RenderState::ParabolaRenderItem::ParabolaRenderItem(const glm:: setAlpha(alpha); setWidth(width); updateKey(); - updateUniformBuffer(); } void ParabolaPointer::RenderState::ParabolaRenderItem::setVisible(bool visible) { @@ -302,12 +299,16 @@ void ParabolaPointer::RenderState::ParabolaRenderItem::setVisible(bool visible) } else { _key = render::ItemKey::Builder(_key).withInvisible(); } + _visible = visible; } void ParabolaPointer::RenderState::ParabolaRenderItem::updateKey() { - auto builder = _parabolaData.color.a < 1.0f ? render::ItemKey::Builder::transparentShape() : render::ItemKey::Builder::opaqueShape(); + // 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(); - if (_enabled) { + if (_enabled && _visible) { builder.withVisible(); } else { builder.withInvisible(); @@ -358,6 +359,10 @@ const gpu::PipelinePointer ParabolaPointer::RenderState::ParabolaRenderItem::get } void ParabolaPointer::RenderState::ParabolaRenderItem::render(RenderArgs* args) { + if (!_visible) { + return; + } + gpu::Batch& batch = *(args->_batch); Transform transform; @@ -366,12 +371,17 @@ void ParabolaPointer::RenderState::ParabolaRenderItem::render(RenderArgs* args) batch.setPipeline(getParabolaPipeline()); + const int MAX_SECTIONS = 100; + if (glm::length2(_parabolaData.acceleration) < EPSILON) { + _parabolaData.numSections = 1; + } else { + _parabolaData.numSections = glm::clamp((int)(_parabolaData.parabolicDistance + 1) * 10, 1, MAX_SECTIONS); + } + updateUniformBuffer(); batch.setUniformBuffer(0, _uniformBuffer); - // TODO: variable number of sections, depending on ? (acceleration?, parabolicDistance?) - const int NUM_SECTIONS = 25; // must match value in parabola.slv // We draw 2 * n + 2 vertices for a triangle strip - batch.draw(gpu::TRIANGLE_STRIP, 2 * NUM_SECTIONS + 2, 0); + batch.draw(gpu::TRIANGLE_STRIP, 2 * _parabolaData.numSections + 2, 0); } namespace render { diff --git a/interface/src/raypick/ParabolaPointer.h b/interface/src/raypick/ParabolaPointer.h index 4a4a27e8fc..28e34523c2 100644 --- a/interface/src/raypick/ParabolaPointer.h +++ b/interface/src/raypick/ParabolaPointer.h @@ -57,6 +57,7 @@ public: glm::vec3 _origin { 0.0f }; bool _isVisibleInSecondaryCamera { DEFAULT_PARABOLA_ISVISIBLEINSECONDARYCAMERA }; + bool _visible { false }; bool _enabled { false }; struct ParabolaData { @@ -65,6 +66,8 @@ public: vec3 acceleration { 0.0f }; float width { DEFAULT_PARABOLA_WIDTH }; vec4 color { vec4(DEFAULT_PARABOLA_COLOR)}; + int numSections { 0 }; + ivec3 spare; }; ParabolaData _parabolaData; diff --git a/interface/src/raypick/PathPointer.cpp b/interface/src/raypick/PathPointer.cpp index 664e124ea0..13ec063b80 100644 --- a/interface/src/raypick/PathPointer.cpp +++ b/interface/src/raypick/PathPointer.cpp @@ -113,13 +113,12 @@ PickResultPointer PathPointer::getVisualPickResult(const PickResultPointer& pick const glm::vec3 DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f); endVec = pos + rot * (dim * (DEFAULT_REGISTRATION_POINT - registrationPoint)); glm::vec3 direction = endVec - origin; - float distance = glm::distance(origin, endVec); + distance = glm::distance(origin, endVec); glm::vec3 normalizedDirection = glm::normalize(direction); type = _lockEndObject.isOverlay ? IntersectionType::OVERLAY : IntersectionType::ENTITY; id = _lockEndObject.id; intersection = endVec; - distance = distance; surfaceNormal = -normalizedDirection; setVisualPickResultInternal(visualPickResult, type, id, intersection, distance, surfaceNormal); } else if (type != IntersectionType::NONE && _lockEnd) { @@ -134,7 +133,6 @@ PickResultPointer PathPointer::getVisualPickResult(const PickResultPointer& pick glm::vec3 direction = endVec - origin; distance = glm::distance(origin, endVec); glm::vec3 normalizedDirection = glm::normalize(direction); - type = type; intersection = endVec; surfaceNormal = -normalizedDirection; setVisualPickResultInternal(visualPickResult, type, id, intersection, distance, surfaceNormal); diff --git a/interface/src/raypick/PathPointer.h b/interface/src/raypick/PathPointer.h index 1e85ad7a92..a8b3d1bcdb 100644 --- a/interface/src/raypick/PathPointer.h +++ b/interface/src/raypick/PathPointer.h @@ -79,11 +79,11 @@ public: void updateVisuals(const PickResultPointer& prevRayPickResult) override; protected: - PointerTriggers _triggers; - float _pathLength { 0.0f }; RenderStateMap _renderStates; DefaultRenderStateMap _defaultRenderStates; std::string _currentRenderState { "" }; + PointerTriggers _triggers; + float _pathLength { 0.0f }; bool _faceAvatar; bool _followNormal; bool _centerEndY; diff --git a/interface/src/raypick/RayPick.cpp b/interface/src/raypick/RayPick.cpp index 75b5e77fd8..96b41dcc72 100644 --- a/interface/src/raypick/RayPick.cpp +++ b/interface/src/raypick/RayPick.cpp @@ -39,7 +39,7 @@ PickResultPointer RayPick::getOverlayIntersection(const PickRay& pick) { PickResultPointer RayPick::getAvatarIntersection(const PickRay& pick) { RayToAvatarIntersectionResult avatarRes = DependencyManager::get()->findRayIntersectionVector(pick, getIncludeItemsAs(), getIgnoreItemsAs()); if (avatarRes.intersects) { - return std::make_shared(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, pick, glm::vec3(NAN), avatarRes.extraInfo); + return std::make_shared(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, pick, avatarRes.surfaceNormal, avatarRes.extraInfo); } else { return std::make_shared(pick.toVariantMap()); } diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 9a054ffaa3..de4ff94719 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -622,75 +622,37 @@ ParabolaToOverlayIntersectionResult Overlays::findParabolaIntersectionVector(con } QScriptValue RayToOverlayIntersectionResultToScriptValue(QScriptEngine* engine, const RayToOverlayIntersectionResult& value) { - auto obj = engine->newObject(); + QScriptValue obj = engine->newObject(); obj.setProperty("intersects", value.intersects); - obj.setProperty("overlayID", OverlayIDtoScriptValue(engine, value.overlayID)); + QScriptValue overlayIDValue = quuidToScriptValue(engine, value.overlayID); + obj.setProperty("overlayID", overlayIDValue); obj.setProperty("distance", value.distance); + obj.setProperty("face", boxFaceToString(value.face)); - QString faceName = ""; - // handle BoxFace - switch (value.face) { - case MIN_X_FACE: - faceName = "MIN_X_FACE"; - break; - case MAX_X_FACE: - faceName = "MAX_X_FACE"; - break; - case MIN_Y_FACE: - faceName = "MIN_Y_FACE"; - break; - case MAX_Y_FACE: - faceName = "MAX_Y_FACE"; - break; - case MIN_Z_FACE: - faceName = "MIN_Z_FACE"; - break; - case MAX_Z_FACE: - faceName = "MAX_Z_FACE"; - break; - default: - case UNKNOWN_FACE: - faceName = "UNKNOWN_FACE"; - break; - } - obj.setProperty("face", faceName); - auto intersection = vec3toScriptValue(engine, value.intersection); + QScriptValue intersection = vec3toScriptValue(engine, value.intersection); obj.setProperty("intersection", intersection); + QScriptValue surfaceNormal = vec3toScriptValue(engine, value.surfaceNormal); + obj.setProperty("surfaceNormal", surfaceNormal); obj.setProperty("extraInfo", engine->toScriptValue(value.extraInfo)); return obj; } -void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& objectVar, RayToOverlayIntersectionResult& value) { - QVariantMap object = objectVar.toVariant().toMap(); - value.intersects = object["intersects"].toBool(); - value.overlayID = OverlayID(QUuid(object["overlayID"].toString())); - value.distance = object["distance"].toFloat(); +void RayToOverlayIntersectionResultFromScriptValue(const QScriptValue& object, RayToOverlayIntersectionResult& value) { + value.intersects = object.property("intersects").toVariant().toBool(); + QScriptValue overlayIDValue = object.property("overlayID"); + quuidFromScriptValue(overlayIDValue, value.overlayID); + value.distance = object.property("distance").toVariant().toFloat(); + value.face = boxFaceFromString(object.property("face").toVariant().toString()); - QString faceName = object["face"].toString(); - if (faceName == "MIN_X_FACE") { - value.face = MIN_X_FACE; - } else if (faceName == "MAX_X_FACE") { - value.face = MAX_X_FACE; - } else if (faceName == "MIN_Y_FACE") { - value.face = MIN_Y_FACE; - } else if (faceName == "MAX_Y_FACE") { - value.face = MAX_Y_FACE; - } else if (faceName == "MIN_Z_FACE") { - value.face = MIN_Z_FACE; - } else if (faceName == "MAX_Z_FACE") { - value.face = MAX_Z_FACE; - } else { - value.face = UNKNOWN_FACE; - }; - auto intersection = object["intersection"]; + QScriptValue intersection = object.property("intersection"); if (intersection.isValid()) { - bool valid; - auto newIntersection = vec3FromVariant(intersection, valid); - if (valid) { - value.intersection = newIntersection; - } + vec3FromScriptValue(intersection, value.intersection); } - value.extraInfo = object["extraInfo"].toMap(); + QScriptValue surfaceNormal = object.property("surfaceNormal"); + if (surfaceNormal.isValid()) { + vec3FromScriptValue(surfaceNormal, value.surfaceNormal); + } + value.extraInfo = object.property("extraInfo").toVariant().toMap(); } bool Overlays::isLoaded(OverlayID id) { diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 33768416fe..21b9e93648 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -59,7 +59,7 @@ class RayToOverlayIntersectionResult { public: bool intersects { false }; OverlayID overlayID { UNKNOWN_OVERLAY_ID }; - float distance { 0 }; + float distance { 0.0f }; BoxFace face { UNKNOWN_FACE }; glm::vec3 surfaceNormal; glm::vec3 intersection; @@ -73,8 +73,8 @@ class ParabolaToOverlayIntersectionResult { public: bool intersects { false }; OverlayID overlayID { UNKNOWN_OVERLAY_ID }; - float distance { 0 }; - float parabolicDistance { 0 }; + float distance { 0.0f }; + float parabolicDistance { 0.0f }; BoxFace face { UNKNOWN_FACE }; glm::vec3 surfaceNormal; glm::vec3 intersection; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index fc72f34304..abdac838b6 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -2555,15 +2555,18 @@ glm::mat4 AvatarData::getControllerRightHandMatrix() const { return _controllerRightHandMatrixCache.get(); } - QScriptValue RayToAvatarIntersectionResultToScriptValue(QScriptEngine* engine, const RayToAvatarIntersectionResult& value) { QScriptValue obj = engine->newObject(); obj.setProperty("intersects", value.intersects); QScriptValue avatarIDValue = quuidToScriptValue(engine, value.avatarID); obj.setProperty("avatarID", avatarIDValue); obj.setProperty("distance", value.distance); + obj.setProperty("face", boxFaceToString(value.face)); + QScriptValue intersection = vec3toScriptValue(engine, value.intersection); obj.setProperty("intersection", intersection); + QScriptValue surfaceNormal = vec3toScriptValue(engine, value.surfaceNormal); + obj.setProperty("surfaceNormal", surfaceNormal); obj.setProperty("extraInfo", engine->toScriptValue(value.extraInfo)); return obj; } @@ -2573,10 +2576,16 @@ void RayToAvatarIntersectionResultFromScriptValue(const QScriptValue& object, Ra QScriptValue avatarIDValue = object.property("avatarID"); quuidFromScriptValue(avatarIDValue, value.avatarID); value.distance = object.property("distance").toVariant().toFloat(); + value.face = boxFaceFromString(object.property("face").toVariant().toString()); + QScriptValue intersection = object.property("intersection"); if (intersection.isValid()) { vec3FromScriptValue(intersection, value.intersection); } + QScriptValue surfaceNormal = object.property("surfaceNormal"); + if (surfaceNormal.isValid()) { + vec3FromScriptValue(surfaceNormal, value.surfaceNormal); + } value.extraInfo = object.property("extraInfo").toVariant().toMap(); } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 5e799b8401..0f850aaf24 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -1527,7 +1527,9 @@ public: bool intersects { false }; QUuid avatarID; float distance { 0.0f }; + BoxFace face; glm::vec3 intersection; + glm::vec3 surfaceNormal; QVariantMap extraInfo; }; Q_DECLARE_METATYPE(RayToAvatarIntersectionResult) @@ -1540,7 +1542,9 @@ public: QUuid avatarID; float distance { 0.0f }; float parabolicDistance { 0.0f }; + BoxFace face; glm::vec3 intersection; + glm::vec3 surfaceNormal; QVariantMap extraInfo; }; diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index f9fed5ae8b..2de6316d74 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -567,8 +567,7 @@ public: bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, - QVariantMap& extraInfo, bool precisionPicking) const -{ + QVariantMap& extraInfo, bool precisionPicking) const { // TODO -- correctly pick against marching-cube generated meshes if (!precisionPicking) { // just intersect with bounding box @@ -614,6 +613,87 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o return hit; } +bool RenderablePolyVoxEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, + const glm::vec3& acceleration, OctreeElementPointer& element, + float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, + QVariantMap& extraInfo, bool precisionPicking) const { + // TODO -- correctly pick against marching-cube generated meshes + if (!precisionPicking) { + // just intersect with bounding box + return true; + } + + glm::mat4 wtvMatrix = worldToVoxelMatrix(); + glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f); + glm::vec4 velocityInVoxel = wtvMatrix * glm::vec4(velocity, 0.0f); + glm::vec4 accelerationInVoxel = wtvMatrix * glm::vec4(acceleration, 0.0f); + + // find the first intersection with the voxel bounding box (slightly enlarged so we can catch voxels that touch the sides) + bool success; + glm::vec3 center = getCenterPosition(success); + glm::vec3 dimensions = getScaledDimensions(); + const float FIRST_BOX_HALF_SCALE = 0.51f; + AABox voxelBox1(wtvMatrix * vec4(center - FIRST_BOX_HALF_SCALE * dimensions, 1.0f), + wtvMatrix * vec4(2.0f * FIRST_BOX_HALF_SCALE * dimensions, 0.0f)); + bool hit1; + float parabolicDistance1; + // If we're starting inside the box, our first point is originInVoxel + if (voxelBox1.contains(originInVoxel)) { + parabolicDistance1 = 0.0f; + hit1 = true; + } else { + BoxFace face1; + glm::vec3 surfaceNormal1; + hit1 = voxelBox1.findParabolaIntersection(glm::vec3(originInVoxel), glm::vec3(velocityInVoxel), glm::vec3(accelerationInVoxel), + parabolicDistance1, face1, surfaceNormal1); + } + + if (hit1) { + // find the second intersection, which should be with the inside of the box (use a slightly large box again) + const float SECOND_BOX_HALF_SCALE = 0.52f; + AABox voxelBox2(wtvMatrix * vec4(center - SECOND_BOX_HALF_SCALE * dimensions, 1.0f), + wtvMatrix * vec4(2.0f * SECOND_BOX_HALF_SCALE * dimensions, 0.0f)); + glm::vec4 originInVoxel2 = originInVoxel + velocityInVoxel * parabolicDistance1 + 0.5f * accelerationInVoxel * parabolicDistance1 * parabolicDistance1; + glm::vec4 velocityInVoxel2 = velocityInVoxel + accelerationInVoxel * parabolicDistance1; + glm::vec4 accelerationInVoxel2 = accelerationInVoxel; + float parabolicDistance2; + BoxFace face2; + glm::vec3 surfaceNormal2; + // this should always be true + if (voxelBox2.findParabolaIntersection(glm::vec3(originInVoxel2), glm::vec3(velocityInVoxel2), glm::vec3(accelerationInVoxel2), + parabolicDistance2, face2, surfaceNormal2)) { + const int MAX_SECTIONS = 15; + PolyVox::RaycastResult raycastResult = PolyVox::RaycastResults::Completed; + glm::vec4 result = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f); + glm::vec4 segmentStartVoxel = originInVoxel2; + for (int i = 0; i < MAX_SECTIONS; i++) { + float t = parabolicDistance2 * ((float)(i + 1)) / ((float)MAX_SECTIONS); + glm::vec4 segmentEndVoxel = originInVoxel2 + velocityInVoxel2 * t + 0.5f * accelerationInVoxel2 * t * t; + raycastResult = doRayCast(segmentStartVoxel, segmentEndVoxel, result); + if (raycastResult != PolyVox::RaycastResults::Completed) { + // We hit something! + break; + } + segmentStartVoxel = segmentEndVoxel; + } + + if (raycastResult == PolyVox::RaycastResults::Completed) { + // the parabola completed its path -- nothing was hit. + return false; + } + + glm::vec3 result3 = glm::vec3(result); + + AABox voxelBox; + voxelBox += result3 - Vectors::HALF; + voxelBox += result3 + Vectors::HALF; + + return voxelBox.findParabolaIntersection(glm::vec3(originInVoxel), glm::vec3(velocityInVoxel), glm::vec3(accelerationInVoxel), + parabolicDistance, face, surfaceNormal); + } + } + return false; +} PolyVox::RaycastResult RenderablePolyVoxEntityItem::doRayCast(glm::vec4 originInVoxel, glm::vec4 farInVoxel, diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index d7b9868fbc..7afb9b41b4 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -53,9 +53,13 @@ public: virtual bool supportsDetailedIntersection() const override { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - OctreeElementPointer& element, float& distance, - BoxFace& face, glm::vec3& surfaceNormal, - QVariantMap& extraInfo, bool precisionPicking) const override; + OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, + QVariantMap& extraInfo, bool precisionPicking) const override; + virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const vec3& accleration, + OctreeElementPointer& element, float& parabolicDistance, + BoxFace& face, glm::vec3& surfaceNormal, + QVariantMap& extraInfo, bool precisionPicking) const override; virtual void setVoxelData(const QByteArray& voxelData) override; virtual void setVoxelVolumeSize(const glm::vec3& voxelVolumeSize) override; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index d2e40eb527..8fd87e068a 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -1050,65 +1050,16 @@ bool EntityScriptingInterface::getDrawZoneBoundaries() const { } QScriptValue RayToEntityIntersectionResultToScriptValue(QScriptEngine* engine, const RayToEntityIntersectionResult& value) { - PROFILE_RANGE(script_entities, __FUNCTION__); - QScriptValue obj = engine->newObject(); obj.setProperty("intersects", value.intersects); obj.setProperty("accurate", value.accurate); QScriptValue entityItemValue = EntityItemIDtoScriptValue(engine, value.entityID); obj.setProperty("entityID", entityItemValue); - obj.setProperty("distance", value.distance); - - QString faceName = ""; - // handle BoxFace - /**jsdoc - *

A BoxFace specifies the face of an axis-aligned (AA) box. - * - * - * - * - * - * - * - * - * - * - * - * - * - *
ValueDescription
"MIN_X_FACE"The minimum x-axis face.
"MAX_X_FACE"The maximum x-axis face.
"MIN_Y_FACE"The minimum y-axis face.
"MAX_Y_FACE"The maximum y-axis face.
"MIN_Z_FACE"The minimum z-axis face.
"MAX_Z_FACE"The maximum z-axis face.
"UNKNOWN_FACE"Unknown value.
- * @typedef {string} BoxFace - */ - // FIXME: Move enum to string function to BoxBase.cpp. - switch (value.face) { - case MIN_X_FACE: - faceName = "MIN_X_FACE"; - break; - case MAX_X_FACE: - faceName = "MAX_X_FACE"; - break; - case MIN_Y_FACE: - faceName = "MIN_Y_FACE"; - break; - case MAX_Y_FACE: - faceName = "MAX_Y_FACE"; - break; - case MIN_Z_FACE: - faceName = "MIN_Z_FACE"; - break; - case MAX_Z_FACE: - faceName = "MAX_Z_FACE"; - break; - case UNKNOWN_FACE: - faceName = "UNKNOWN_FACE"; - break; - } - obj.setProperty("face", faceName); + obj.setProperty("face", boxFaceToString(value.face)); QScriptValue intersection = vec3toScriptValue(engine, value.intersection); obj.setProperty("intersection", intersection); - QScriptValue surfaceNormal = vec3toScriptValue(engine, value.surfaceNormal); obj.setProperty("surfaceNormal", surfaceNormal); obj.setProperty("extraInfo", engine->toScriptValue(value.extraInfo)); @@ -1116,29 +1067,13 @@ QScriptValue RayToEntityIntersectionResultToScriptValue(QScriptEngine* engine, c } void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, RayToEntityIntersectionResult& value) { - PROFILE_RANGE(script_entities, __FUNCTION__); - value.intersects = object.property("intersects").toVariant().toBool(); value.accurate = object.property("accurate").toVariant().toBool(); QScriptValue entityIDValue = object.property("entityID"); - // EntityItemIDfromScriptValue(entityIDValue, value.entityID); quuidFromScriptValue(entityIDValue, value.entityID); value.distance = object.property("distance").toVariant().toFloat(); + value.face = boxFaceFromString(object.property("face").toVariant().toString()); - QString faceName = object.property("face").toVariant().toString(); - if (faceName == "MIN_X_FACE") { - value.face = MIN_X_FACE; - } else if (faceName == "MAX_X_FACE") { - value.face = MAX_X_FACE; - } else if (faceName == "MIN_Y_FACE") { - value.face = MIN_Y_FACE; - } else if (faceName == "MAX_Y_FACE") { - value.face = MAX_Y_FACE; - } else if (faceName == "MIN_Z_FACE") { - value.face = MIN_Z_FACE; - } else { - value.face = MAX_Z_FACE; - }; QScriptValue intersection = object.property("intersection"); if (intersection.isValid()) { vec3FromScriptValue(intersection, value.intersection); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index d7d86fc489..a166d513d3 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -80,9 +80,7 @@ public: glm::vec3 surfaceNormal; QVariantMap extraInfo; }; - Q_DECLARE_METATYPE(RayToEntityIntersectionResult) - QScriptValue RayToEntityIntersectionResultToScriptValue(QScriptEngine* engine, const RayToEntityIntersectionResult& results); void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, RayToEntityIntersectionResult& results); diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index 0a48ed584e..52ec8e8c2d 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -97,7 +97,7 @@ class PolyLineEntityItem : public EntityItem { virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, - QVariantMap& extraInfo, bool precisionPicking) const { return false; } + QVariantMap& extraInfo, bool precisionPicking) const override { return false; } // disable these external interfaces as PolyLineEntities caculate their own dimensions based on the points they contain virtual void setRegistrationPoint(const glm::vec3& value) override {}; // FIXME: this is suspicious! diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index e3f8c48dd1..d2ca4db124 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -50,7 +50,7 @@ class PolyVoxEntityItem : public EntityItem { virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, - QVariantMap& extraInfo, bool precisionPicking) const { return false; } + QVariantMap& extraInfo, bool precisionPicking) const override { return false; } virtual void debugDump() const override; diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 71312f3bb3..ba0d714f7a 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -516,9 +516,9 @@ bool Model::findParabolaIntersectionAgainstSubMeshes(const glm::vec3& origin, co face = triangleSetFace; bestModelTriangle = triangleSetTriangle; bestWorldTriangle = triangleSetTriangle * meshToWorldMatrix; - glm::vec3 worldIntersectionPoint = meshFrameOrigin + meshFrameVelocity * triangleSetDistance + + glm::vec3 meshIntersectionPoint = meshFrameOrigin + meshFrameVelocity * triangleSetDistance + 0.5f * meshFrameAcceleration * triangleSetDistance * triangleSetDistance; - glm::vec3 meshIntersectionPoint = origin + velocity * triangleSetDistance + + glm::vec3 worldIntersectionPoint = origin + velocity * triangleSetDistance + 0.5f * acceleration * triangleSetDistance * triangleSetDistance; extraInfo["worldIntersectionPoint"] = vec3toVariant(worldIntersectionPoint); extraInfo["meshIntersectionPoint"] = vec3toVariant(meshIntersectionPoint); diff --git a/libraries/render-utils/src/parabola.slv b/libraries/render-utils/src/parabola.slv index a8c892ab00..c40fc89302 100644 --- a/libraries/render-utils/src/parabola.slv +++ b/libraries/render-utils/src/parabola.slv @@ -18,6 +18,8 @@ layout(std140) uniform parabolaData { vec3 acceleration; float width; vec4 color; + int numSections; + ivec3 spare; }; out vec4 _color; @@ -25,8 +27,7 @@ out vec4 _color; void main(void) { _color = color; - const int NUM_SECTIONS = 25; // must match value in ParabolaPointer.cpp - float t = parabolicDistance * (floor(gl_VertexID / 2) / float(NUM_SECTIONS)); + float t = parabolicDistance * (floor(gl_VertexID / 2) / float(numSections)); vec4 pos = vec4(velocity * t + 0.5 * acceleration * t * t, 1); const float EPSILON = 0.00001; diff --git a/libraries/shared/src/BoxBase.cpp b/libraries/shared/src/BoxBase.cpp new file mode 100644 index 0000000000..0b790dc2b0 --- /dev/null +++ b/libraries/shared/src/BoxBase.cpp @@ -0,0 +1,46 @@ +// +// Created by Sam Gondelman on 7/20/18 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "BoxBase.h" + +QString boxFaceToString(BoxFace face) { + switch (face) { + case MIN_X_FACE: + return "MIN_X_FACE"; + case MAX_X_FACE: + return "MAX_X_FACE"; + case MIN_Y_FACE: + return "MIN_Y_FACE"; + case MAX_Y_FACE: + return "MAX_Y_FACE"; + case MIN_Z_FACE: + return "MIN_Z_FACE"; + case MAX_Z_FACE: + return "MAX_Z_FACE"; + default: + return "UNKNOWN_FACE"; + } +} + +BoxFace boxFaceFromString(const QString& face) { + if (face == "MIN_X_FACE") { + return MIN_X_FACE; + } else if (face == "MAX_X_FACE") { + return MAX_X_FACE; + } else if (face == "MIN_Y_FACE") { + return MIN_Y_FACE; + } else if (face == "MAX_Y_FACE") { + return MAX_Y_FACE; + } else if (face == "MIN_Z_FACE") { + return MIN_Z_FACE; + } else if (face == "MAX_Z_FACE") { + return MAX_Z_FACE; + } else { + return UNKNOWN_FACE; + } +} \ No newline at end of file diff --git a/libraries/shared/src/BoxBase.h b/libraries/shared/src/BoxBase.h index 7f1dd4d34c..9bc2115d9e 100644 --- a/libraries/shared/src/BoxBase.h +++ b/libraries/shared/src/BoxBase.h @@ -16,7 +16,26 @@ #define hifi_BoxBase_h #include +#include +/**jsdoc +*

A BoxFace specifies the face of an axis-aligned (AA) box. +* +* +* +* +* +* +* +* +* +* +* +* +* +*
ValueDescription
"MIN_X_FACE"The minimum x-axis face.
"MAX_X_FACE"The maximum x-axis face.
"MIN_Y_FACE"The minimum y-axis face.
"MAX_Y_FACE"The maximum y-axis face.
"MIN_Z_FACE"The minimum z-axis face.
"MAX_Z_FACE"The maximum z-axis face.
"UNKNOWN_FACE"Unknown value.
+* @typedef {string} BoxFace +*/ enum BoxFace { MIN_X_FACE, MAX_X_FACE, @@ -27,6 +46,9 @@ enum BoxFace { UNKNOWN_FACE }; +QString boxFaceToString(BoxFace face); +BoxFace boxFaceFromString(const QString& face); + enum BoxVertex { BOTTOM_LEFT_NEAR = 0, BOTTOM_RIGHT_NEAR = 1, diff --git a/libraries/shared/src/GeometryUtil.cpp b/libraries/shared/src/GeometryUtil.cpp index f34473a5d8..963294a360 100644 --- a/libraries/shared/src/GeometryUtil.cpp +++ b/libraries/shared/src/GeometryUtil.cpp @@ -952,7 +952,7 @@ void checkPossibleParabolicIntersectionWithTriangle(float t, float& minDistance, bool findParabolaTriangleIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration, const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, float& parabolicDistance, bool allowBackface) { - glm::vec3 normal = glm::cross(v2 - v1, v0 - v1); + glm::vec3 normal = glm::normalize(glm::cross(v2 - v1, v0 - v1)); // We transform the parabola and triangle so that the triangle is in the plane z = 0, with v0 at the origin glm::quat inverseRot; @@ -1092,7 +1092,7 @@ inline float parabolaVelocityAtT(float velocity, float acceleration, float t) { bool findParabolaAABoxIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration, const glm::vec3& corner, const glm::vec3& scale, float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal) { float minDistance = FLT_MAX; - BoxFace minFace; + BoxFace minFace = UNKNOWN_FACE; glm::vec3 minNormal; glm::vec2 possibleDistances; float a, b, c; @@ -1720,8 +1720,8 @@ unsigned int solveP3(float* x, float a, float b, float c) { a /= 3.0f; q = -2.0f * sqrtf(q); x[0] = q * cosf(t / 3.0f) - a; - x[1] = q * cosf((t + 2.0f * M_PI) / 3.0f) - a; - x[2] = q * cosf((t - 2.0f * M_PI) / 3.0f) - a; + x[1] = q * cosf((t + 2.0f * (float)M_PI) / 3.0f) - a; + x[2] = q * cosf((t - 2.0f * (float)M_PI) / 3.0f) - a; return 3; } else { A = -powf(fabsf(r) + sqrtf(r2 - q3), 1.0f / 3.0f); @@ -1755,27 +1755,27 @@ bool solve_quartic(float a, float b, float c, float d, glm::vec4& roots) { y = px3[0]; if (iZeroes != 1) { - if (fabs(px3[1]) > fabs(y)) { + if (fabsf(px3[1]) > fabsf(y)) { y = px3[1]; } - if (fabs(px3[2]) > fabs(y)) { + if (fabsf(px3[2]) > fabsf(y)) { y = px3[2]; } } D = y * y - 4.0f * d; - if (fabs(D) < EPSILON) { + if (fabsf(D) < EPSILON) { q1 = q2 = 0.5f * y; D = a * a - 4.0f * (b - y); - if (fabs(D) < EPSILON) { + if (fabsf(D) < EPSILON) { p1 = p2 = 0.5f * a; } else { - sqD = sqrt(D); + sqD = sqrtf(D); p1 = 0.5f * (a + sqD); p2 = 0.5f * (a - sqD); } } else { - sqD = sqrt(D); + sqD = sqrtf(D); q1 = 0.5f * (y + sqD); q2 = 0.5f * (y - sqD); p1 = (a * q1 - c) / (q1 - q2); @@ -1786,10 +1786,10 @@ bool solve_quartic(float a, float b, float c, float d, glm::vec4& roots) { D = p1 * p1 - 4.0f * q1; if (D < 0.0f) { x1.real(-0.5f * p1); - x1.imag(0.5f * sqrt(-D)); + x1.imag(0.5f * sqrtf(-D)); x2 = std::conj(x1); } else { - sqD = sqrt(D); + sqD = sqrtf(D); x1.real(0.5f * (-p1 + sqD)); x2.real(0.5f * (-p1 - sqD)); } @@ -1797,10 +1797,10 @@ bool solve_quartic(float a, float b, float c, float d, glm::vec4& roots) { D = p2 * p2 - 4.0f * q2; if (D < 0.0f) { x3.real(-0.5f * p2); - x3.imag(0.5f * sqrt(-D)); + x3.imag(0.5f * sqrtf(-D)); x4 = std::conj(x3); } else { - sqD = sqrt(D); + sqD = sqrtf(D); x3.real(0.5f * (-p2 + sqD)); x4.real(0.5f * (-p2 - sqD)); } diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index 55162ae3e9..e926a70bee 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -100,7 +100,7 @@ Script.include("/~/system/libraries/controllers.js"); {name: "teleport", path: teleportPath, end: teleportEnd}, {name: "seat", path: seatPath, end: seatEnd}]; - var DEFAULT_DISTANCE = 10; + var DEFAULT_DISTANCE = 4.0; var teleportDefaultRenderStates = [{name: "cancel", distance: DEFAULT_DISTANCE, path: cancelPath}]; var coolInTimeout = null; @@ -151,7 +151,8 @@ Script.include("/~/system/libraries/controllers.js"); accelerationAxis: accelerationAxis, rotateAccelerationWithAvatar: true, renderStates: teleportRenderStates, - defaultRenderStates: teleportDefaultRenderStates + defaultRenderStates: teleportDefaultRenderStates, + maxDistance: 4.0 }); this.teleportParabolaHandInvisible = Pointers.createPointer(PickType.Parabola, { joint: (_this.hand === RIGHT_HAND) ? "RightHand" : "LeftHand", @@ -163,7 +164,8 @@ Script.include("/~/system/libraries/controllers.js"); speed: speed, accelerationAxis: accelerationAxis, rotateAccelerationWithAvatar: true, - renderStates: teleportRenderStates + renderStates: teleportRenderStates, + maxDistance: 4.0 }); this.teleportParabolaHeadVisible = Pointers.createPointer(PickType.Parabola, { joint: "Avatar", @@ -176,7 +178,8 @@ Script.include("/~/system/libraries/controllers.js"); accelerationAxis: accelerationAxis, rotateAccelerationWithAvatar: true, renderStates: teleportRenderStates, - defaultRenderStates: teleportDefaultRenderStates + defaultRenderStates: teleportDefaultRenderStates, + maxDistance: 4.0 }); this.teleportParabolaHeadInvisible = Pointers.createPointer(PickType.Parabola, { joint: "Avatar", @@ -188,7 +191,8 @@ Script.include("/~/system/libraries/controllers.js"); speed: speed, accelerationAxis: accelerationAxis, rotateAccelerationWithAvatar: true, - renderStates: teleportRenderStates + renderStates: teleportRenderStates, + maxDistance: 4.0 }); this.cleanup = function() { @@ -430,7 +434,7 @@ Script.include("/~/system/libraries/controllers.js"); } var surfaceNormal = result.surfaceNormal; - var angle = Math.abs(Math.acos(Vec3.dot(surfaceNormal, Quat.getUp(MyAvatar.orientation)))) * (180.0 / Math.PI); + var angle = Math.acos(Vec3.dot(surfaceNormal, Quat.getUp(MyAvatar.orientation))) * (180.0 / Math.PI); if (angle > MAX_ANGLE_FROM_UP_TO_TELEPORT || Vec3.distance(MyAvatar.position, result.intersection) <= TELEPORT_CANCEL_RANGE * MyAvatar.sensorToWorldScale) {