diff --git a/examples/example/scripts/rayPickExample.js b/examples/example/scripts/rayPickExample.js index b0b7c24fef..d85138211e 100644 --- a/examples/example/scripts/rayPickExample.js +++ b/examples/example/scripts/rayPickExample.js @@ -11,6 +11,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + +var normalDisplay = Entities.addEntity({ + type: "Line", + name: "normalDisplay", + visible: false, + color: { red: 255, green: 0, blue: 0 }, + dimensions: { x: 100, y: 100, z: 100 } +}); + +var wasVisible = false; + function mouseMoveEvent(event) { print("mouseMoveEvent event.x,y=" + event.x + ", " + event.y); var pickRay = Camera.computePickRay(event.x, event.y); @@ -18,26 +29,45 @@ function mouseMoveEvent(event) { print("computePickRay origin=" + pickRay.origin.x + ", " + pickRay.origin.y + ", " + pickRay.origin.z); print("computePickRay direction=" + pickRay.direction.x + ", " + pickRay.direction.y + ", " + pickRay.direction.z); var pickRay = Camera.computePickRay(event.x, event.y); - intersection = Entities.findRayIntersection(pickRay); + intersection = Entities.findRayIntersection(pickRay, true); // to get precise picking if (!intersection.accurate) { print(">>> NOTE: intersection not accurate. will try calling Entities.findRayIntersectionBlocking()"); - intersection = Entities.findRayIntersectionBlocking(pickRay); + intersection = Entities.findRayIntersectionBlocking(pickRay, true); // to get precise picking print(">>> AFTER BLOCKING CALL intersection.accurate=" + intersection.accurate); } if (intersection.intersects) { - print("intersection entityID.id=" + intersection.entityID.id); + print("intersection entityID=" + intersection.entityID); print("intersection properties.modelURL=" + intersection.properties.modelURL); print("intersection face=" + intersection.face); print("intersection distance=" + intersection.distance); - print("intersection intersection.x/y/z=" + intersection.intersection.x + ", " + print("intersection intersection.x/y/z=" + intersection.intersection.x + ", " + intersection.intersection.y + ", " + intersection.intersection.z); + print("intersection surfaceNormal.x/y/z=" + intersection.surfaceNormal.x + ", " + + intersection.surfaceNormal.y + ", " + intersection.surfaceNormal.z); + + + // Note: line entity takes points in "entity relative frame" + var lineStart = { x: 0, y: 0, z: 0 }; + var lineEnd = intersection.surfaceNormal; + + Entities.editEntity(normalDisplay, { + visible: true, + position: intersection.intersection, + linePoints: [lineStart, lineEnd], + }); + wasVisible = true; + } else { + if (wasVisible) { + Entities.editEntity(normalDisplay, { visible: false }); + wasVisible = false; + } } } Controller.mouseMoveEvent.connect(mouseMoveEvent); -function scriptEnding() { -} -Script.scriptEnding.connect(scriptEnding); +Script.scriptEnding.connect(function() { + Entities.deleteEntity(normalDisplay); +}); diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index e1252836d7..4d7ca90925 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -171,6 +171,6 @@ QScriptValue Base3DOverlay::getProperty(const QString& property) { } bool Base3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face) { + float& distance, BoxFace& face, glm::vec3& surfaceNormal) { return false; } diff --git a/interface/src/ui/overlays/Base3DOverlay.h b/interface/src/ui/overlays/Base3DOverlay.h index 3cb4d27021..441da4f2da 100644 --- a/interface/src/ui/overlays/Base3DOverlay.h +++ b/interface/src/ui/overlays/Base3DOverlay.h @@ -57,11 +57,12 @@ public: virtual void setProperties(const QScriptValue& properties); virtual QScriptValue getProperty(const QString& property); - virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face); + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, + BoxFace& face, glm::vec3& surfaceNormal); virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face, QString& extraInfo) { - return findRayIntersection(origin, direction, distance, face); + float& distance, BoxFace& face, glm::vec3& surfaceNormal, QString& extraInfo) { + return findRayIntersection(origin, direction, distance, face, surfaceNormal); } protected: diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp index 44d8b6861a..0b7da72d58 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.cpp +++ b/interface/src/ui/overlays/Circle3DOverlay.cpp @@ -391,10 +391,10 @@ QScriptValue Circle3DOverlay::getProperty(const QString& property) { } -bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin, - const glm::vec3& direction, float& distance, BoxFace& face) { +bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, + BoxFace& face, glm::vec3& surfaceNormal) { - bool intersects = Planar3DOverlay::findRayIntersection(origin, direction, distance, face); + bool intersects = Planar3DOverlay::findRayIntersection(origin, direction, distance, face, surfaceNormal); if (intersects) { glm::vec3 hitPosition = origin + (distance * direction); diff --git a/interface/src/ui/overlays/Circle3DOverlay.h b/interface/src/ui/overlays/Circle3DOverlay.h index 5879fe1701..d03dc2ee2a 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.h +++ b/interface/src/ui/overlays/Circle3DOverlay.h @@ -52,7 +52,8 @@ public: void setMajorTickMarksColor(const xColor& value) { _majorTickMarksColor = value; } void setMinorTickMarksColor(const xColor& value) { _minorTickMarksColor = value; } - virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face); + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, + BoxFace& face, glm::vec3& surfaceNormal); virtual Circle3DOverlay* createClone() const; diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp index a609f485a6..2f8450131f 100644 --- a/interface/src/ui/overlays/Image3DOverlay.cpp +++ b/interface/src/ui/overlays/Image3DOverlay.cpp @@ -166,7 +166,7 @@ void Image3DOverlay::setURL(const QString& url) { } bool Image3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face) { + float& distance, BoxFace& face, glm::vec3& surfaceNormal) { if (_texture && _texture->isLoaded()) { // Make sure position and rotation is updated. applyTransformTo(_transform, true); @@ -178,6 +178,7 @@ bool Image3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec float maxSize = glm::max(width, height); glm::vec2 dimensions = _dimensions * glm::vec2(width / maxSize, height / maxSize); + // FIXME - face and surfaceNormal not being set return findRayRectangleIntersection(origin, direction, getRotation(), getPosition(), dimensions, distance); } diff --git a/interface/src/ui/overlays/Image3DOverlay.h b/interface/src/ui/overlays/Image3DOverlay.h index 0c71fef173..f848023fbe 100644 --- a/interface/src/ui/overlays/Image3DOverlay.h +++ b/interface/src/ui/overlays/Image3DOverlay.h @@ -38,7 +38,8 @@ public: virtual void setProperties(const QScriptValue& properties); virtual QScriptValue getProperty(const QString& property); - virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face); + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, + BoxFace& face, glm::vec3& surfaceNormal); virtual Image3DOverlay* createClone() const; diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 49321e7d6d..b6422d86e0 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -159,16 +159,16 @@ QScriptValue ModelOverlay::getProperty(const QString& property) { } bool ModelOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face) { + float& distance, BoxFace& face, glm::vec3& surfaceNormal) { QString subMeshNameTemp; - return _model.findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, subMeshNameTemp); + return _model.findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, subMeshNameTemp); } bool ModelOverlay::findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face, QString& extraInfo) { + float& distance, BoxFace& face, glm::vec3& surfaceNormal, QString& extraInfo) { - return _model.findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, extraInfo); + return _model.findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, surfaceNormal, extraInfo); } ModelOverlay* ModelOverlay::createClone() const { diff --git a/interface/src/ui/overlays/ModelOverlay.h b/interface/src/ui/overlays/ModelOverlay.h index 97ecfb642c..5d09ea75a0 100644 --- a/interface/src/ui/overlays/ModelOverlay.h +++ b/interface/src/ui/overlays/ModelOverlay.h @@ -29,9 +29,10 @@ public: virtual void render(RenderArgs* args); virtual void setProperties(const QScriptValue& properties); virtual QScriptValue getProperty(const QString& property); - virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face); + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, + BoxFace& face, glm::vec3& surfaceNormal); virtual bool findRayIntersectionExtraInfo(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face, QString& extraInfo); + float& distance, BoxFace& face, glm::vec3& surfaceNormal, QString& extraInfo); virtual ModelOverlay* createClone() const; diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 563d90f6b9..bc786f3f4c 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -346,6 +346,7 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) { glm::vec3 origin(pointCopy.x, pointCopy.y, LARGE_NEGATIVE_FLOAT); glm::vec3 direction(0, 0, 1); BoxFace thisFace; + glm::vec3 thisSurfaceNormal; float distance; while (i.hasPrevious()) { @@ -354,7 +355,7 @@ unsigned int Overlays::getOverlayAtPoint(const glm::vec2& point) { if (i.value()->is3D()) { auto thisOverlay = std::dynamic_pointer_cast(i.value()); if (thisOverlay && !thisOverlay->getIgnoreRayIntersection()) { - if (thisOverlay->findRayIntersection(origin, direction, distance, thisFace)) { + if (thisOverlay->findRayIntersection(origin, direction, distance, thisFace, thisSurfaceNormal)) { return thisID; } } @@ -423,8 +424,10 @@ RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray) if (thisOverlay && thisOverlay->getVisible() && !thisOverlay->getIgnoreRayIntersection() && thisOverlay->isLoaded()) { float thisDistance; BoxFace thisFace; + glm::vec3 thisSurfaceNormal; QString thisExtraInfo; - if (thisOverlay->findRayIntersectionExtraInfo(ray.origin, ray.direction, thisDistance, thisFace, thisExtraInfo)) { + if (thisOverlay->findRayIntersectionExtraInfo(ray.origin, ray.direction, thisDistance, + thisFace, thisSurfaceNormal, thisExtraInfo)) { bool isDrawInFront = thisOverlay->getDrawInFront(); if (thisDistance < bestDistance && (!bestIsFront || isDrawInFront)) { bestIsFront = isDrawInFront; @@ -432,6 +435,7 @@ RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray) result.intersects = true; result.distance = thisDistance; result.face = thisFace; + result.surfaceNormal = thisSurfaceNormal; result.overlayID = thisID; result.intersection = ray.origin + (ray.direction * thisDistance); result.extraInfo = thisExtraInfo; diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index bb4d94cdab..5bd8098150 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -46,6 +46,7 @@ public: int overlayID; float distance; BoxFace face; + glm::vec3 surfaceNormal; glm::vec3 intersection; QString extraInfo; }; diff --git a/interface/src/ui/overlays/Planar3DOverlay.cpp b/interface/src/ui/overlays/Planar3DOverlay.cpp index 354991b596..b04316b3ee 100644 --- a/interface/src/ui/overlays/Planar3DOverlay.cpp +++ b/interface/src/ui/overlays/Planar3DOverlay.cpp @@ -92,6 +92,7 @@ QScriptValue Planar3DOverlay::getProperty(const QString& property) { } bool Planar3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face) { + float& distance, BoxFace& face, glm::vec3& surfaceNormal) { + // FIXME - face and surfaceNormal not being returned return findRayRectangleIntersection(origin, direction, getRotation(), getPosition(), getDimensions(), distance); } diff --git a/interface/src/ui/overlays/Planar3DOverlay.h b/interface/src/ui/overlays/Planar3DOverlay.h index 08a7121e91..63de15a8f8 100644 --- a/interface/src/ui/overlays/Planar3DOverlay.h +++ b/interface/src/ui/overlays/Planar3DOverlay.h @@ -29,7 +29,8 @@ public: virtual void setProperties(const QScriptValue& properties); virtual QScriptValue getProperty(const QString& property); - virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face); + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, + BoxFace& face, glm::vec3& surfaceNormal); protected: glm::vec2 _dimensions; diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp index d4df8553c8..563f454057 100644 --- a/interface/src/ui/overlays/Text3DOverlay.cpp +++ b/interface/src/ui/overlays/Text3DOverlay.cpp @@ -211,7 +211,8 @@ QSizeF Text3DOverlay::textSize(const QString& text) const { return QSizeF(extents.x, extents.y) * pointToWorldScale; } -bool Text3DOverlay::findRayIntersection(const glm::vec3 &origin, const glm::vec3 &direction, float &distance, BoxFace &face) { +bool Text3DOverlay::findRayIntersection(const glm::vec3 &origin, const glm::vec3 &direction, float &distance, + BoxFace &face, glm::vec3& surfaceNormal) { applyTransformTo(_transform, true); - return Billboard3DOverlay::findRayIntersection(origin, direction, distance, face); + return Billboard3DOverlay::findRayIntersection(origin, direction, distance, face, surfaceNormal); } diff --git a/interface/src/ui/overlays/Text3DOverlay.h b/interface/src/ui/overlays/Text3DOverlay.h index e5e0ff7b96..5bd87e766a 100644 --- a/interface/src/ui/overlays/Text3DOverlay.h +++ b/interface/src/ui/overlays/Text3DOverlay.h @@ -54,7 +54,8 @@ public: QSizeF textSize(const QString& test) const; // Meters - virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face); + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, + BoxFace& face, glm::vec3& surfaceNormal); virtual Text3DOverlay* createClone() const; diff --git a/interface/src/ui/overlays/Volume3DOverlay.cpp b/interface/src/ui/overlays/Volume3DOverlay.cpp index a7c9835f5d..687f1f6286 100644 --- a/interface/src/ui/overlays/Volume3DOverlay.cpp +++ b/interface/src/ui/overlays/Volume3DOverlay.cpp @@ -93,7 +93,7 @@ QScriptValue Volume3DOverlay::getProperty(const QString& property) { } bool Volume3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - float& distance, BoxFace& face) { + float& distance, BoxFace& face, glm::vec3& surfaceNormal) { // extents is the entity relative, scaled, centered extents of the entity glm::mat4 worldToEntityMatrix; _transform.getInverseMatrix(worldToEntityMatrix); @@ -103,5 +103,5 @@ bool Volume3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::ve // we can use the AABox's ray intersection by mapping our origin and direction into the overlays frame // and testing intersection there. - return _localBoundingBox.findRayIntersection(overlayFrameOrigin, overlayFrameDirection, distance, face); + return _localBoundingBox.findRayIntersection(overlayFrameOrigin, overlayFrameDirection, distance, face, surfaceNormal); } diff --git a/interface/src/ui/overlays/Volume3DOverlay.h b/interface/src/ui/overlays/Volume3DOverlay.h index ada485a663..1608e99b35 100644 --- a/interface/src/ui/overlays/Volume3DOverlay.h +++ b/interface/src/ui/overlays/Volume3DOverlay.h @@ -29,7 +29,8 @@ public: virtual void setProperties(const QScriptValue& properties); virtual QScriptValue getProperty(const QString& property); - virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face); + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, + BoxFace& face, glm::vec3& surfaceNormal); protected: // Centered local bounding box diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 73e83fa097..0f2361410b 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -151,8 +151,10 @@ void Web3DOverlay::setURL(const QString& url) { } -bool Web3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) { - //// Make sure position and rotation is updated. +bool Web3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal) { + // FIXME - face and surfaceNormal not being returned + + // Make sure position and rotation is updated. applyTransformTo(_transform, true); vec2 size = _resolution / _dpi * INCHES_TO_METERS * vec2(getDimensions()); // Produce the dimensions of the overlay based on the image's aspect ratio and the overlay's scale. diff --git a/interface/src/ui/overlays/Web3DOverlay.h b/interface/src/ui/overlays/Web3DOverlay.h index 59c8fae0fe..bab2a1b55a 100644 --- a/interface/src/ui/overlays/Web3DOverlay.h +++ b/interface/src/ui/overlays/Web3DOverlay.h @@ -34,7 +34,8 @@ public: virtual void setProperties(const QScriptValue& properties); virtual QScriptValue getProperty(const QString& property); - virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face); + virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, + BoxFace& face, glm::vec3& surfaceNormal); virtual Web3DOverlay* createClone() const; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index c57d1e5d23..db86c91c02 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -470,9 +470,10 @@ RayToEntityIntersectionResult EntityTreeRenderer::findRayIntersectionWorker(cons OctreeElementPointer element; EntityItemPointer intersectedEntity = NULL; - result.intersects = entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face, - (void**)&intersectedEntity, lockType, &result.accurate, - precisionPicking); + result.intersects = entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, + result.face, result.surfaceNormal, + (void**)&intersectedEntity, lockType, &result.accurate, + precisionPicking); if (result.intersects && intersectedEntity) { result.entityID = intersectedEntity->getEntityItemID(); result.properties = intersectedEntity->getProperties(); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index d100597969..76220952ef 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -87,10 +87,10 @@ public: QList& getEntitiesLastInScene() { return _entityIDsLastInScene; } signals: - void mousePressOnEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId); - void mousePressOffEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId); - void mouseMoveOnEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId); - void mouseReleaseOnEntity(const RayToEntityIntersectionResult& entityItemID, const QMouseEvent* event, unsigned int deviceId); + void mousePressOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId); + void mousePressOffEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId); + void mouseMoveOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId); + void mouseReleaseOnEntity(const RayToEntityIntersectionResult& intersection, const QMouseEvent* event, unsigned int deviceId); void clickDownOnEntity(const EntityItemID& entityItemID, const MouseEvent& event); void holdingClickOnEntity(const EntityItemID& entityItemID, const MouseEvent& event); diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp index 19b1ec9c8d..b0cc0462c6 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp @@ -54,8 +54,9 @@ void RenderableLightEntityItem::render(RenderArgs* args) { }; bool RenderableLightEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, - void** intersectedObject, bool precisionPicking) const { + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, + void** intersectedObject, bool precisionPicking) const { // TODO: consider if this is really what we want to do. We've made it so that "lights are pickable" is a global state // this is probably reasonable since there's typically only one tree you'd be picking on at a time. Technically we could diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.h b/libraries/entities-renderer/src/RenderableLightEntityItem.h index bf73493729..ecf24eaec7 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.h +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.h @@ -26,7 +26,8 @@ public: virtual void render(RenderArgs* args); virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const; SIMPLE_RENDERABLE(); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 74317b7eff..c978fab012 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -366,9 +366,9 @@ EntityItemProperties RenderableModelEntityItem::getProperties(EntityPropertyFlag return properties; } -bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, +bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, - void** intersectedObject, bool precisionPicking) const { + glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const { if (!_model) { return true; } @@ -376,7 +376,8 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori // << precisionPicking; QString extraInfo; - return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, extraInfo, precisionPicking); + return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, + face, surfaceNormal, extraInfo, precisionPicking); } void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 5b61046816..509b842c08 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -55,8 +55,9 @@ public: virtual void render(RenderArgs* args); virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, - void** intersectedObject, bool precisionPicking) const; + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, + void** intersectedObject, bool precisionPicking) const; Model* getModel(EntityTreeRenderer* renderer); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 2e8696625c..5d9a247741 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -348,13 +348,10 @@ public: const PolyVox::SimpleVolume* _vol = nullptr; }; -bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& origin, - const glm::vec3& direction, - bool& keepSearching, - OctreeElementPointer& element, - float& distance, BoxFace& face, - void** intersectedObject, - bool precisionPicking) const +bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, + bool& keepSearching, OctreeElementPointer& element, + float& distance, BoxFace& face, glm::vec3& surfaceNormal, + void** intersectedObject, bool precisionPicking) const { // TODO -- correctly pick against marching-cube generated meshes if (!precisionPicking) { @@ -392,7 +389,7 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o float voxelDistance; - bool hit = voxelBox.findRayIntersection(glm::vec3(originInVoxel), glm::vec3(directionInVoxel), voxelDistance, face); + bool hit = voxelBox.findRayIntersection(glm::vec3(originInVoxel), glm::vec3(directionInVoxel), voxelDistance, face, surfaceNormal); glm::vec4 voxelIntersectionPoint = glm::vec4(glm::vec3(originInVoxel) + glm::vec3(directionInVoxel) * voxelDistance, 1.0); glm::vec4 intersectionPoint = vtwMatrix * voxelIntersectionPoint; diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index 14853d929e..e1e042f3d0 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -64,8 +64,9 @@ public: void render(RenderArgs* args); virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, - void** intersectedObject, bool precisionPicking) const; + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, + void** intersectedObject, bool precisionPicking) const; virtual void setVoxelData(QByteArray voxelData); virtual void setVoxelVolumeSize(glm::vec3 voxelVolumeSize); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index deebfc400d..62b436b498 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -206,7 +206,8 @@ public: virtual bool supportsDetailedRayIntersection() const { return false; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const { return true; } // attributes applicable to all entity types diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 91edfe9a42..0dd0129a1e 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -297,7 +297,7 @@ RayToEntityIntersectionResult EntityScriptingInterface::findRayIntersectionWorke OctreeElementPointer element; EntityItemPointer intersectedEntity = NULL; result.intersects = _entityTree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face, - (void**)&intersectedEntity, lockType, &result.accurate, + result.surfaceNormal, (void**)&intersectedEntity, lockType, &result.accurate, precisionPicking); if (result.intersects && intersectedEntity) { result.entityID = intersectedEntity->getEntityItemID(); @@ -393,6 +393,9 @@ QScriptValue RayToEntityIntersectionResultToScriptValue(QScriptEngine* engine, c QScriptValue intersection = vec3toScriptValue(engine, value.intersection); obj.setProperty("intersection", intersection); + + QScriptValue surfaceNormal = vec3toScriptValue(engine, value.surfaceNormal); + obj.setProperty("surfaceNormal", surfaceNormal); return obj; } @@ -426,6 +429,10 @@ void RayToEntityIntersectionResultFromScriptValue(const QScriptValue& object, Ra if (intersection.isValid()) { vec3FromScriptValue(intersection, value.intersection); } + QScriptValue surfaceNormal = object.property("surfaceNormal"); + if (surfaceNormal.isValid()) { + vec3FromScriptValue(surfaceNormal, value.surfaceNormal); + } } bool EntityScriptingInterface::setVoxels(QUuid entityID, diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 877edd16e3..47f5312d88 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -43,6 +43,7 @@ public: float distance; BoxFace face; glm::vec3 intersection; + glm::vec3 surfaceNormal; EntityItemPointer entity; }; diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index ca24199497..9448c5523a 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -492,9 +492,9 @@ bool EntityTreeElement::bestFitBounds(const glm::vec3& minPoint, const glm::vec3 return false; } -bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, - void** intersectedObject, bool precisionPicking, float distanceToElementCube) { +bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, + OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, + void** intersectedObject, bool precisionPicking, float distanceToElementCube) { // only called if we do intersect our bounding cube, but find if we actually intersect with entities... int entityNumber = 0; @@ -503,9 +503,10 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con AABox entityBox = entity->getAABox(); float localDistance; BoxFace localFace; + glm::vec3 localSurfaceNormal; // if the ray doesn't intersect with our cube, we can stop searching! - if (!entityBox.findRayIntersection(origin, direction, localDistance, localFace)) { + if (!entityBox.findRayIntersection(origin, direction, localDistance, localFace, localSurfaceNormal)) { return; } @@ -526,16 +527,18 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con // we can use the AABox's ray intersection by mapping our origin and direction into the entity frame // and testing intersection there. - if (entityFrameBox.findRayIntersection(entityFrameOrigin, entityFrameDirection, localDistance, localFace)) { + if (entityFrameBox.findRayIntersection(entityFrameOrigin, entityFrameDirection, localDistance, + localFace, localSurfaceNormal)) { if (localDistance < distance) { // now ask the entity if we actually intersect if (entity->supportsDetailedRayIntersection()) { if (entity->findDetailedRayIntersection(origin, direction, keepSearching, element, localDistance, - localFace, intersectedObject, precisionPicking)) { + localFace, localSurfaceNormal, intersectedObject, precisionPicking)) { if (localDistance < distance) { distance = localDistance; face = localFace; + surfaceNormal = localSurfaceNormal; *intersectedObject = (void*)entity.get(); somethingIntersected = true; } @@ -545,6 +548,7 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con if (localDistance < distance) { distance = localDistance; face = localFace; + surfaceNormal = localSurfaceNormal; *intersectedObject = (void*)entity.get(); somethingIntersected = true; } diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index d7d8344dfa..c26b5417ed 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -143,7 +143,8 @@ public: virtual bool canRayIntersect() const { return hasEntities(); } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking, float distanceToElementCube); virtual bool findSpherePenetration(const glm::vec3& center, float radius, diff --git a/libraries/entities/src/LineEntityItem.h b/libraries/entities/src/LineEntityItem.h index 7e0f49c984..b462cd804c 100644 --- a/libraries/entities/src/LineEntityItem.h +++ b/libraries/entities/src/LineEntityItem.h @@ -64,8 +64,9 @@ class LineEntityItem : public EntityItem { // never have a ray intersection pick a LineEntityItem. virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, - void** intersectedObject, bool precisionPicking) const { return false; } + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, + void** intersectedObject, bool precisionPicking) const { return false; } virtual void debugDump() const; static const float DEFAULT_LINE_WIDTH; diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index 27a116e1b1..e20a0b1c93 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -73,8 +73,9 @@ class PolyLineEntityItem : public EntityItem { // never have a ray intersection pick a PolyLineEntityItem. virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, - void** intersectedObject, bool precisionPicking) const { return false; } + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, + void** intersectedObject, bool precisionPicking) const { return false;} virtual void debugDump() const; static const float DEFAULT_LINE_WIDTH; diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 4cacf22457..8a781bf127 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -44,8 +44,9 @@ class PolyVoxEntityItem : public EntityItem { // never have a ray intersection pick a PolyVoxEntityItem. virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, - void** intersectedObject, bool precisionPicking) const { return false; } + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, + void** intersectedObject, bool precisionPicking) const { return false; } virtual void debugDump() const; diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp index b00544e979..1d0b2db5b3 100644 --- a/libraries/entities/src/SphereEntityItem.cpp +++ b/libraries/entities/src/SphereEntityItem.cpp @@ -95,7 +95,7 @@ void SphereEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBi bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, bool& keepSearching, OctreeElementPointer& element, - float& distance, BoxFace& face, + float& distance, BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const { // determine the ray in the frame of the entity transformed from a unit sphere glm::mat4 entityToWorldMatrix = getEntityToWorldMatrix(); @@ -111,6 +111,7 @@ bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, cons // then translate back to work coordinates glm::vec3 hitAt = glm::vec3(entityToWorldMatrix * glm::vec4(entityFrameHitAt, 1.0f)); distance = glm::distance(origin, hitAt); + surfaceNormal = glm::normalize(hitAt - getCenterPosition()); return true; } return false; diff --git a/libraries/entities/src/SphereEntityItem.h b/libraries/entities/src/SphereEntityItem.h index 46798d6b10..19ea5d06f9 100644 --- a/libraries/entities/src/SphereEntityItem.h +++ b/libraries/entities/src/SphereEntityItem.h @@ -54,8 +54,9 @@ public: virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, - void** intersectedObject, bool precisionPicking) const; + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, + void** intersectedObject, bool precisionPicking) const; virtual void debugDump() const; diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index a4ce27f8b2..dec4f4b4da 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -129,12 +129,15 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits } bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const { glm::vec3 dimensions = getDimensions(); glm::vec2 xyDimensions(dimensions.x, dimensions.y); glm::quat rotation = getRotation(); glm::vec3 position = getPosition() + rotation * (dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT)); + + // FIXME - should set face and surfaceNormal return findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance); } diff --git a/libraries/entities/src/TextEntityItem.h b/libraries/entities/src/TextEntityItem.h index 101cef50b5..0874651302 100644 --- a/libraries/entities/src/TextEntityItem.h +++ b/libraries/entities/src/TextEntityItem.h @@ -47,7 +47,8 @@ public: virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const; static const QString DEFAULT_TEXT; diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index a4f60d5150..d6fc0e2148 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -99,13 +99,15 @@ void WebEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst } bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const { glm::vec3 dimensions = getDimensions(); glm::vec2 xyDimensions(dimensions.x, dimensions.y); glm::quat rotation = getRotation(); glm::vec3 position = getPosition() + rotation * (dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT)); + // FIXME - should set face and surfaceNormal return findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance); } diff --git a/libraries/entities/src/WebEntityItem.h b/libraries/entities/src/WebEntityItem.h index a2ca955916..7046051b8e 100644 --- a/libraries/entities/src/WebEntityItem.h +++ b/libraries/entities/src/WebEntityItem.h @@ -46,7 +46,8 @@ public: virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const; virtual void setSourceUrl(const QString& value); diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index 8d843bd0b9..137ad55303 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -246,7 +246,8 @@ void ZoneEntityItem::setCompoundShapeURL(const QString& url) { } bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const { return _zonesArePickable; diff --git a/libraries/entities/src/ZoneEntityItem.h b/libraries/entities/src/ZoneEntityItem.h index dbc3cede63..96b0f9cbeb 100644 --- a/libraries/entities/src/ZoneEntityItem.h +++ b/libraries/entities/src/ZoneEntityItem.h @@ -100,7 +100,8 @@ public: virtual bool supportsDetailedRayIntersection() const { return true; } virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const; virtual void debugDump() const; diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 62e4fa0219..758a47bc61 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -702,6 +702,7 @@ public: OctreeElementPointer& element; float& distance; BoxFace& face; + glm::vec3& surfaceNormal; void** intersectedObject; bool found; bool precisionPicking; @@ -711,17 +712,18 @@ bool findRayIntersectionOp(OctreeElementPointer element, void* extraData) { RayArgs* args = static_cast(extraData); bool keepSearching = true; if (element->findRayIntersection(args->origin, args->direction, keepSearching, - args->element, args->distance, args->face, args->intersectedObject, args->precisionPicking)) { + args->element, args->distance, args->face, args->surfaceNormal, + args->intersectedObject, args->precisionPicking)) { args->found = true; } return keepSearching; } bool Octree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - OctreeElementPointer& element, float& distance, BoxFace& face, void** intersectedObject, + OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, Octree::lockType lockType, bool* accurateResult, bool precisionPicking) { - RayArgs args = { origin, direction, element, distance, face, - intersectedObject, false, precisionPicking}; + RayArgs args = { origin, direction, element, distance, face, surfaceNormal, intersectedObject, false, precisionPicking}; distance = FLT_MAX; bool requireLock = lockType == Octree::Lock; diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 7d48e0e151..dececf1456 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -299,7 +299,7 @@ public: } lockType; bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - OctreeElementPointer& node, float& distance, BoxFace& face, + OctreeElementPointer& node, float& distance, BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject = NULL, Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL, diff --git a/libraries/octree/src/OctreeElement.cpp b/libraries/octree/src/OctreeElement.cpp index 9e2cfbbf63..25758c29d9 100644 --- a/libraries/octree/src/OctreeElement.cpp +++ b/libraries/octree/src/OctreeElement.cpp @@ -574,7 +574,8 @@ void OctreeElement::notifyUpdateHooks() { } bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) { keepSearching = true; // assume that we will continue searching after this. @@ -582,9 +583,10 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 float distanceToElementCube = std::numeric_limits::max(); float distanceToElementDetails = distance; BoxFace localFace; + glm::vec3 localSurfaceNormal; // if the ray doesn't intersect with our cube, we can stop searching! - if (!_cube.findRayIntersection(origin, direction, distanceToElementCube, localFace)) { + if (!_cube.findRayIntersection(origin, direction, distanceToElementCube, localFace, localSurfaceNormal)) { keepSearching = false; // no point in continuing to search return false; // we did not intersect } @@ -599,11 +601,12 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 if (_cube.contains(origin) || distanceToElementCube < distance) { if (findDetailedRayIntersection(origin, direction, keepSearching, element, distanceToElementDetails, - face, intersectedObject, precisionPicking, distanceToElementCube)) { + face, localSurfaceNormal, intersectedObject, precisionPicking, distanceToElementCube)) { if (distanceToElementDetails < distance) { distance = distanceToElementDetails; face = localFace; + surfaceNormal = localSurfaceNormal; return true; } } @@ -612,7 +615,8 @@ bool OctreeElement::findRayIntersection(const glm::vec3& origin, const glm::vec3 } bool OctreeElement::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking, float distanceToElementCube) { // we did hit this element, so calculate appropriate distances diff --git a/libraries/octree/src/OctreeElement.h b/libraries/octree/src/OctreeElement.h index 475d9568bb..fcdc9985e3 100644 --- a/libraries/octree/src/OctreeElement.h +++ b/libraries/octree/src/OctreeElement.h @@ -119,11 +119,13 @@ public: virtual bool canRayIntersect() const { return isLeaf(); } virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& node, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& node, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject = NULL, bool precisionPicking = false); virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction, - bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face, + bool& keepSearching, OctreeElementPointer& element, float& distance, + BoxFace& face, glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking, float distanceToElementCube); /// \param center center of sphere in meters diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 7aee46b108..ee40dcb913 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -457,7 +457,8 @@ void Model::initJointStates(QVector states) { } bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, - BoxFace& face, QString& extraInfo, bool pickAgainstTriangles) { + BoxFace& face, glm::vec3& surfaceNormal, + QString& extraInfo, bool pickAgainstTriangles) { bool intersectedSomething = false; @@ -484,11 +485,12 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g // we can use the AABox's ray intersection by mapping our origin and direction into the model frame // and testing intersection there. - if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face)) { + if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face, surfaceNormal)) { float bestDistance = std::numeric_limits::max(); float distanceToSubMesh; BoxFace subMeshFace; + glm::vec3 subMeshSurfaceNormal; int subMeshIndex = 0; const FBXGeometry& geometry = _geometry->getFBXGeometry(); @@ -500,9 +502,9 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g recalculateMeshBoxes(pickAgainstTriangles); } - foreach(const AABox& subMeshBox, _calculatedMeshBoxes) { + foreach (const AABox& subMeshBox, _calculatedMeshBoxes) { - if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace)) { + if (subMeshBox.findRayIntersection(origin, direction, distanceToSubMesh, subMeshFace, subMeshSurfaceNormal)) { if (distanceToSubMesh < bestDistance) { if (pickAgainstTriangles) { if (!_calculatedMeshTrianglesValid) { @@ -520,6 +522,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g bestDistance = thisTriangleDistance; intersectedSomething = true; face = subMeshFace; + surfaceNormal = triangle.getNormal(); extraInfo = geometry.getModelNameOfMesh(subMeshIndex); } } @@ -529,6 +532,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g bestDistance = distanceToSubMesh; intersectedSomething = true; face = subMeshFace; + surfaceNormal = subMeshSurfaceNormal; extraInfo = geometry.getModelNameOfMesh(subMeshIndex); } } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index de760dc793..cae94569b1 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -129,7 +129,8 @@ public: void setJointState(int index, bool valid, const glm::quat& rotation = glm::quat(), float priority = 1.0f); bool findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance, - BoxFace& face, QString& extraInfo, bool pickAgainstTriangles = false); + BoxFace& face, glm::vec3& surfaceNormal, + QString& extraInfo, bool pickAgainstTriangles = false); // Set the model to use for collisions Q_INVOKABLE void setCollisionModelURL(const QUrl& url); diff --git a/libraries/shared/src/AABox.cpp b/libraries/shared/src/AABox.cpp index a57ba8914d..b514e171eb 100644 --- a/libraries/shared/src/AABox.cpp +++ b/libraries/shared/src/AABox.cpp @@ -221,7 +221,8 @@ bool AABox::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& e isWithin(start.x + axisDistance*direction.x, expandedCorner.x, expandedSize.x)); } -bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const { +bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, + BoxFace& face, glm::vec3& surfaceNormal) const { // handle the trivial case where the box contains the origin if (contains(origin)) { // We still want to calculate the distance from the origin to the inside out plane @@ -231,6 +232,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale.z))) { distance = axisDistance; face = direction.x > 0 ? MAX_X_FACE : MIN_X_FACE; + surfaceNormal = glm::vec3(direction.x > 0 ? 1.0f : -1.0f, 0.0f, 0.0f); return true; } if ((findInsideOutIntersection(origin.y, direction.y, _corner.y, _scale.y, axisDistance) && axisDistance >= 0 && @@ -238,6 +240,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale.z))) { distance = axisDistance; face = direction.y > 0 ? MAX_Y_FACE : MIN_Y_FACE; + surfaceNormal = glm::vec3(0.0f, direction.y > 0 ? 1.0f : -1.0f, 0.0f); return true; } if ((findInsideOutIntersection(origin.z, direction.z, _corner.z, _scale.z, axisDistance) && axisDistance >= 0 && @@ -245,6 +248,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) { distance = axisDistance; face = direction.z > 0 ? MAX_Z_FACE : MIN_Z_FACE; + surfaceNormal = glm::vec3(0.0f, 0.0f, direction.z > 0 ? 1.0f : -1.0f); return true; } // This case is unexpected, but mimics the previous behavior for inside out intersections @@ -259,6 +263,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale.z))) { distance = axisDistance; face = direction.x > 0 ? MIN_X_FACE : MAX_X_FACE; + surfaceNormal = glm::vec3(direction.x > 0 ? -1.0f : 1.0f, 0.0f, 0.0f); return true; } if ((findIntersection(origin.y, direction.y, _corner.y, _scale.y, axisDistance) && axisDistance >= 0 && @@ -266,6 +271,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale.z))) { distance = axisDistance; face = direction.y > 0 ? MIN_Y_FACE : MAX_Y_FACE; + surfaceNormal = glm::vec3(0.0f, direction.y > 0 ? -1.0f : 1.0f, 0.0f); return true; } if ((findIntersection(origin.z, direction.z, _corner.z, _scale.z, axisDistance) && axisDistance >= 0 && @@ -273,6 +279,7 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale.x))) { distance = axisDistance; face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE; + surfaceNormal = glm::vec3(0.0f, 0.0f, direction.z > 0 ? -1.0f : 1.0f); return true; } return false; diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h index f185122534..1f5923dbd8 100644 --- a/libraries/shared/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -67,7 +67,8 @@ public: bool expandedContains(const glm::vec3& point, float expansion) const; bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const; - bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; + bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, + BoxFace& face, glm::vec3& surfaceNormal) const; bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const; bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const; diff --git a/libraries/shared/src/AACube.cpp b/libraries/shared/src/AACube.cpp index 18a990cc9a..32a304872c 100644 --- a/libraries/shared/src/AACube.cpp +++ b/libraries/shared/src/AACube.cpp @@ -219,7 +219,8 @@ bool AACube::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& isWithin(start.x + axisDistance*direction.x, expandedCorner.x, expandedSize.x)); } -bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const { +bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, + BoxFace& face, glm::vec3& surfaceNormal) const { // handle the trivial case where the box contains the origin if (contains(origin)) { @@ -230,6 +231,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) { distance = axisDistance; face = direction.x > 0 ? MAX_X_FACE : MIN_X_FACE; + surfaceNormal = glm::vec3(direction.x > 0 ? 1.0f : -1.0f, 0.0f, 0.0f); return true; } if ((findInsideOutIntersection(origin.y, direction.y, _corner.y, _scale, axisDistance) && axisDistance >= 0 && @@ -237,6 +239,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) { distance = axisDistance; face = direction.y > 0 ? MAX_Y_FACE : MIN_Y_FACE; + surfaceNormal = glm::vec3(0.0f, direction.y > 0 ? 1.0f : -1.0f, 0.0f); return true; } if ((findInsideOutIntersection(origin.z, direction.z, _corner.z, _scale, axisDistance) && axisDistance >= 0 && @@ -244,6 +247,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) { distance = axisDistance; face = direction.z > 0 ? MAX_Z_FACE : MIN_Z_FACE; + surfaceNormal = glm::vec3(0.0f, 0.0f, direction.z > 0 ? 1.0f : -1.0f); return true; } // This case is unexpected, but mimics the previous behavior for inside out intersections @@ -258,6 +262,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) { distance = axisDistance; face = direction.x > 0 ? MIN_X_FACE : MAX_X_FACE; + surfaceNormal = glm::vec3(direction.x > 0 ? -1.0f : 1.0f, 0.0f, 0.0f); return true; } if ((findIntersection(origin.y, direction.y, _corner.y, _scale, axisDistance) && axisDistance >= 0 && @@ -265,6 +270,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) { distance = axisDistance; face = direction.y > 0 ? MIN_Y_FACE : MAX_Y_FACE; + surfaceNormal = glm::vec3(0.0f, direction.y > 0 ? -1.0f : 1.0f, 0.0f); return true; } if ((findIntersection(origin.z, direction.z, _corner.z, _scale, axisDistance) && axisDistance >= 0 && @@ -272,6 +278,7 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) { distance = axisDistance; face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE; + surfaceNormal = glm::vec3(0.0f, 0.0f, direction.z > 0 ? -1.0f : 1.0f); return true; } return false; diff --git a/libraries/shared/src/AACube.h b/libraries/shared/src/AACube.h index b29bc49bef..d301207429 100644 --- a/libraries/shared/src/AACube.h +++ b/libraries/shared/src/AACube.h @@ -56,7 +56,8 @@ public: bool touches(const AABox& otherBox) const; bool expandedContains(const glm::vec3& point, float expansion) const; bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const; - bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; + bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, + BoxFace& face, glm::vec3& surfaceNormal) const; bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const; bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const; diff --git a/libraries/shared/src/GeometryUtil.cpp b/libraries/shared/src/GeometryUtil.cpp index 7d8ee185d5..96c4d3bdea 100644 --- a/libraries/shared/src/GeometryUtil.cpp +++ b/libraries/shared/src/GeometryUtil.cpp @@ -255,6 +255,13 @@ bool findRayCapsuleIntersection(const glm::vec3& origin, const glm::vec3& direct return true; } +// reference https://www.opengl.org/wiki/Calculating_a_Surface_Normal +glm::vec3 Triangle::getNormal() const { + glm::vec3 edge1 = v1 - v0; + glm::vec3 edge2 = v2 - v0; + return glm::normalize(glm::cross(edge1, edge2)); +} + bool findRayTriangleIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, float& distance) { glm::vec3 firstSide = v0 - v1; diff --git a/libraries/shared/src/GeometryUtil.h b/libraries/shared/src/GeometryUtil.h index b6bbdeaebb..7224aaacff 100644 --- a/libraries/shared/src/GeometryUtil.h +++ b/libraries/shared/src/GeometryUtil.h @@ -97,6 +97,7 @@ public: glm::vec3 v0; glm::vec3 v1; glm::vec3 v2; + glm::vec3 getNormal() const; }; inline bool findRayTriangleIntersection(const glm::vec3& origin, const glm::vec3& direction, diff --git a/tests/octree/src/AABoxCubeTests.cpp b/tests/octree/src/AABoxCubeTests.cpp index cc9c06161c..8180e6f674 100644 --- a/tests/octree/src/AABoxCubeTests.cpp +++ b/tests/octree/src/AABoxCubeTests.cpp @@ -26,8 +26,9 @@ void AABoxCubeTests::raycastOutHitsXMinFace() { glm::vec3 direction(-1.0f, 0.0f, 0.0f); float distance; BoxFace face; + glm::vec3 surfaceNormal; - bool intersects = box.findRayIntersection(origin, direction, distance, face); + bool intersects = box.findRayIntersection(origin, direction, distance, face, surfaceNormal); QCOMPARE(intersects, true); QCOMPARE(distance, 0.5f); @@ -44,9 +45,10 @@ void AABoxCubeTests::raycastOutHitsXMaxFace () { glm::vec3 direction(1.0f, 0.0f, 0.0f); float distance; BoxFace face; + glm::vec3 surfaceNormal; + + bool intersects = box.findRayIntersection(origin, direction, distance, face, surfaceNormal); - bool intersects = box.findRayIntersection(origin, direction, distance, face); - QCOMPARE(intersects, true); QCOMPARE(distance, 0.5f); QCOMPARE(face, MAX_X_FACE); @@ -61,9 +63,10 @@ void AABoxCubeTests::raycastInHitsXMinFace () { glm::vec3 direction(1.0f, 0.0f, 0.0f); float distance; BoxFace face; + glm::vec3 surfaceNormal; + + bool intersects = box.findRayIntersection(origin, direction, distance, face, surfaceNormal); - bool intersects = box.findRayIntersection(origin, direction, distance, face); - QCOMPARE(intersects, true); QCOMPARE(distance, 0.25f); QCOMPARE(face, MIN_X_FACE);