mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-17 08:13:10 +02:00
parabola triangle intersection
This commit is contained in:
parent
fcc523fbef
commit
ca5ce888f4
8 changed files with 333 additions and 19 deletions
|
@ -294,6 +294,18 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori
|
|||
face, surfaceNormal, extraInfo, precisionPicking, false);
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance, BoxFace& face,
|
||||
glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const {
|
||||
auto model = getModel();
|
||||
if (!model || !isModelLoaded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return model->findParabolaIntersectionAgainstSubMeshes(origin, velocity, acceleration, parabolicDistance,
|
||||
face, surfaceNormal, extraInfo, precisionPicking, false);
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::getCollisionGeometryResource() {
|
||||
QUrl hullURL(getCompoundShapeURL());
|
||||
QUrlQuery queryArgs(hullURL);
|
||||
|
|
|
@ -71,6 +71,10 @@ public:
|
|||
OctreeElementPointer& element, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
virtual bool findDetailedParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, OctreeElementPointer& element, float& parabolicDistance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool precisionPicking) const override;
|
||||
|
||||
virtual void setShapeType(ShapeType type) override;
|
||||
virtual void setCompoundShapeURL(const QString& url) override;
|
||||
|
|
|
@ -353,31 +353,27 @@ void Model::initJointStates() {
|
|||
bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
|
||||
bool pickAgainstTriangles, bool allowBackface) {
|
||||
|
||||
bool intersectedSomething = false;
|
||||
|
||||
// if we aren't active, we can't ray pick yet...
|
||||
// if we aren't active, we can't pick yet...
|
||||
if (!isActive()) {
|
||||
return intersectedSomething;
|
||||
}
|
||||
|
||||
// extents is the entity relative, scaled, centered extents of the entity
|
||||
glm::vec3 position = _translation;
|
||||
glm::mat4 rotation = glm::mat4_cast(_rotation);
|
||||
glm::mat4 translation = glm::translate(position);
|
||||
glm::mat4 modelToWorldMatrix = translation * rotation;
|
||||
glm::mat4 modelToWorldMatrix = createMatFromQuatAndPos(_rotation, _translation);
|
||||
glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix);
|
||||
|
||||
Extents modelExtents = getMeshExtents(); // NOTE: unrotated
|
||||
|
||||
glm::vec3 dimensions = modelExtents.maximum - modelExtents.minimum;
|
||||
glm::vec3 corner = -(dimensions * _registrationPoint); // since we're going to do the ray picking in the model frame of reference
|
||||
glm::vec3 corner = -(dimensions * _registrationPoint); // since we're going to do the picking in the model frame of reference
|
||||
AABox modelFrameBox(corner, dimensions);
|
||||
|
||||
glm::vec3 modelFrameOrigin = glm::vec3(worldToModelMatrix * glm::vec4(origin, 1.0f));
|
||||
glm::vec3 modelFrameDirection = glm::vec3(worldToModelMatrix * glm::vec4(direction, 0.0f));
|
||||
|
||||
// we can use the AABox's ray intersection by mapping our origin and direction into the model frame
|
||||
// we can use the AABox's intersection by mapping our origin and direction into the model frame
|
||||
// and testing intersection there.
|
||||
if (modelFrameBox.findRayIntersection(modelFrameOrigin, modelFrameDirection, distance, face, surfaceNormal)) {
|
||||
QMutexLocker locker(&_mutex);
|
||||
|
@ -395,7 +391,7 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
|||
}
|
||||
|
||||
glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset);
|
||||
glm::mat4 meshToWorldMatrix = createMatFromQuatAndPos(_rotation, _translation) * meshToModelMatrix;
|
||||
glm::mat4 meshToWorldMatrix = modelToWorldMatrix * meshToModelMatrix;
|
||||
glm::mat4 worldToMeshMatrix = glm::inverse(meshToWorldMatrix);
|
||||
|
||||
glm::vec3 meshFrameOrigin = glm::vec3(worldToMeshMatrix * glm::vec4(origin, 1.0f));
|
||||
|
@ -405,11 +401,10 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
|||
for (auto& meshTriangleSets : _modelSpaceMeshTriangleSets) {
|
||||
int partIndex = 0;
|
||||
for (auto &partTriangleSet : meshTriangleSets) {
|
||||
float triangleSetDistance = 0.0f;
|
||||
float triangleSetDistance;
|
||||
BoxFace triangleSetFace;
|
||||
Triangle triangleSetTriangle;
|
||||
if (partTriangleSet.findRayIntersection(meshFrameOrigin, meshFrameDirection, triangleSetDistance, triangleSetFace, triangleSetTriangle, pickAgainstTriangles, allowBackface)) {
|
||||
|
||||
glm::vec3 meshIntersectionPoint = meshFrameOrigin + (meshFrameDirection * triangleSetDistance);
|
||||
glm::vec3 worldIntersectionPoint = glm::vec3(meshToWorldMatrix * glm::vec4(meshIntersectionPoint, 1.0f));
|
||||
float worldDistance = glm::distance(origin, worldIntersectionPoint);
|
||||
|
@ -457,6 +452,111 @@ bool Model::findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const g
|
|||
return intersectedSomething;
|
||||
}
|
||||
|
||||
bool Model::findParabolaIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo,
|
||||
bool pickAgainstTriangles, bool allowBackface) {
|
||||
bool intersectedSomething = false;
|
||||
|
||||
// if we aren't active, we can't pick yet...
|
||||
if (!isActive()) {
|
||||
return intersectedSomething;
|
||||
}
|
||||
|
||||
// extents is the entity relative, scaled, centered extents of the entity
|
||||
glm::mat4 modelToWorldMatrix = createMatFromQuatAndPos(_rotation, _translation);
|
||||
glm::mat4 worldToModelMatrix = glm::inverse(modelToWorldMatrix);
|
||||
|
||||
Extents modelExtents = getMeshExtents(); // NOTE: unrotated
|
||||
|
||||
glm::vec3 dimensions = modelExtents.maximum - modelExtents.minimum;
|
||||
glm::vec3 corner = -(dimensions * _registrationPoint); // since we're going to do the picking in the model frame of reference
|
||||
AABox modelFrameBox(corner, dimensions);
|
||||
|
||||
glm::vec3 modelFrameOrigin = glm::vec3(worldToModelMatrix * glm::vec4(origin, 1.0f));
|
||||
glm::vec3 modelFrameVelocity = glm::vec3(worldToModelMatrix * glm::vec4(velocity, 0.0f));
|
||||
glm::vec3 modelFrameAcceleration = glm::vec3(worldToModelMatrix * glm::vec4(acceleration, 0.0f));
|
||||
|
||||
// we can use the AABox's intersection by mapping our origin and direction into the model frame
|
||||
// and testing intersection there.
|
||||
if (modelFrameBox.findParabolaIntersection(modelFrameOrigin, modelFrameVelocity, modelFrameAcceleration, parabolicDistance, face, surfaceNormal)) {
|
||||
QMutexLocker locker(&_mutex);
|
||||
|
||||
float bestDistance = FLT_MAX;
|
||||
Triangle bestModelTriangle;
|
||||
Triangle bestWorldTriangle;
|
||||
int bestSubMeshIndex = 0;
|
||||
|
||||
int subMeshIndex = 0;
|
||||
const FBXGeometry& geometry = getFBXGeometry();
|
||||
|
||||
if (!_triangleSetsValid) {
|
||||
calculateTriangleSets(geometry);
|
||||
}
|
||||
|
||||
glm::mat4 meshToModelMatrix = glm::scale(_scale) * glm::translate(_offset);
|
||||
glm::mat4 meshToWorldMatrix = modelToWorldMatrix * meshToModelMatrix;
|
||||
glm::mat4 worldToMeshMatrix = glm::inverse(meshToWorldMatrix);
|
||||
|
||||
glm::vec3 meshFrameOrigin = glm::vec3(worldToMeshMatrix * glm::vec4(origin, 1.0f));
|
||||
glm::vec3 meshFrameVelocity = glm::vec3(worldToMeshMatrix * glm::vec4(velocity, 0.0f));
|
||||
glm::vec3 meshFrameAcceleration = glm::vec3(worldToMeshMatrix * glm::vec4(acceleration, 0.0f));
|
||||
|
||||
int shapeID = 0;
|
||||
for (auto& meshTriangleSets : _modelSpaceMeshTriangleSets) {
|
||||
int partIndex = 0;
|
||||
for (auto &partTriangleSet : meshTriangleSets) {
|
||||
float triangleSetDistance;
|
||||
BoxFace triangleSetFace;
|
||||
Triangle triangleSetTriangle;
|
||||
if (partTriangleSet.findParabolaIntersection(meshFrameOrigin, meshFrameVelocity, meshFrameAcceleration,
|
||||
triangleSetDistance, triangleSetFace, triangleSetTriangle, pickAgainstTriangles, allowBackface)) {
|
||||
if (triangleSetDistance < bestDistance) {
|
||||
bestDistance = triangleSetDistance;
|
||||
intersectedSomething = true;
|
||||
face = triangleSetFace;
|
||||
bestModelTriangle = triangleSetTriangle;
|
||||
bestWorldTriangle = triangleSetTriangle * meshToWorldMatrix;
|
||||
glm::vec3 worldIntersectionPoint = meshFrameOrigin + meshFrameVelocity * triangleSetDistance +
|
||||
0.5f * meshFrameAcceleration * triangleSetDistance * triangleSetDistance;
|
||||
glm::vec3 meshIntersectionPoint = origin + velocity * triangleSetDistance +
|
||||
0.5f * acceleration * triangleSetDistance * triangleSetDistance;
|
||||
extraInfo["worldIntersectionPoint"] = vec3toVariant(worldIntersectionPoint);
|
||||
extraInfo["meshIntersectionPoint"] = vec3toVariant(meshIntersectionPoint);
|
||||
extraInfo["partIndex"] = partIndex;
|
||||
extraInfo["shapeID"] = shapeID;
|
||||
bestSubMeshIndex = subMeshIndex;
|
||||
}
|
||||
}
|
||||
partIndex++;
|
||||
shapeID++;
|
||||
}
|
||||
subMeshIndex++;
|
||||
}
|
||||
|
||||
if (intersectedSomething) {
|
||||
parabolicDistance = bestDistance;
|
||||
surfaceNormal = bestWorldTriangle.getNormal();
|
||||
if (pickAgainstTriangles) {
|
||||
extraInfo["subMeshIndex"] = bestSubMeshIndex;
|
||||
extraInfo["subMeshName"] = geometry.getModelNameOfMesh(bestSubMeshIndex);
|
||||
extraInfo["subMeshTriangleWorld"] = QVariantMap{
|
||||
{ "v0", vec3toVariant(bestWorldTriangle.v0) },
|
||||
{ "v1", vec3toVariant(bestWorldTriangle.v1) },
|
||||
{ "v2", vec3toVariant(bestWorldTriangle.v2) },
|
||||
};
|
||||
extraInfo["subMeshNormal"] = vec3toVariant(bestModelTriangle.getNormal());
|
||||
extraInfo["subMeshTriangle"] = QVariantMap{
|
||||
{ "v0", vec3toVariant(bestModelTriangle.v0) },
|
||||
{ "v1", vec3toVariant(bestModelTriangle.v1) },
|
||||
{ "v2", vec3toVariant(bestModelTriangle.v2) },
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return intersectedSomething;
|
||||
}
|
||||
|
||||
bool Model::convexHullContains(glm::vec3 point) {
|
||||
// if we aren't active, we can't compute that yet...
|
||||
if (!isActive()) {
|
||||
|
@ -594,7 +694,7 @@ bool Model::replaceScriptableModelMeshPart(scriptable::ScriptableModelBasePointe
|
|||
}
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
// update triangles for ray picking
|
||||
// update triangles for picking
|
||||
{
|
||||
FBXGeometry geometry;
|
||||
for (const auto& newMesh : meshes) {
|
||||
|
|
|
@ -178,6 +178,9 @@ public:
|
|||
bool findRayIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool pickAgainstTriangles = false, bool allowBackface = false);
|
||||
bool findParabolaIntersectionAgainstSubMeshes(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
float& parabolicDistance, BoxFace& face, glm::vec3& surfaceNormal,
|
||||
QVariantMap& extraInfo, bool pickAgainstTriangles = false, bool allowBackface = false);
|
||||
|
||||
void setOffset(const glm::vec3& offset);
|
||||
const glm::vec3& getOffset() const { return _offset; }
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <complex>
|
||||
#include <qmath.h>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include "glm/gtc/matrix_transform.hpp"
|
||||
|
||||
#include "NumericalConstants.h"
|
||||
#include "GLMHelpers.h"
|
||||
|
@ -797,6 +798,62 @@ bool findParabolaSphereIntersection(const glm::vec3& origin, const glm::vec3& ve
|
|||
return false;
|
||||
}
|
||||
|
||||
void checkPossibleParabolicIntersectionWithTriangle(float t, float& minDistance,
|
||||
const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
const glm::vec3& localVelocity, const glm::vec3& localAcceleration, const glm::vec3& normal,
|
||||
const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, bool allowBackface) {
|
||||
// Check if we're hitting the backface in the rotated coordinate space
|
||||
float localIntersectionVelocityZ = localVelocity.z + localAcceleration.z * t;
|
||||
if (!allowBackface && localIntersectionVelocityZ < 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that the point is within all three sides
|
||||
glm::vec3 point = origin + velocity * t + 0.5f * acceleration * t * t;
|
||||
if (glm::dot(normal, glm::cross(point - v1, v0 - v1)) > 0.0f &&
|
||||
glm::dot(normal, glm::cross(v2 - v1, point - v1)) > 0.0f &&
|
||||
glm::dot(normal, glm::cross(point - v0, v2 - v0)) > 0.0f) {
|
||||
minDistance = t;
|
||||
}
|
||||
}
|
||||
|
||||
bool findParabolaTriangleIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, float& parabolicDistance, bool allowBackface) {
|
||||
glm::vec3 normal = glm::cross(v2 - v1, v0 - v1);
|
||||
|
||||
// We transform the parabola and triangle so that the triangle is in the plane z = 0, with v0 at the origin
|
||||
glm::quat inverseRot;
|
||||
// Note: OpenGL view matrix is already the inverse of our camera matrix
|
||||
// if the direction is nearly aligned with the Y axis, then use the X axis for 'up'
|
||||
const float MAX_ABS_Y_COMPONENT = 0.9999991f;
|
||||
if (fabsf(normal.y) > MAX_ABS_Y_COMPONENT) {
|
||||
inverseRot = glm::quat_cast(glm::lookAt(glm::vec3(0.0f), normal, Vectors::UNIT_X));
|
||||
} else {
|
||||
inverseRot = glm::quat_cast(glm::lookAt(glm::vec3(0.0f), normal, Vectors::UNIT_Y));
|
||||
}
|
||||
|
||||
glm::vec3 localOrigin = inverseRot * (origin - v0);
|
||||
glm::vec3 localVelocity = inverseRot * velocity;
|
||||
glm::vec3 localAcceleration = inverseRot * acceleration;
|
||||
|
||||
float minDistance = FLT_MAX;
|
||||
float a = 0.5f * localAcceleration.z;
|
||||
float b = localVelocity.z;
|
||||
float c = localOrigin.z;
|
||||
glm::vec2 possibleDistances = { FLT_MAX, FLT_MAX };
|
||||
if (computeRealQuadraticRoots(a, b, c, possibleDistances)) {
|
||||
checkPossibleParabolicIntersectionWithTriangle(possibleDistances.x, minDistance, origin, velocity, acceleration,
|
||||
localVelocity, localAcceleration, normal, v0, v1, v2, allowBackface);
|
||||
checkPossibleParabolicIntersectionWithTriangle(possibleDistances.y, minDistance, origin, velocity, acceleration,
|
||||
localVelocity, localAcceleration, normal, v0, v1, v2, allowBackface);
|
||||
}
|
||||
if (minDistance < FLT_MAX) {
|
||||
parabolicDistance = minDistance;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void swingTwistDecomposition(const glm::quat& rotation,
|
||||
const glm::vec3& direction,
|
||||
glm::quat& swing,
|
||||
|
|
|
@ -94,6 +94,9 @@ bool findParabolaRectangleIntersection(const glm::vec3& origin, const glm::vec3&
|
|||
bool findParabolaSphereIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
const glm::vec3& center, float radius, float& distance);
|
||||
|
||||
bool findParabolaTriangleIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, float& parabolicDistance, bool allowBackface = false);
|
||||
|
||||
/// \brief decomposes rotation into its components such that: rotation = swing * twist
|
||||
/// \param rotation[in] rotation to decompose
|
||||
/// \param direction[in] normalized axis about which the twist happens (typically original direction before rotation applied)
|
||||
|
@ -118,6 +121,11 @@ inline bool findRayTriangleIntersection(const glm::vec3& origin, const glm::vec3
|
|||
return findRayTriangleIntersection(origin, direction, triangle.v0, triangle.v1, triangle.v2, distance, allowBackface);
|
||||
}
|
||||
|
||||
inline bool findParabolaTriangleIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, const Triangle& triangle, float& parabolicDistance, bool allowBackface = false) {
|
||||
return findParabolaTriangleIntersection(origin, velocity, acceleration, triangle.v0, triangle.v1, triangle.v2, parabolicDistance, allowBackface);
|
||||
}
|
||||
|
||||
int clipTriangleWithPlane(const Triangle& triangle, const Plane& plane, Triangle* clippedTriangles, int maxClippedTriangleCount);
|
||||
int clipTriangleWithPlanes(const Triangle& triangle, const Plane* planes, int planeCount, Triangle* clippedTriangles, int maxClippedTriangleCount);
|
||||
|
||||
|
@ -194,5 +202,9 @@ bool isWithin(float value, float corner, float size);
|
|||
|
||||
void checkPossibleParabolicIntersectionWithZPlane(float t, float& minDistance,
|
||||
const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration, const glm::vec2& corner, const glm::vec2& scale);
|
||||
void checkPossibleParabolicIntersectionWithTriangle(float t, float& minDistance,
|
||||
const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
const glm::vec3& localVelocity, const glm::vec3& localAcceleration, const glm::vec3& normal,
|
||||
const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2, bool allowBackface);
|
||||
|
||||
#endif // hifi_GeometryUtil_h
|
||||
|
|
|
@ -51,6 +51,26 @@ bool TriangleSet::findRayIntersection(const glm::vec3& origin, const glm::vec3&
|
|||
return result;
|
||||
}
|
||||
|
||||
bool TriangleSet::findParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
float& parabolicDistance, BoxFace& face, Triangle& triangle, bool precision, bool allowBackface) {
|
||||
// reset our distance to be the max possible, lower level tests will store best distance here
|
||||
parabolicDistance = FLT_MAX;
|
||||
|
||||
if (!_isBalanced) {
|
||||
balanceOctree();
|
||||
}
|
||||
|
||||
int trianglesTouched = 0;
|
||||
auto result = _triangleOctree.findParabolaIntersection(origin, velocity, acceleration, parabolicDistance, face, triangle, precision, trianglesTouched, allowBackface);
|
||||
|
||||
#if WANT_DEBUGGING
|
||||
if (precision) {
|
||||
qDebug() << "trianglesTouched :" << trianglesTouched << "out of:" << _triangleOctree._population << "_triangles.size:" << _triangles.size();
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
bool TriangleSet::convexHullContains(const glm::vec3& point) const {
|
||||
if (!_bounds.contains(point)) {
|
||||
return false;
|
||||
|
@ -105,7 +125,7 @@ bool TriangleSet::TriangleOctreeCell::findRayIntersectionInternal(const glm::vec
|
|||
if (_bounds.findRayIntersection(origin, direction, boxDistance, face, surfaceNormal)) {
|
||||
|
||||
// if our bounding box intersects at a distance greater than the current known
|
||||
// best distance, and our origin isn't inside the boounds, then we can safely
|
||||
// best distance, and our origin isn't inside the boounds, then we can safely
|
||||
// not check any of our triangles
|
||||
if (boxDistance > bestDistance && !_bounds.contains(origin)) {
|
||||
return false;
|
||||
|
@ -127,6 +147,7 @@ bool TriangleSet::TriangleOctreeCell::findRayIntersectionInternal(const glm::vec
|
|||
}
|
||||
} else {
|
||||
intersectedSomething = true;
|
||||
// FIXME: this needs to set triangle to something or it will carry the previous value
|
||||
distance = boxDistance;
|
||||
}
|
||||
}
|
||||
|
@ -134,6 +155,48 @@ bool TriangleSet::TriangleOctreeCell::findRayIntersectionInternal(const glm::vec
|
|||
return intersectedSomething;
|
||||
}
|
||||
|
||||
bool TriangleSet::TriangleOctreeCell::findParabolaIntersectionInternal(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, float& parabolicDistance, BoxFace& face, Triangle& triangle, bool precision,
|
||||
int& trianglesTouched, bool allowBackface) {
|
||||
|
||||
bool intersectedSomething = false;
|
||||
float boxDistance = parabolicDistance;
|
||||
float bestDistance = parabolicDistance;
|
||||
glm::vec3 surfaceNormal;
|
||||
|
||||
if (_bounds.findParabolaIntersection(origin, velocity, acceleration, boxDistance, face, surfaceNormal)) {
|
||||
|
||||
// if our bounding box intersects at a distance greater than the current known
|
||||
// best distance, and our origin isn't inside the boounds, then we can safely
|
||||
// not check any of our triangles
|
||||
if (boxDistance > bestDistance && !_bounds.contains(origin)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (precision) {
|
||||
for (const auto& triangleIndex : _triangleIndices) {
|
||||
const auto& thisTriangle = _allTriangles[triangleIndex];
|
||||
float thisTriangleDistance;
|
||||
trianglesTouched++;
|
||||
if (findParabolaTriangleIntersection(origin, velocity, acceleration, thisTriangle, thisTriangleDistance, allowBackface)) {
|
||||
if (thisTriangleDistance < bestDistance) {
|
||||
bestDistance = thisTriangleDistance;
|
||||
intersectedSomething = true;
|
||||
triangle = thisTriangle;
|
||||
parabolicDistance = bestDistance;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
intersectedSomething = true;
|
||||
// FIXME: this needs to set triangle to something or it will carry the previous value
|
||||
parabolicDistance = boxDistance;
|
||||
}
|
||||
}
|
||||
|
||||
return intersectedSomething;
|
||||
}
|
||||
|
||||
static const int MAX_DEPTH = 4; // for now
|
||||
static const int MAX_CHILDREN = 8;
|
||||
|
||||
|
@ -267,3 +330,64 @@ bool TriangleSet::TriangleOctreeCell::findRayIntersection(const glm::vec3& origi
|
|||
}
|
||||
return intersects;
|
||||
}
|
||||
|
||||
bool TriangleSet::TriangleOctreeCell::findParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity,
|
||||
const glm::vec3& acceleration, float& parabolicDistance, BoxFace& face, Triangle& triangle, bool precision,
|
||||
int& trianglesTouched, bool allowBackface) {
|
||||
if (_population < 1) {
|
||||
return false; // no triangles below here, so we can't intersect
|
||||
}
|
||||
|
||||
float bestLocalDistance = parabolicDistance;
|
||||
BoxFace bestLocalFace;
|
||||
Triangle bestLocalTriangle;
|
||||
glm::vec3 bestLocalNormal;
|
||||
bool intersects = false;
|
||||
|
||||
// if the ray intersects our bounding box, then continue
|
||||
if (getBounds().findParabolaIntersection(origin, velocity, acceleration, bestLocalDistance, bestLocalFace, bestLocalNormal)) {
|
||||
// if the intersection with our bounding box, is greater than the current best distance (the distance passed in)
|
||||
// then we know that none of our triangles can represent a better intersection and we can return
|
||||
if (bestLocalDistance > parabolicDistance) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bestLocalDistance = parabolicDistance;
|
||||
|
||||
float childDistance = parabolicDistance;
|
||||
BoxFace childFace;
|
||||
Triangle childTriangle;
|
||||
|
||||
// if we're not yet at the max depth, then check which child the triangle fits in
|
||||
if (_depth < MAX_DEPTH) {
|
||||
for (auto& child : _children) {
|
||||
// check each child, if there's an intersection, it will return some distance that we need
|
||||
// to compare against the other results, because there might be multiple intersections and
|
||||
// we will always choose the best (shortest) intersection
|
||||
if (child.second.findParabolaIntersection(origin, velocity, acceleration, childDistance, childFace, childTriangle, precision, trianglesTouched)) {
|
||||
if (childDistance < bestLocalDistance) {
|
||||
bestLocalDistance = childDistance;
|
||||
bestLocalFace = childFace;
|
||||
bestLocalTriangle = childTriangle;
|
||||
intersects = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// also check our local triangle set
|
||||
if (findParabolaIntersectionInternal(origin, velocity, acceleration, childDistance, childFace, childTriangle, precision, trianglesTouched, allowBackface)) {
|
||||
if (childDistance < bestLocalDistance) {
|
||||
bestLocalDistance = childDistance;
|
||||
bestLocalFace = childFace;
|
||||
bestLocalTriangle = childTriangle;
|
||||
intersects = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (intersects) {
|
||||
parabolicDistance = bestLocalDistance;
|
||||
face = bestLocalFace;
|
||||
triangle = bestLocalTriangle;
|
||||
}
|
||||
return intersects;
|
||||
}
|
|
@ -31,6 +31,9 @@ class TriangleSet {
|
|||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, Triangle& triangle, bool precision, int& trianglesTouched,
|
||||
bool allowBackface = false);
|
||||
bool findParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
float& parabolicDistance, BoxFace& face, Triangle& triangle, bool precision, int& trianglesTouched,
|
||||
bool allowBackface = false);
|
||||
|
||||
const AABox& getBounds() const { return _bounds; }
|
||||
|
||||
|
@ -43,6 +46,9 @@ class TriangleSet {
|
|||
bool findRayIntersectionInternal(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, Triangle& triangle, bool precision, int& trianglesTouched,
|
||||
bool allowBackface = false);
|
||||
bool findParabolaIntersectionInternal(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
float& parabolicDistance, BoxFace& face, Triangle& triangle, bool precision, int& trianglesTouched,
|
||||
bool allowBackface = false);
|
||||
|
||||
std::vector<Triangle>& _allTriangles;
|
||||
std::map<AABox::OctreeChild, TriangleOctreeCell> _children;
|
||||
|
@ -65,6 +71,8 @@ public:
|
|||
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, Triangle& triangle, bool precision, bool allowBackface = false);
|
||||
bool findParabolaIntersection(const glm::vec3& origin, const glm::vec3& velocity, const glm::vec3& acceleration,
|
||||
float& parabolicDistance, BoxFace& face, Triangle& triangle, bool precision, bool allowBackface = false);
|
||||
|
||||
void balanceOctree();
|
||||
|
||||
|
@ -72,12 +80,6 @@ public:
|
|||
size_t size() const { return _triangles.size(); }
|
||||
void clear();
|
||||
|
||||
// Determine if the given ray (origin/direction) in model space intersects with any triangles in the set. If an
|
||||
// intersection occurs, the distance and surface normal will be provided.
|
||||
// note: this might side-effect internal structures
|
||||
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
float& distance, BoxFace& face, Triangle& triangle, bool precision, int& trianglesTouched);
|
||||
|
||||
// Determine if a point is "inside" all the triangles of a convex hull. It is the responsibility of the caller to
|
||||
// determine that the triangle set is indeed a convex hull. If the triangles added to this set are not in fact a
|
||||
// convex hull, the result of this method is meaningless and undetermined.
|
||||
|
|
Loading…
Reference in a new issue