Merge pull request #5911 from ZappoMan/rayIntersectionWork

adding surface normals to ray intersection
This commit is contained in:
Eric Levin 2015-09-28 17:21:40 -07:00
commit e8e9957846
56 changed files with 229 additions and 110 deletions

View file

@ -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);
});

View file

@ -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;
}

View file

@ -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:

View file

@ -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);

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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 {

View file

@ -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;

View file

@ -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<Base3DOverlay>(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;

View file

@ -46,6 +46,7 @@ public:
int overlayID;
float distance;
BoxFace face;
glm::vec3 surfaceNormal;
glm::vec3 intersection;
QString extraInfo;
};

View file

@ -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);
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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

View file

@ -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.

View file

@ -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;

View file

@ -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();

View file

@ -87,10 +87,10 @@ public:
QList<EntityItemID>& 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);

View file

@ -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

View file

@ -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();

View file

@ -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) {

View file

@ -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);

View file

@ -348,13 +348,10 @@ public:
const PolyVox::SimpleVolume<uint8_t>* _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;

View file

@ -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);

View file

@ -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

View file

@ -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,

View file

@ -43,6 +43,7 @@ public:
float distance;
BoxFace face;
glm::vec3 intersection;
glm::vec3 surfaceNormal;
EntityItemPointer entity;
};

View file

@ -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;
}

View file

@ -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,

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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<RayArgs*>(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;

View file

@ -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,

View file

@ -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<float>::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

View file

@ -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

View file

@ -457,7 +457,8 @@ void Model::initJointStates(QVector<JointState> 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<float>::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);
}
}

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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,

View file

@ -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);