added support for returning accuracy of ray intersections and other octree tests that can fail due to getting lock

This commit is contained in:
ZappoMan 2014-04-29 15:10:28 -07:00
parent 8a823ee4c4
commit 4aa96e1fbe
9 changed files with 112 additions and 29 deletions

View file

@ -19,6 +19,12 @@ function mouseMoveEvent(event) {
print("computePickRay direction=" + pickRay.direction.x + ", " + pickRay.direction.y + ", " + pickRay.direction.z);
var pickRay = Camera.computePickRay(event.x, event.y);
var intersection = Voxels.findRayIntersection(pickRay);
if (!intersection.accurate) {
print(">>> NOTE: intersection not accurate. will try calling Voxels.findRayIntersectionBlocking()");
intersection = Voxels.findRayIntersectionBlocking(pickRay);
print(">>> AFTER BLOCKING CALL intersection.accurate=" + intersection.accurate);
}
if (intersection.intersects) {
print("intersection voxel.red/green/blue=" + intersection.voxel.red + ", "
+ intersection.voxel.green + ", " + intersection.voxel.blue);

View file

@ -594,8 +594,9 @@ bool findRayIntersectionOp(OctreeElement* node, void* extraData) {
}
bool Octree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
OctreeElement*& node, float& distance, BoxFace& face, Octree::lockType lockType) {
RayArgs args = { origin / (float)(TREE_SCALE), direction, node, distance, face };
OctreeElement*& node, float& distance, BoxFace& face,
Octree::lockType lockType, bool* accurateResult) {
RayArgs args = { origin / (float)(TREE_SCALE), direction, node, distance, face, false};
bool gotLock = false;
if (lockType == Octree::Lock) {
@ -604,6 +605,9 @@ bool Octree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc
} else if (lockType == Octree::TryLock) {
gotLock = tryLockForRead();
if (!gotLock) {
if (accurateResult) {
*accurateResult = false; // if user asked to accuracy or result, let them know this is inaccurate
}
return args.found; // if we wanted to tryLock, and we couldn't then just bail...
}
}
@ -614,6 +618,9 @@ bool Octree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc
unlock();
}
if (accurateResult) {
*accurateResult = true; // if user asked to accuracy or result, let them know this is accurate
}
return args.found;
}
@ -640,7 +647,8 @@ bool findSpherePenetrationOp(OctreeElement* element, void* extraData) {
if (element->hasContent()) {
glm::vec3 elementPenetration;
if (element->findSpherePenetration(args->center, args->radius, elementPenetration, &args->penetratedObject)) {
// NOTE: it is possible for this penetration accumulation algorithm to produce a final penetration vector with zero length.
// NOTE: it is possible for this penetration accumulation algorithm to produce a
// final penetration vector with zero length.
args->penetration = addPenetrations(args->penetration, elementPenetration * (float)(TREE_SCALE));
args->found = true;
}
@ -649,7 +657,7 @@ bool findSpherePenetrationOp(OctreeElement* element, void* extraData) {
}
bool Octree::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration,
void** penetratedObject, Octree::lockType lockType) {
void** penetratedObject, Octree::lockType lockType, bool* accurateResult) {
SphereArgs args = {
center / (float)(TREE_SCALE),
@ -666,6 +674,9 @@ bool Octree::findSpherePenetration(const glm::vec3& center, float radius, glm::v
} else if (lockType == Octree::TryLock) {
gotLock = tryLockForRead();
if (!gotLock) {
if (accurateResult) {
*accurateResult = false; // if user asked to accuracy or result, let them know this is inaccurate
}
return args.found; // if we wanted to tryLock, and we couldn't then just bail...
}
}
@ -679,6 +690,9 @@ bool Octree::findSpherePenetration(const glm::vec3& center, float radius, glm::v
unlock();
}
if (accurateResult) {
*accurateResult = true; // if user asked to accuracy or result, let them know this is accurate
}
return args.found;
}
@ -741,7 +755,7 @@ bool findShapeCollisionsOp(OctreeElement* node, void* extraData) {
}
bool Octree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius,
glm::vec3& penetration, Octree::lockType lockType) {
glm::vec3& penetration, Octree::lockType lockType, bool* accurateResult) {
CapsuleArgs args = {
start / (float)(TREE_SCALE),
@ -758,6 +772,9 @@ bool Octree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end
} else if (lockType == Octree::TryLock) {
gotLock = tryLockForRead();
if (!gotLock) {
if (accurateResult) {
*accurateResult = false; // if user asked to accuracy or result, let them know this is inaccurate
}
return args.found; // if we wanted to tryLock, and we couldn't then just bail...
}
}
@ -767,10 +784,15 @@ bool Octree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end
if (gotLock) {
unlock();
}
if (accurateResult) {
*accurateResult = true; // if user asked to accuracy or result, let them know this is accurate
}
return args.found;
}
bool Octree::findShapeCollisions(const Shape* shape, CollisionList& collisions, Octree::lockType lockType) {
bool Octree::findShapeCollisions(const Shape* shape, CollisionList& collisions,
Octree::lockType lockType, bool* accurateResult) {
ShapeArgs args = { shape, collisions, false };
@ -781,6 +803,9 @@ bool Octree::findShapeCollisions(const Shape* shape, CollisionList& collisions,
} else if (lockType == Octree::TryLock) {
gotLock = tryLockForRead();
if (!gotLock) {
if (accurateResult) {
*accurateResult = false; // if user asked to accuracy or result, let them know this is inaccurate
}
return args.found; // if we wanted to tryLock, and we couldn't then just bail...
}
}
@ -790,6 +815,10 @@ bool Octree::findShapeCollisions(const Shape* shape, CollisionList& collisions,
if (gotLock) {
unlock();
}
if (accurateResult) {
*accurateResult = true; // if user asked to accuracy or result, let them know this is accurate
}
return args.found;
}
@ -816,7 +845,7 @@ bool getElementEnclosingOperation(OctreeElement* element, void* extraData) {
return true; // keep looking
}
OctreeElement* Octree::getElementEnclosingPoint(const glm::vec3& point, Octree::lockType lockType) {
OctreeElement* Octree::getElementEnclosingPoint(const glm::vec3& point, Octree::lockType lockType, bool* accurateResult) {
GetElementEnclosingArgs args;
args.point = point;
args.element = NULL;
@ -828,6 +857,9 @@ OctreeElement* Octree::getElementEnclosingPoint(const glm::vec3& point, Octree::
} else if (lockType == Octree::TryLock) {
gotLock = tryLockForRead();
if (!gotLock) {
if (accurateResult) {
*accurateResult = false; // if user asked to accuracy or result, let them know this is inaccurate
}
return args.element; // if we wanted to tryLock, and we couldn't then just bail...
}
}
@ -838,6 +870,9 @@ OctreeElement* Octree::getElementEnclosingPoint(const glm::vec3& point, Octree::
unlock();
}
if (accurateResult) {
*accurateResult = false; // if user asked to accuracy or result, let them know this is inaccurate
}
return args.element;
}

View file

@ -249,17 +249,20 @@ public:
} lockType;
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
OctreeElement*& node, float& distance, BoxFace& face, Octree::lockType lockType = Octree::TryLock);
OctreeElement*& node, float& distance, BoxFace& face,
Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL);
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration,
void** penetratedObject = NULL, Octree::lockType lockType = Octree::TryLock);
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration, void** penetratedObject = NULL,
Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL);
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius,
glm::vec3& penetration, Octree::lockType lockType = Octree::TryLock);
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration,
Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL);
bool findShapeCollisions(const Shape* shape, CollisionList& collisions, Octree::lockType = Octree::TryLock);
bool findShapeCollisions(const Shape* shape, CollisionList& collisions,
Octree::lockType = Octree::TryLock, bool* accurateResult = NULL);
OctreeElement* getElementEnclosingPoint(const glm::vec3& point, Octree::lockType lockType = Octree::TryLock);
OctreeElement* getElementEnclosingPoint(const glm::vec3& point,
Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL);
// Note: this assumes the fileFormat is the HIO individual voxels code files
void loadOctreeFile(const char* fileName, bool wantColorRandomizer);

View file

@ -119,10 +119,19 @@ void LocalVoxels::pasteFrom(float x, float y, float z, float scale, const QStrin
}
RayToVoxelIntersectionResult LocalVoxels::findRayIntersection(const PickRay& ray) {
return findRayIntersectionWorker(ray, Octree::TryLock);
}
RayToVoxelIntersectionResult LocalVoxels::findRayIntersectionBlocking(const PickRay& ray) {
return findRayIntersectionWorker(ray, Octree::Lock);
}
RayToVoxelIntersectionResult LocalVoxels::findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType) {
RayToVoxelIntersectionResult result;
if (_tree) {
OctreeElement* element;
result.intersects = _tree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face);
result.intersects = _tree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face,
lockType, &result.accurate);
if (result.intersects) {
VoxelTreeElement* voxel = (VoxelTreeElement*)element;
result.voxel.x = voxel->getCorner().x;

View file

@ -76,13 +76,22 @@ public:
/// \param source LocalVoxels' source tree
Q_INVOKABLE void pasteFrom(float x, float y, float z, float scale, const QString source);
/// If the scripting context has visible voxels, this will determine a ray intersection
/// If the scripting context has visible voxels, this will determine a ray intersection, the results
/// may be inaccurate if the engine is unable to access the visible voxels, in which case result.accurate
/// will be false.
Q_INVOKABLE RayToVoxelIntersectionResult findRayIntersection(const PickRay& ray);
/// If the scripting context has visible voxels, this will determine a ray intersection, and will block in
/// order to return an accurate result
Q_INVOKABLE RayToVoxelIntersectionResult findRayIntersectionBlocking(const PickRay& ray);
/// returns a voxel space axis aligned vector for the face, useful in doing voxel math
Q_INVOKABLE glm::vec3 getFaceVector(const QString& face);
private:
/// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode
RayToVoxelIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType);
QString _name;
StrongVoxelTreePointer _tree;
};

View file

@ -41,6 +41,7 @@ void voxelDetailFromScriptValue(const QScriptValue &object, VoxelDetail& voxelDe
RayToVoxelIntersectionResult::RayToVoxelIntersectionResult() :
intersects(false),
accurate(true), // assume it's accurate
voxel(),
distance(0),
face()
@ -50,6 +51,7 @@ RayToVoxelIntersectionResult::RayToVoxelIntersectionResult() :
QScriptValue rayToVoxelIntersectionResultToScriptValue(QScriptEngine* engine, const RayToVoxelIntersectionResult& value) {
QScriptValue obj = engine->newObject();
obj.setProperty("intersects", value.intersects);
obj.setProperty("accurate", value.accurate);
QScriptValue voxelValue = voxelDetailToScriptValue(engine, value.voxel);
obj.setProperty("voxel", voxelValue);
obj.setProperty("distance", value.distance);
@ -88,6 +90,7 @@ QScriptValue rayToVoxelIntersectionResultToScriptValue(QScriptEngine* engine, co
void rayToVoxelIntersectionResultFromScriptValue(const QScriptValue& object, RayToVoxelIntersectionResult& value) {
value.intersects = object.property("intersects").toVariant().toBool();
value.accurate = object.property("accurate").toVariant().toBool();
QScriptValue voxelValue = object.property("voxel");
if (voxelValue.isValid()) {
voxelDetailFromScriptValue(voxelValue, value.voxel);

View file

@ -39,6 +39,7 @@ class RayToVoxelIntersectionResult {
public:
RayToVoxelIntersectionResult();
bool intersects;
bool accurate;
VoxelDetail voxel;
float distance;
BoxFace face;

View file

@ -122,12 +122,21 @@ void VoxelsScriptingInterface::eraseVoxel(float x, float y, float z, float scale
}
}
RayToVoxelIntersectionResult VoxelsScriptingInterface::findRayIntersection(const PickRay& ray) {
return findRayIntersectionWorker(ray, Octree::TryLock);
}
RayToVoxelIntersectionResult VoxelsScriptingInterface::findRayIntersectionBlocking(const PickRay& ray) {
return findRayIntersectionWorker(ray, Octree::Lock);
}
RayToVoxelIntersectionResult VoxelsScriptingInterface::findRayIntersectionWorker(const PickRay& ray,
Octree::lockType lockType) {
RayToVoxelIntersectionResult result;
if (_tree) {
OctreeElement* element;
result.intersects = _tree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face);
result.intersects = _tree->findRayIntersection(ray.origin, ray.direction, element, result.distance, result.face,
lockType, &result.accurate);
if (result.intersects) {
VoxelTreeElement* voxel = (VoxelTreeElement*)element;
result.voxel.x = voxel->getCorner().x;

View file

@ -35,17 +35,16 @@ public:
void setVoxelTree(VoxelTree* tree) { _tree = tree; }
void setUndoStack(QUndoStack* undoStack) { _undoStack = undoStack; }
public slots:
public:
/// provide the world scale
const int getTreeScale() const { return TREE_SCALE; }
Q_INVOKABLE const int getTreeScale() const { return TREE_SCALE; }
/// checks the local voxel tree for a voxel at the specified location and scale
/// \param x the x-coordinate of the voxel (in meter units)
/// \param y the y-coordinate of the voxel (in meter units)
/// \param z the z-coordinate of the voxel (in meter units)
/// \param scale the scale of the voxel (in meter units)
VoxelDetail getVoxelAt(float x, float y, float z, float scale);
Q_INVOKABLE VoxelDetail getVoxelAt(float x, float y, float z, float scale);
/// queues the creation of a voxel which will be sent by calling process on the PacketSender
/// \param x the x-coordinate of the voxel (in meter units)
@ -55,7 +54,7 @@ public slots:
/// \param red the R value for RGB color of voxel
/// \param green the G value for RGB color of voxel
/// \param blue the B value for RGB color of voxel
void setVoxelNonDestructive(float x, float y, float z, float scale, uchar red, uchar green, uchar blue);
Q_INVOKABLE void setVoxelNonDestructive(float x, float y, float z, float scale, uchar red, uchar green, uchar blue);
/// queues the destructive creation of a voxel which will be sent by calling process on the PacketSender
/// \param x the x-coordinate of the voxel (in meter units)
@ -65,27 +64,36 @@ public slots:
/// \param red the R value for RGB color of voxel
/// \param green the G value for RGB color of voxel
/// \param blue the B value for RGB color of voxel
void setVoxel(float x, float y, float z, float scale, uchar red, uchar green, uchar blue);
Q_INVOKABLE void setVoxel(float x, float y, float z, float scale, uchar red, uchar green, uchar blue);
/// queues the deletion of a voxel, sent by calling process on the PacketSender
/// \param x the x-coordinate of the voxel (in meter units)
/// \param y the y-coordinate of the voxel (in meter units)
/// \param z the z-coordinate of the voxel (in meter units)
/// \param scale the scale of the voxel (in meter units)
void eraseVoxel(float x, float y, float z, float scale);
Q_INVOKABLE void eraseVoxel(float x, float y, float z, float scale);
/// If the scripting context has visible voxels, this will determine a ray intersection
RayToVoxelIntersectionResult findRayIntersection(const PickRay& ray);
/// If the scripting context has visible voxels, this will determine a ray intersection, the results
/// may be inaccurate if the engine is unable to access the visible voxels, in which case result.accurate
/// will be false.
Q_INVOKABLE RayToVoxelIntersectionResult findRayIntersection(const PickRay& ray);
/// If the scripting context has visible voxels, this will determine a ray intersection, and will block in
/// order to return an accurate result
Q_INVOKABLE RayToVoxelIntersectionResult findRayIntersectionBlocking(const PickRay& ray);
/// returns a voxel space axis aligned vector for the face, useful in doing voxel math
glm::vec3 getFaceVector(const QString& face);
Q_INVOKABLE glm::vec3 getFaceVector(const QString& face);
/// checks the local voxel tree for the smallest voxel enclosing the point
/// \param point the x,y,z coordinates of the point (in meter units)
/// \return VoxelDetail - if no voxel encloses the point then VoxelDetail items will be 0
VoxelDetail getVoxelEnclosingPoint(const glm::vec3& point);
Q_INVOKABLE VoxelDetail getVoxelEnclosingPoint(const glm::vec3& point);
private:
/// actually does the work of finding the ray intersection, can be called in locking mode or tryLock mode
RayToVoxelIntersectionResult findRayIntersectionWorker(const PickRay& ray, Octree::lockType lockType);
void queueVoxelAdd(PacketType addPacketType, VoxelDetail& addVoxelDetails);
VoxelTree* _tree;
QUndoStack* _undoStack;