mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 14:58:03 +02:00
Merge pull request #7205 from AndrewMeadows/cleanup2
cleanup ViewFrustum method names (correct branch)
This commit is contained in:
commit
2f490a0684
30 changed files with 1949 additions and 650 deletions
|
@ -153,7 +153,7 @@ bool OctreeQueryNode::updateCurrentViewFrustum() {
|
||||||
newestViewFrustum.setPosition(getCameraPosition());
|
newestViewFrustum.setPosition(getCameraPosition());
|
||||||
newestViewFrustum.setOrientation(getCameraOrientation());
|
newestViewFrustum.setOrientation(getCameraOrientation());
|
||||||
|
|
||||||
newestViewFrustum.setKeyholeRadius(getKeyholeRadius());
|
newestViewFrustum.setCenterRadius(getCameraCenterRadius());
|
||||||
|
|
||||||
// Also make sure it's got the correct lens details from the camera
|
// Also make sure it's got the correct lens details from the camera
|
||||||
float originalFOV = getCameraFov();
|
float originalFOV = getCameraFov();
|
||||||
|
|
|
@ -3387,7 +3387,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
|
||||||
_octreeQuery.setCameraNearClip(_viewFrustum.getNearClip());
|
_octreeQuery.setCameraNearClip(_viewFrustum.getNearClip());
|
||||||
_octreeQuery.setCameraFarClip(_viewFrustum.getFarClip());
|
_octreeQuery.setCameraFarClip(_viewFrustum.getFarClip());
|
||||||
_octreeQuery.setCameraEyeOffsetPosition(glm::vec3());
|
_octreeQuery.setCameraEyeOffsetPosition(glm::vec3());
|
||||||
_octreeQuery.setKeyholeRadius(_viewFrustum.getKeyholeRadius());
|
_octreeQuery.setCameraCenterRadius(_viewFrustum.getCenterRadius());
|
||||||
auto lodManager = DependencyManager::get<LODManager>();
|
auto lodManager = DependencyManager::get<LODManager>();
|
||||||
_octreeQuery.setOctreeSizeScale(lodManager->getOctreeSizeScale());
|
_octreeQuery.setOctreeSizeScale(lodManager->getOctreeSizeScale());
|
||||||
_octreeQuery.setBoundaryLevelAdjust(lodManager->getBoundaryLevelAdjust());
|
_octreeQuery.setBoundaryLevelAdjust(lodManager->getBoundaryLevelAdjust());
|
||||||
|
@ -3423,9 +3423,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
|
||||||
rootDetails.y * TREE_SCALE,
|
rootDetails.y * TREE_SCALE,
|
||||||
rootDetails.z * TREE_SCALE) - glm::vec3(HALF_TREE_SCALE),
|
rootDetails.z * TREE_SCALE) - glm::vec3(HALF_TREE_SCALE),
|
||||||
rootDetails.s * TREE_SCALE);
|
rootDetails.s * TREE_SCALE);
|
||||||
ViewFrustum::location serverFrustumLocation = _viewFrustum.computeCubeViewLocation(serverBounds);
|
if (_viewFrustum.cubeIntersectsKeyhole(serverBounds)) {
|
||||||
|
|
||||||
if (serverFrustumLocation != ViewFrustum::OUTSIDE) {
|
|
||||||
inViewServers++;
|
inViewServers++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3491,12 +3489,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
|
||||||
rootDetails.s * TREE_SCALE);
|
rootDetails.s * TREE_SCALE);
|
||||||
|
|
||||||
|
|
||||||
ViewFrustum::location serverFrustumLocation = _viewFrustum.computeCubeViewLocation(serverBounds);
|
inView = _viewFrustum.cubeIntersectsKeyhole(serverBounds);
|
||||||
if (serverFrustumLocation != ViewFrustum::OUTSIDE) {
|
|
||||||
inView = true;
|
|
||||||
} else {
|
|
||||||
inView = false;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (wantExtraDebugging) {
|
if (wantExtraDebugging) {
|
||||||
qCDebug(interfaceapp) << "Jurisdiction without RootCode for node " << *node << ". That's unusual!";
|
qCDebug(interfaceapp) << "Jurisdiction without RootCode for node " << *node << ". That's unusual!";
|
||||||
|
|
|
@ -188,15 +188,14 @@ void Avatar::simulate(float deltaTime) {
|
||||||
|
|
||||||
// simple frustum check
|
// simple frustum check
|
||||||
float boundingRadius = getBoundingRadius();
|
float boundingRadius = getBoundingRadius();
|
||||||
bool inViewFrustum = qApp->getViewFrustum()->computeSphereViewLocation(getPosition(), boundingRadius) !=
|
bool inView = qApp->getViewFrustum()->sphereIntersectsFrustum(getPosition(), boundingRadius);
|
||||||
ViewFrustum::OUTSIDE;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("hand");
|
PerformanceTimer perfTimer("hand");
|
||||||
getHand()->simulate(deltaTime, false);
|
getHand()->simulate(deltaTime, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_shouldAnimate && !_shouldSkipRender && inViewFrustum) {
|
if (_shouldAnimate && !_shouldSkipRender && inView) {
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("skeleton");
|
PerformanceTimer perfTimer("skeleton");
|
||||||
_skeletonModel.getRig()->copyJointsFromJointData(_jointData);
|
_skeletonModel.getRig()->copyJointsFromJointData(_jointData);
|
||||||
|
@ -401,7 +400,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
|
||||||
frustum = qApp->getDisplayViewFrustum();
|
frustum = qApp->getDisplayViewFrustum();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frustum->computeSphereViewLocation(getPosition(), boundingRadius) == ViewFrustum::OUTSIDE) {
|
if (frustum->sphereIntersectsFrustum(getPosition(), boundingRadius)) {
|
||||||
endRender();
|
endRender();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -517,7 +516,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
|
||||||
auto& frustum = *renderArgs->_viewFrustum;
|
auto& frustum = *renderArgs->_viewFrustum;
|
||||||
auto textPosition = getDisplayNamePosition();
|
auto textPosition = getDisplayNamePosition();
|
||||||
|
|
||||||
if (frustum.computePointFrustumLocation(textPosition) == ViewFrustum::INSIDE) {
|
if (frustum.pointIntersectsFrustum(textPosition)) {
|
||||||
renderDisplayName(batch, frustum, textPosition);
|
renderDisplayName(batch, frustum, textPosition);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -670,10 +669,10 @@ glm::vec3 Avatar::getDisplayNamePosition() const {
|
||||||
return namePosition;
|
return namePosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, const glm::vec3& textPosition) const {
|
Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& view, const glm::vec3& textPosition) const {
|
||||||
Q_ASSERT_X(frustum.computePointFrustumLocation(textPosition) == ViewFrustum::INSIDE,
|
Q_ASSERT_X(view.pointIntersectsFrustum(textPosition),
|
||||||
"Avatar::calculateDisplayNameTransform", "Text not in viewfrustum.");
|
"Avatar::calculateDisplayNameTransform", "Text not in viewfrustum.");
|
||||||
glm::vec3 toFrustum = frustum.getPosition() - textPosition;
|
glm::vec3 toFrustum = view.getPosition() - textPosition;
|
||||||
|
|
||||||
// Compute orientation
|
// Compute orientation
|
||||||
// If x and z are 0, atan(x, z) adais undefined, so default to 0 degrees
|
// If x and z are 0, atan(x, z) adais undefined, so default to 0 degrees
|
||||||
|
@ -695,7 +694,7 @@ Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, cons
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, const glm::vec3& textPosition) const {
|
void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const glm::vec3& textPosition) const {
|
||||||
PROFILE_RANGE_BATCH(batch, __FUNCTION__);
|
PROFILE_RANGE_BATCH(batch, __FUNCTION__);
|
||||||
|
|
||||||
bool shouldShowReceiveStats = DependencyManager::get<AvatarManager>()->shouldShowReceiveStats() && !isMyAvatar();
|
bool shouldShowReceiveStats = DependencyManager::get<AvatarManager>()->shouldShowReceiveStats() && !isMyAvatar();
|
||||||
|
@ -703,7 +702,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, co
|
||||||
// If we have nothing to draw, or it's totally transparent, or it's too close or behind the camera, return
|
// If we have nothing to draw, or it's totally transparent, or it's too close or behind the camera, return
|
||||||
static const float CLIP_DISTANCE = 0.2f;
|
static const float CLIP_DISTANCE = 0.2f;
|
||||||
if ((_displayName.isEmpty() && !shouldShowReceiveStats) || _displayNameAlpha == 0.0f
|
if ((_displayName.isEmpty() && !shouldShowReceiveStats) || _displayNameAlpha == 0.0f
|
||||||
|| (glm::dot(frustum.getDirection(), getDisplayNamePosition() - frustum.getPosition()) <= CLIP_DISTANCE)) {
|
|| (glm::dot(view.getDirection(), getDisplayNamePosition() - view.getPosition()) <= CLIP_DISTANCE)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto renderer = textRenderer(DISPLAYNAME);
|
auto renderer = textRenderer(DISPLAYNAME);
|
||||||
|
@ -744,7 +743,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, co
|
||||||
(_displayNameAlpha / DISPLAYNAME_ALPHA) * DISPLAYNAME_BACKGROUND_ALPHA);
|
(_displayNameAlpha / DISPLAYNAME_ALPHA) * DISPLAYNAME_BACKGROUND_ALPHA);
|
||||||
|
|
||||||
// Compute display name transform
|
// Compute display name transform
|
||||||
auto textTransform = calculateDisplayNameTransform(frustum, textPosition);
|
auto textTransform = calculateDisplayNameTransform(view, textPosition);
|
||||||
// Test on extent above insures abs(height) > 0.0f
|
// Test on extent above insures abs(height) > 0.0f
|
||||||
textTransform.postScale(1.0f / height);
|
textTransform.postScale(1.0f / height);
|
||||||
batch.setModelTransform(textTransform);
|
batch.setModelTransform(textTransform);
|
||||||
|
|
|
@ -231,8 +231,8 @@ protected:
|
||||||
float getPelvisFloatingHeight() const;
|
float getPelvisFloatingHeight() const;
|
||||||
glm::vec3 getDisplayNamePosition() const;
|
glm::vec3 getDisplayNamePosition() const;
|
||||||
|
|
||||||
Transform calculateDisplayNameTransform(const ViewFrustum& frustum, const glm::vec3& textPosition) const;
|
Transform calculateDisplayNameTransform(const ViewFrustum& view, const glm::vec3& textPosition) const;
|
||||||
void renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, const glm::vec3& textPosition) const;
|
void renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const glm::vec3& textPosition) const;
|
||||||
virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel = 0.0f);
|
virtual void renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, float glowLevel = 0.0f);
|
||||||
virtual bool shouldRenderHead(const RenderArgs* renderArgs) const;
|
virtual bool shouldRenderHead(const RenderArgs* renderArgs) const;
|
||||||
virtual void fixupModelsInScene();
|
virtual void fixupModelsInScene();
|
||||||
|
|
|
@ -304,15 +304,13 @@ OctreeElement::AppendState EntityTreeElement::appendElementData(OctreePacketData
|
||||||
// frustum culling on rendering.
|
// frustum culling on rendering.
|
||||||
bool success;
|
bool success;
|
||||||
AACube entityCube = entity->getQueryAACube(success);
|
AACube entityCube = entity->getQueryAACube(success);
|
||||||
if (!success || params.viewFrustum->computeCubeViewLocation(entityCube) == ViewFrustum::OUTSIDE) {
|
if (!success || !params.viewFrustum->cubeIntersectsKeyhole(entityCube)) {
|
||||||
includeThisEntity = false; // out of view, don't include it
|
includeThisEntity = false; // out of view, don't include it
|
||||||
}
|
} else {
|
||||||
|
// Check the size of the entity, it's possible that a "too small to see" entity is included in a
|
||||||
// Now check the size of the entity, it's possible that a "too small to see" entity is included in a
|
// larger octree cell because of its position (for example if it crosses the boundary of a cell it
|
||||||
// larger octree cell because of its position (for example if it crosses the boundary of a cell it
|
// pops to the next higher cell. So we want to check to see that the entity is large enough to be seen
|
||||||
// pops to the next higher cell. So we want to check to see that the entity is large enough to be seen
|
// before we consider including it.
|
||||||
// before we consider including it.
|
|
||||||
if (includeThisEntity) {
|
|
||||||
success = true;
|
success = true;
|
||||||
// we can't cull a parent-entity by its dimensions because the child may be larger. we need to
|
// we can't cull a parent-entity by its dimensions because the child may be larger. we need to
|
||||||
// avoid sending details about a child but not the parent. the parent's queryAACube should have
|
// avoid sending details about a child but not the parent. the parent's queryAACube should have
|
||||||
|
|
|
@ -937,7 +937,7 @@ int Octree::encodeTreeBitstream(OctreeElementPointer element,
|
||||||
params.stats->traversed(element);
|
params.stats->traversed(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewFrustum::location parentLocationThisView = ViewFrustum::INTERSECT; // assume parent is in view, but not fully
|
ViewFrustum::intersection parentLocationThisView = ViewFrustum::INTERSECT; // assume parent is in view, but not fully
|
||||||
|
|
||||||
int childBytesWritten = encodeTreeBitstreamRecursion(element, packetData, bag, params,
|
int childBytesWritten = encodeTreeBitstreamRecursion(element, packetData, bag, params,
|
||||||
currentEncodeLevel, parentLocationThisView);
|
currentEncodeLevel, parentLocationThisView);
|
||||||
|
@ -974,7 +974,7 @@ int Octree::encodeTreeBitstream(OctreeElementPointer element,
|
||||||
int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element,
|
int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element,
|
||||||
OctreePacketData* packetData, OctreeElementBag& bag,
|
OctreePacketData* packetData, OctreeElementBag& bag,
|
||||||
EncodeBitstreamParams& params, int& currentEncodeLevel,
|
EncodeBitstreamParams& params, int& currentEncodeLevel,
|
||||||
const ViewFrustum::location& parentLocationThisView) const {
|
const ViewFrustum::intersection& parentLocationThisView) const {
|
||||||
|
|
||||||
|
|
||||||
const bool wantDebug = false;
|
const bool wantDebug = false;
|
||||||
|
@ -1013,7 +1013,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewFrustum::location nodeLocationThisView = ViewFrustum::INSIDE; // assume we're inside
|
ViewFrustum::intersection nodeLocationThisView = ViewFrustum::INSIDE; // assume we're inside
|
||||||
|
|
||||||
// caller can pass NULL as viewFrustum if they want everything
|
// caller can pass NULL as viewFrustum if they want everything
|
||||||
if (params.viewFrustum) {
|
if (params.viewFrustum) {
|
||||||
|
@ -1034,7 +1034,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element,
|
||||||
// if we are INSIDE, INTERSECT, or OUTSIDE
|
// if we are INSIDE, INTERSECT, or OUTSIDE
|
||||||
if (parentLocationThisView != ViewFrustum::INSIDE) {
|
if (parentLocationThisView != ViewFrustum::INSIDE) {
|
||||||
assert(parentLocationThisView != ViewFrustum::OUTSIDE); // we shouldn't be here if our parent was OUTSIDE!
|
assert(parentLocationThisView != ViewFrustum::OUTSIDE); // we shouldn't be here if our parent was OUTSIDE!
|
||||||
nodeLocationThisView = element->computeViewLocation(*params.viewFrustum);
|
nodeLocationThisView = element->computeViewIntersection(*params.viewFrustum);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're at a element that is out of view, then we can return, because no nodes below us will be in view!
|
// If we're at a element that is out of view, then we can return, because no nodes below us will be in view!
|
||||||
|
@ -1053,7 +1053,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element,
|
||||||
bool wasInView = false;
|
bool wasInView = false;
|
||||||
|
|
||||||
if (params.deltaViewFrustum && params.lastViewFrustum) {
|
if (params.deltaViewFrustum && params.lastViewFrustum) {
|
||||||
ViewFrustum::location location = element->computeViewLocation(*params.lastViewFrustum);
|
ViewFrustum::intersection location = element->computeViewIntersection(*params.lastViewFrustum);
|
||||||
|
|
||||||
// If we're a leaf, then either intersect or inside is considered "formerly in view"
|
// If we're a leaf, then either intersect or inside is considered "formerly in view"
|
||||||
if (element->isLeaf()) {
|
if (element->isLeaf()) {
|
||||||
|
@ -1237,7 +1237,7 @@ int Octree::encodeTreeBitstreamRecursion(OctreeElementPointer element,
|
||||||
bool childWasInView = false;
|
bool childWasInView = false;
|
||||||
|
|
||||||
if (childElement && params.deltaViewFrustum && params.lastViewFrustum) {
|
if (childElement && params.deltaViewFrustum && params.lastViewFrustum) {
|
||||||
ViewFrustum::location location = childElement->computeViewLocation(*params.lastViewFrustum);
|
ViewFrustum::intersection location = childElement->computeViewIntersection(*params.lastViewFrustum);
|
||||||
|
|
||||||
// If we're a leaf, then either intersect or inside is considered "formerly in view"
|
// If we're a leaf, then either intersect or inside is considered "formerly in view"
|
||||||
if (childElement->isLeaf()) {
|
if (childElement->isLeaf()) {
|
||||||
|
|
|
@ -367,7 +367,7 @@ protected:
|
||||||
int encodeTreeBitstreamRecursion(OctreeElementPointer element,
|
int encodeTreeBitstreamRecursion(OctreeElementPointer element,
|
||||||
OctreePacketData* packetData, OctreeElementBag& bag,
|
OctreePacketData* packetData, OctreeElementBag& bag,
|
||||||
EncodeBitstreamParams& params, int& currentEncodeLevel,
|
EncodeBitstreamParams& params, int& currentEncodeLevel,
|
||||||
const ViewFrustum::location& parentLocationThisView) const;
|
const ViewFrustum::intersection& parentLocationThisView) const;
|
||||||
|
|
||||||
static bool countOctreeElementsOperation(OctreeElementPointer element, void* extraData);
|
static bool countOctreeElementsOperation(OctreeElementPointer element, void* extraData);
|
||||||
|
|
||||||
|
|
|
@ -458,8 +458,8 @@ float OctreeElement::getEnclosingRadius() const {
|
||||||
return getScale() * sqrtf(3.0f) / 2.0f;
|
return getScale() * sqrtf(3.0f) / 2.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewFrustum::location OctreeElement::computeViewLocation(const ViewFrustum& viewFrustum) const {
|
ViewFrustum::intersection OctreeElement::computeViewIntersection(const ViewFrustum& viewFrustum) const {
|
||||||
return viewFrustum.computeCubeViewLocation(_cube);
|
return viewFrustum.calculateCubeKeyholeIntersection(_cube);
|
||||||
}
|
}
|
||||||
|
|
||||||
// There are two types of nodes for which we want to "render"
|
// There are two types of nodes for which we want to "render"
|
||||||
|
|
|
@ -134,8 +134,8 @@ public:
|
||||||
int getLevel() const { return numberOfThreeBitSectionsInCode(getOctalCode()) + 1; }
|
int getLevel() const { return numberOfThreeBitSectionsInCode(getOctalCode()) + 1; }
|
||||||
|
|
||||||
float getEnclosingRadius() const;
|
float getEnclosingRadius() const;
|
||||||
bool isInView(const ViewFrustum& viewFrustum) const { return computeViewLocation(viewFrustum) != ViewFrustum::OUTSIDE; }
|
bool isInView(const ViewFrustum& viewFrustum) const { return computeViewIntersection(viewFrustum) != ViewFrustum::OUTSIDE; }
|
||||||
ViewFrustum::location computeViewLocation(const ViewFrustum& viewFrustum) const;
|
ViewFrustum::intersection computeViewIntersection(const ViewFrustum& viewFrustum) const;
|
||||||
float distanceToCamera(const ViewFrustum& viewFrustum) const;
|
float distanceToCamera(const ViewFrustum& viewFrustum) const;
|
||||||
float furthestDistanceToCamera(const ViewFrustum& viewFrustum) const;
|
float furthestDistanceToCamera(const ViewFrustum& viewFrustum) const;
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ void OctreeHeadlessViewer::queryOctree() {
|
||||||
_octreeQuery.setCameraNearClip(_viewFrustum.getNearClip());
|
_octreeQuery.setCameraNearClip(_viewFrustum.getNearClip());
|
||||||
_octreeQuery.setCameraFarClip(_viewFrustum.getFarClip());
|
_octreeQuery.setCameraFarClip(_viewFrustum.getFarClip());
|
||||||
_octreeQuery.setCameraEyeOffsetPosition(glm::vec3());
|
_octreeQuery.setCameraEyeOffsetPosition(glm::vec3());
|
||||||
_octreeQuery.setKeyholeRadius(_viewFrustum.getKeyholeRadius());
|
_octreeQuery.setCameraCenterRadius(_viewFrustum.getCenterRadius());
|
||||||
_octreeQuery.setOctreeSizeScale(_voxelSizeScale);
|
_octreeQuery.setOctreeSizeScale(_voxelSizeScale);
|
||||||
_octreeQuery.setBoundaryLevelAdjust(_boundaryLevelAdjust);
|
_octreeQuery.setBoundaryLevelAdjust(_boundaryLevelAdjust);
|
||||||
|
|
||||||
|
@ -91,9 +91,7 @@ void OctreeHeadlessViewer::queryOctree() {
|
||||||
|
|
||||||
if (foundRootDetails) {
|
if (foundRootDetails) {
|
||||||
AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
|
AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
|
||||||
ViewFrustum::location serverFrustumLocation = _viewFrustum.computeCubeViewLocation(serverBounds);
|
if ((bool)(_viewFrustum.calculateCubeKeyholeIntersection(serverBounds))) {
|
||||||
|
|
||||||
if (serverFrustumLocation != ViewFrustum::OUTSIDE) {
|
|
||||||
inViewServers++;
|
inViewServers++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,13 +162,7 @@ void OctreeHeadlessViewer::queryOctree() {
|
||||||
|
|
||||||
if (foundRootDetails) {
|
if (foundRootDetails) {
|
||||||
AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
|
AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s);
|
||||||
|
inView = (bool)(_viewFrustum.calculateCubeKeyholeIntersection(serverBounds));
|
||||||
ViewFrustum::location serverFrustumLocation = _viewFrustum.computeCubeViewLocation(serverBounds);
|
|
||||||
if (serverFrustumLocation != ViewFrustum::OUTSIDE) {
|
|
||||||
inView = true;
|
|
||||||
} else {
|
|
||||||
inView = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inView) {
|
if (inView) {
|
||||||
|
|
|
@ -46,7 +46,7 @@ public slots:
|
||||||
// setters for camera attributes
|
// setters for camera attributes
|
||||||
void setPosition(const glm::vec3& position) { _viewFrustum.setPosition(position); }
|
void setPosition(const glm::vec3& position) { _viewFrustum.setPosition(position); }
|
||||||
void setOrientation(const glm::quat& orientation) { _viewFrustum.setOrientation(orientation); }
|
void setOrientation(const glm::quat& orientation) { _viewFrustum.setOrientation(orientation); }
|
||||||
void setKeyholeRadius(float keyholdRadius) { _viewFrustum.setKeyholeRadius(keyholdRadius); }
|
void setCenterRadius(float radius) { _viewFrustum.setCenterRadius(radius); }
|
||||||
|
|
||||||
// setters for LOD and PPS
|
// setters for LOD and PPS
|
||||||
void setVoxelSizeScale(float sizeScale) { _voxelSizeScale = sizeScale; }
|
void setVoxelSizeScale(float sizeScale) { _voxelSizeScale = sizeScale; }
|
||||||
|
|
|
@ -64,8 +64,8 @@ int OctreeQuery::getBroadcastData(unsigned char* destinationBuffer) {
|
||||||
memcpy(destinationBuffer, &_boundaryLevelAdjust, sizeof(_boundaryLevelAdjust));
|
memcpy(destinationBuffer, &_boundaryLevelAdjust, sizeof(_boundaryLevelAdjust));
|
||||||
destinationBuffer += sizeof(_boundaryLevelAdjust);
|
destinationBuffer += sizeof(_boundaryLevelAdjust);
|
||||||
|
|
||||||
memcpy(destinationBuffer, &_keyholeRadius, sizeof(_keyholeRadius));
|
memcpy(destinationBuffer, &_cameraCenterRadius, sizeof(_cameraCenterRadius));
|
||||||
destinationBuffer += sizeof(_keyholeRadius);
|
destinationBuffer += sizeof(_cameraCenterRadius);
|
||||||
|
|
||||||
return destinationBuffer - bufferStart;
|
return destinationBuffer - bufferStart;
|
||||||
}
|
}
|
||||||
|
@ -109,9 +109,9 @@ int OctreeQuery::parseData(ReceivedMessage& message) {
|
||||||
|
|
||||||
auto bytesRead = sourceBuffer - startPosition;
|
auto bytesRead = sourceBuffer - startPosition;
|
||||||
auto bytesLeft = message.getSize() - bytesRead;
|
auto bytesLeft = message.getSize() - bytesRead;
|
||||||
if (bytesLeft >= (int)sizeof(_keyholeRadius)) {
|
if (bytesLeft >= (int)sizeof(_cameraCenterRadius)) {
|
||||||
memcpy(&_keyholeRadius, sourceBuffer, sizeof(_keyholeRadius));
|
memcpy(&_cameraCenterRadius, sourceBuffer, sizeof(_cameraCenterRadius));
|
||||||
sourceBuffer += sizeof(_keyholeRadius);
|
sourceBuffer += sizeof(_cameraCenterRadius);
|
||||||
}
|
}
|
||||||
return sourceBuffer - startPosition;
|
return sourceBuffer - startPosition;
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ public:
|
||||||
float getCameraNearClip() const { return _cameraNearClip; }
|
float getCameraNearClip() const { return _cameraNearClip; }
|
||||||
float getCameraFarClip() const { return _cameraFarClip; }
|
float getCameraFarClip() const { return _cameraFarClip; }
|
||||||
const glm::vec3& getCameraEyeOffsetPosition() const { return _cameraEyeOffsetPosition; }
|
const glm::vec3& getCameraEyeOffsetPosition() const { return _cameraEyeOffsetPosition; }
|
||||||
float getKeyholeRadius() const { return _keyholeRadius; }
|
float getCameraCenterRadius() const { return _cameraCenterRadius; }
|
||||||
|
|
||||||
glm::vec3 calculateCameraDirection() const;
|
glm::vec3 calculateCameraDirection() const;
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ public:
|
||||||
void setCameraNearClip(float nearClip) { _cameraNearClip = nearClip; }
|
void setCameraNearClip(float nearClip) { _cameraNearClip = nearClip; }
|
||||||
void setCameraFarClip(float farClip) { _cameraFarClip = farClip; }
|
void setCameraFarClip(float farClip) { _cameraFarClip = farClip; }
|
||||||
void setCameraEyeOffsetPosition(const glm::vec3& eyeOffsetPosition) { _cameraEyeOffsetPosition = eyeOffsetPosition; }
|
void setCameraEyeOffsetPosition(const glm::vec3& eyeOffsetPosition) { _cameraEyeOffsetPosition = eyeOffsetPosition; }
|
||||||
void setKeyholeRadius(float keyholeRadius) { _keyholeRadius = keyholeRadius; }
|
void setCameraCenterRadius(float radius) { _cameraCenterRadius = radius; }
|
||||||
|
|
||||||
// related to Octree Sending strategies
|
// related to Octree Sending strategies
|
||||||
int getMaxQueryPacketsPerSecond() const { return _maxQueryPPS; }
|
int getMaxQueryPacketsPerSecond() const { return _maxQueryPPS; }
|
||||||
|
@ -90,7 +90,7 @@ protected:
|
||||||
float _cameraAspectRatio = 1.0f;
|
float _cameraAspectRatio = 1.0f;
|
||||||
float _cameraNearClip = 0.0f;
|
float _cameraNearClip = 0.0f;
|
||||||
float _cameraFarClip = 0.0f;
|
float _cameraFarClip = 0.0f;
|
||||||
float _keyholeRadius { 0.0f };
|
float _cameraCenterRadius { 0.0f };
|
||||||
glm::vec3 _cameraEyeOffsetPosition = glm::vec3(0.0f);
|
glm::vec3 _cameraEyeOffsetPosition = glm::vec3(0.0f);
|
||||||
|
|
||||||
// octree server sending items
|
// octree server sending items
|
||||||
|
|
|
@ -115,10 +115,6 @@ void ViewFrustum::calculate() {
|
||||||
|
|
||||||
// Our ModelViewProjection : multiplication of our 3 matrices (note: model is identity, so we can drop it)
|
// Our ModelViewProjection : multiplication of our 3 matrices (note: model is identity, so we can drop it)
|
||||||
_ourModelViewProjectionMatrix = _projection * view; // Remember, matrix multiplication is the other way around
|
_ourModelViewProjectionMatrix = _projection * view; // Remember, matrix multiplication is the other way around
|
||||||
|
|
||||||
// Set up our keyhole bounding box...
|
|
||||||
glm::vec3 corner = _position - _keyholeRadius;
|
|
||||||
_keyholeBoundingCube = AACube(corner,(_keyholeRadius * 2.0f));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//enum { TOP_PLANE = 0, BOTTOM_PLANE, LEFT_PLANE, RIGHT_PLANE, NEAR_PLANE, FAR_PLANE };
|
//enum { TOP_PLANE = 0, BOTTOM_PLANE, LEFT_PLANE, RIGHT_PLANE, NEAR_PLANE, FAR_PLANE };
|
||||||
|
@ -134,219 +130,129 @@ const char* ViewFrustum::debugPlaneName (int plane) const {
|
||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewFrustum::location ViewFrustum::pointInKeyhole(const glm::vec3& point) const {
|
ViewFrustum::intersection ViewFrustum::calculateCubeFrustumIntersection(const AACube& cube) const {
|
||||||
|
// only check against frustum
|
||||||
ViewFrustum::location result = INTERSECT;
|
ViewFrustum::intersection result = INSIDE;
|
||||||
|
for(int i=0; i < 6; i++) {
|
||||||
float distance = glm::distance(point, _position);
|
const glm::vec3& normal = _planes[i].getNormal();
|
||||||
if (distance > _keyholeRadius) {
|
// check distance to farthest cube point
|
||||||
result = OUTSIDE;
|
if ( _planes[i].distance(cube.getFarthestVertex(normal)) < 0.0f) {
|
||||||
} else if (distance < _keyholeRadius) {
|
return OUTSIDE;
|
||||||
result = INSIDE;
|
} else {
|
||||||
}
|
// check distance to nearest cube point
|
||||||
|
if (_planes[i].distance(cube.getNearestVertex(normal)) < 0.0f) {
|
||||||
return result;
|
// cube straddles the plane
|
||||||
}
|
result = INTERSECT;
|
||||||
|
|
||||||
// To determine if two spheres intersect, simply calculate the distance between the centers of the two spheres.
|
|
||||||
// If the distance is greater than the sum of the two sphere radii, they don’t intersect. Otherwise they intersect.
|
|
||||||
// If the distance plus the radius of sphere A is less than the radius of sphere B then, sphere A is inside of sphere B
|
|
||||||
ViewFrustum::location ViewFrustum::sphereInKeyhole(const glm::vec3& center, float radius) const {
|
|
||||||
ViewFrustum::location result = INTERSECT;
|
|
||||||
|
|
||||||
float distance = glm::distance(center, _position);
|
|
||||||
if (distance > (radius + _keyholeRadius)) {
|
|
||||||
result = OUTSIDE;
|
|
||||||
} else if ((distance + radius) < _keyholeRadius) {
|
|
||||||
result = INSIDE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// A box is inside a sphere if all of its corners are inside the sphere
|
|
||||||
// A box intersects a sphere if any of its edges (as rays) interesect the sphere
|
|
||||||
// A box is outside a sphere if none of its edges (as rays) interesect the sphere
|
|
||||||
ViewFrustum::location ViewFrustum::cubeInKeyhole(const AACube& cube) const {
|
|
||||||
|
|
||||||
// First check to see if the cube is in the bounding cube for the sphere, if it's not, then we can short circuit
|
|
||||||
// this and not check with sphere penetration which is more expensive
|
|
||||||
if (!_keyholeBoundingCube.contains(cube)) {
|
|
||||||
return OUTSIDE;
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 penetration;
|
|
||||||
bool intersects = cube.findSpherePenetration(_position, _keyholeRadius, penetration);
|
|
||||||
|
|
||||||
ViewFrustum::location result = OUTSIDE;
|
|
||||||
|
|
||||||
// if the cube intersects the sphere, then it may also be inside... calculate further
|
|
||||||
if (intersects) {
|
|
||||||
result = INTERSECT;
|
|
||||||
|
|
||||||
// test all the corners, if they are all inside the sphere, the entire cube is in the sphere
|
|
||||||
bool allPointsInside = true; // assume the best
|
|
||||||
for (int v = BOTTOM_LEFT_NEAR; v < TOP_LEFT_FAR; v++) {
|
|
||||||
glm::vec3 vertex = cube.getVertex((BoxVertex)v);
|
|
||||||
if (!pointInKeyhole(vertex)) {
|
|
||||||
allPointsInside = false;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allPointsInside) {
|
|
||||||
result = INSIDE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A box is inside a sphere if all of its corners are inside the sphere
|
const float HALF_SQRT_THREE = 0.8660254f;
|
||||||
// A box intersects a sphere if any of its edges (as rays) interesect the sphere
|
|
||||||
// A box is outside a sphere if none of its edges (as rays) interesect the sphere
|
|
||||||
ViewFrustum::location ViewFrustum::boxInKeyhole(const AABox& box) const {
|
|
||||||
|
|
||||||
// First check to see if the box is in the bounding box for the sphere, if it's not, then we can short circuit
|
ViewFrustum::intersection ViewFrustum::calculateCubeKeyholeIntersection(const AACube& cube) const {
|
||||||
// this and not check with sphere penetration which is more expensive
|
// check against centeral sphere
|
||||||
if (!_keyholeBoundingCube.contains(box)) {
|
ViewFrustum::intersection sphereResult = INTERSECT;
|
||||||
return OUTSIDE;
|
glm::vec3 cubeOffset = cube.calcCenter() - _position;
|
||||||
|
float distance = glm::length(cubeOffset);
|
||||||
|
if (distance > EPSILON) {
|
||||||
|
glm::vec3 vertex = cube.getFarthestVertex(cubeOffset) - _position;
|
||||||
|
if (glm::dot(vertex, cubeOffset) < _centerSphereRadius * distance) {
|
||||||
|
// the most outward cube vertex is inside central sphere
|
||||||
|
return INSIDE;
|
||||||
|
}
|
||||||
|
if (!cube.touchesSphere(_position, _centerSphereRadius)) {
|
||||||
|
sphereResult = OUTSIDE;
|
||||||
|
}
|
||||||
|
} else if (_centerSphereRadius > HALF_SQRT_THREE * cube.getScale()) {
|
||||||
|
// the cube is in center of sphere and its bounding radius is inside
|
||||||
|
return INSIDE;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 penetration;
|
// check against frustum
|
||||||
bool intersects = box.findSpherePenetration(_position, _keyholeRadius, penetration);
|
ViewFrustum::intersection frustumResult = calculateCubeFrustumIntersection(cube);
|
||||||
|
|
||||||
ViewFrustum::location result = OUTSIDE;
|
return (frustumResult == OUTSIDE) ? sphereResult : frustumResult;
|
||||||
|
|
||||||
// if the box intersects the sphere, then it may also be inside... calculate further
|
|
||||||
if (intersects) {
|
|
||||||
result = INTERSECT;
|
|
||||||
|
|
||||||
// test all the corners, if they are all inside the sphere, the entire box is in the sphere
|
|
||||||
bool allPointsInside = true; // assume the best
|
|
||||||
for (int v = BOTTOM_LEFT_NEAR; v < TOP_LEFT_FAR; v++) {
|
|
||||||
glm::vec3 vertex = box.getVertex((BoxVertex)v);
|
|
||||||
if (!pointInKeyhole(vertex)) {
|
|
||||||
allPointsInside = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allPointsInside) {
|
|
||||||
result = INSIDE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewFrustum::location ViewFrustum::computePointFrustumLocation(const glm::vec3& point) const {
|
bool ViewFrustum::pointIntersectsFrustum(const glm::vec3& point) const {
|
||||||
// only checks against frustum, not sphere
|
// only check against frustum
|
||||||
for(int i = 0; i < 6; ++i) {
|
for(int i = 0; i < 6; ++i) {
|
||||||
float distance = _planes[i].distance(point);
|
float distance = _planes[i].distance(point);
|
||||||
if (distance < 0.0f) {
|
if (distance < 0.0f) {
|
||||||
return OUTSIDE;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return INSIDE;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewFrustum::location ViewFrustum::computeSphereViewLocation(const glm::vec3& center, float radius) const {
|
bool ViewFrustum::sphereIntersectsFrustum(const glm::vec3& center, float radius) const {
|
||||||
ViewFrustum::location regularResult = INSIDE;
|
// only check against frustum
|
||||||
ViewFrustum::location keyholeResult = OUTSIDE;
|
|
||||||
|
|
||||||
// If we have a keyholeRadius, check that first, since it's cheaper
|
|
||||||
if (_keyholeRadius >= 0.0f) {
|
|
||||||
keyholeResult = sphereInKeyhole(center, radius);
|
|
||||||
}
|
|
||||||
if (keyholeResult == INSIDE) {
|
|
||||||
return keyholeResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
float distance;
|
|
||||||
for(int i=0; i < 6; i++) {
|
for(int i=0; i < 6; i++) {
|
||||||
distance = _planes[i].distance(center);
|
float distance = _planes[i].distance(center);
|
||||||
if (distance < -radius) {
|
if (distance < -radius) {
|
||||||
// This is outside the regular frustum, so just return the value from checking the keyhole
|
// This is outside the regular frustum, so just return the value from checking the keyhole
|
||||||
return keyholeResult;
|
return false;
|
||||||
} else if (distance < radius) {
|
|
||||||
regularResult = INTERSECT;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
return regularResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ViewFrustum::boxIntersectsFrustum(const AABox& box) const {
|
||||||
ViewFrustum::location ViewFrustum::computeCubeViewLocation(const AACube& cube) const {
|
// only check against frustum
|
||||||
|
|
||||||
ViewFrustum::location regularResult = INSIDE;
|
|
||||||
ViewFrustum::location keyholeResult = OUTSIDE;
|
|
||||||
|
|
||||||
// If we have a keyholeRadius, check that first, since it's cheaper
|
|
||||||
if (_keyholeRadius >= 0.0f) {
|
|
||||||
keyholeResult = cubeInKeyhole(cube);
|
|
||||||
}
|
|
||||||
if (keyholeResult == INSIDE) {
|
|
||||||
return keyholeResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: These calculations are expensive, taking up 80% of our time in this function.
|
|
||||||
// This appears to be expensive because we have to test the distance to each plane.
|
|
||||||
// One suggested optimization is to first check against the approximated cone. We might
|
|
||||||
// also be able to test against the cone to the bounding sphere of the box.
|
|
||||||
for(int i=0; i < 6; i++) {
|
for(int i=0; i < 6; i++) {
|
||||||
const glm::vec3& normal = _planes[i].getNormal();
|
const glm::vec3& normal = _planes[i].getNormal();
|
||||||
const glm::vec3& boxVertexP = cube.getVertexP(normal);
|
// check distance to farthest box point
|
||||||
float planeToBoxVertexPDistance = _planes[i].distance(boxVertexP);
|
if ( _planes[i].distance(box.getFarthestVertex(normal)) < 0.0f) {
|
||||||
|
return false;
|
||||||
const glm::vec3& boxVertexN = cube.getVertexN(normal);
|
|
||||||
float planeToBoxVertexNDistance = _planes[i].distance(boxVertexN);
|
|
||||||
|
|
||||||
if (planeToBoxVertexPDistance < 0) {
|
|
||||||
// This is outside the regular frustum, so just return the value from checking the keyhole
|
|
||||||
return keyholeResult;
|
|
||||||
} else if (planeToBoxVertexNDistance < 0) {
|
|
||||||
regularResult = INTERSECT;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return regularResult;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewFrustum::location ViewFrustum::computeBoxViewLocation(const AABox& box) const {
|
bool ViewFrustum::sphereIntersectsKeyhole(const glm::vec3& center, float radius) const {
|
||||||
|
// check positive touch against central sphere
|
||||||
ViewFrustum::location regularResult = INSIDE;
|
if (glm::length(center - _position) <= (radius + _centerSphereRadius)) {
|
||||||
ViewFrustum::location keyholeResult = OUTSIDE;
|
return true;
|
||||||
|
|
||||||
// If we have a keyholeRadius, check that first, since it's cheaper
|
|
||||||
if (_keyholeRadius >= 0.0f) {
|
|
||||||
keyholeResult = boxInKeyhole(box);
|
|
||||||
}
|
}
|
||||||
if (keyholeResult == INSIDE) {
|
// check negative touches against frustum planes
|
||||||
return keyholeResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: These calculations are expensive, taking up 80% of our time in this function.
|
|
||||||
// This appears to be expensive because we have to test the distance to each plane.
|
|
||||||
// One suggested optimization is to first check against the approximated cone. We might
|
|
||||||
// also be able to test against the cone to the bounding sphere of the box.
|
|
||||||
for(int i=0; i < 6; i++) {
|
for(int i=0; i < 6; i++) {
|
||||||
const glm::vec3& normal = _planes[i].getNormal();
|
if ( _planes[i].distance(center) < -radius) {
|
||||||
const glm::vec3& boxVertexP = box.getVertexP(normal);
|
return false;
|
||||||
float planeToBoxVertexPDistance = _planes[i].distance(boxVertexP);
|
|
||||||
|
|
||||||
const glm::vec3& boxVertexN = box.getVertexN(normal);
|
|
||||||
float planeToBoxVertexNDistance = _planes[i].distance(boxVertexN);
|
|
||||||
|
|
||||||
if (planeToBoxVertexPDistance < 0) {
|
|
||||||
// This is outside the regular frustum, so just return the value from checking the keyhole
|
|
||||||
return keyholeResult;
|
|
||||||
} else if (planeToBoxVertexNDistance < 0) {
|
|
||||||
regularResult = INTERSECT;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return regularResult;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ViewFrustum::cubeIntersectsKeyhole(const AACube& cube) const {
|
||||||
|
// check positive touch against central sphere
|
||||||
|
if (cube.touchesSphere(_position, _centerSphereRadius)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// check negative touches against frustum planes
|
||||||
|
for(int i=0; i < 6; i++) {
|
||||||
|
const glm::vec3& normal = _planes[i].getNormal();
|
||||||
|
if ( _planes[i].distance(cube.getFarthestVertex(normal)) < 0.0f) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ViewFrustum::boxIntersectsKeyhole(const AABox& box) const {
|
||||||
|
// check positive touch against central sphere
|
||||||
|
if (box.touchesSphere(_position, _centerSphereRadius)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// check negative touches against frustum planes
|
||||||
|
for(int i=0; i < 6; i++) {
|
||||||
|
const glm::vec3& normal = _planes[i].getNormal();
|
||||||
|
if ( _planes[i].distance(box.getFarthestVertex(normal)) < 0.0f) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool testMatches(glm::quat lhs, glm::quat rhs, float epsilon = EPSILON) {
|
bool testMatches(glm::quat lhs, glm::quat rhs, float epsilon = EPSILON) {
|
||||||
|
@ -528,7 +434,7 @@ void ViewFrustum::printDebugDetails() const {
|
||||||
qCDebug(octree, "_right=%f,%f,%f", (double)_right.x, (double)_right.y, (double)_right.z );
|
qCDebug(octree, "_right=%f,%f,%f", (double)_right.x, (double)_right.y, (double)_right.z );
|
||||||
qCDebug(octree, "_fieldOfView=%f", (double)_fieldOfView);
|
qCDebug(octree, "_fieldOfView=%f", (double)_fieldOfView);
|
||||||
qCDebug(octree, "_aspectRatio=%f", (double)_aspectRatio);
|
qCDebug(octree, "_aspectRatio=%f", (double)_aspectRatio);
|
||||||
qCDebug(octree, "_keyHoleRadius=%f", (double)_keyholeRadius);
|
qCDebug(octree, "_centerSphereRadius=%f", (double)_centerSphereRadius);
|
||||||
qCDebug(octree, "_nearClip=%f", (double)_nearClip);
|
qCDebug(octree, "_nearClip=%f", (double)_nearClip);
|
||||||
qCDebug(octree, "_farClip=%f", (double)_farClip);
|
qCDebug(octree, "_farClip=%f", (double)_farClip);
|
||||||
qCDebug(octree, "_focalLength=%f", (double)_focalLength);
|
qCDebug(octree, "_focalLength=%f", (double)_focalLength);
|
||||||
|
|
|
@ -27,12 +27,15 @@
|
||||||
#include "OctreeConstants.h"
|
#include "OctreeConstants.h"
|
||||||
#include "OctreeProjectedPolygon.h"
|
#include "OctreeProjectedPolygon.h"
|
||||||
|
|
||||||
const float DEFAULT_KEYHOLE_RADIUS = 3.0f;
|
const float DEFAULT_CENTER_SPHERE_RADIUS = 3.0f;
|
||||||
const float DEFAULT_FIELD_OF_VIEW_DEGREES = 45.0f;
|
const float DEFAULT_FIELD_OF_VIEW_DEGREES = 45.0f;
|
||||||
const float DEFAULT_ASPECT_RATIO = 16.0f/9.0f;
|
const float DEFAULT_ASPECT_RATIO = 16.0f/9.0f;
|
||||||
const float DEFAULT_NEAR_CLIP = 0.08f;
|
const float DEFAULT_NEAR_CLIP = 0.08f;
|
||||||
const float DEFAULT_FAR_CLIP = (float)HALF_TREE_SCALE;
|
const float DEFAULT_FAR_CLIP = (float)HALF_TREE_SCALE;
|
||||||
|
|
||||||
|
// the "ViewFrustum" has a "keyhole" shape: a regular frustum for stuff that is "visible" with
|
||||||
|
// a central sphere for stuff that is nearby (for physics simulation).
|
||||||
|
|
||||||
class ViewFrustum {
|
class ViewFrustum {
|
||||||
public:
|
public:
|
||||||
// setters for camera attributes
|
// setters for camera attributes
|
||||||
|
@ -83,19 +86,26 @@ public:
|
||||||
const glm::vec3& getNearBottomLeft() const { return _cornersWorld[BOTTOM_LEFT_NEAR]; }
|
const glm::vec3& getNearBottomLeft() const { return _cornersWorld[BOTTOM_LEFT_NEAR]; }
|
||||||
const glm::vec3& getNearBottomRight() const { return _cornersWorld[BOTTOM_RIGHT_NEAR]; }
|
const glm::vec3& getNearBottomRight() const { return _cornersWorld[BOTTOM_RIGHT_NEAR]; }
|
||||||
|
|
||||||
// get/set for keyhole attribute
|
// get/set for central spherek attribute
|
||||||
void setKeyholeRadius(float keyholdRadius) { _keyholeRadius = keyholdRadius; }
|
void setCenterRadius(float radius) { _centerSphereRadius = radius; }
|
||||||
float getKeyholeRadius() const { return _keyholeRadius; }
|
float getCenterRadius() const { return _centerSphereRadius; }
|
||||||
|
|
||||||
void calculate();
|
void calculate();
|
||||||
|
|
||||||
typedef enum {OUTSIDE, INTERSECT, INSIDE} location;
|
typedef enum { OUTSIDE = 0, INTERSECT, INSIDE } intersection;
|
||||||
|
|
||||||
ViewFrustum::location computePointFrustumLocation(const glm::vec3& point) const;
|
/// @return INSIDE, INTERSECT, or OUTSIDE depending on how cube intersects the keyhole shape
|
||||||
|
ViewFrustum::intersection calculateCubeFrustumIntersection(const AACube& cube) const;
|
||||||
|
ViewFrustum::intersection calculateCubeKeyholeIntersection(const AACube& cube) const;
|
||||||
|
|
||||||
ViewFrustum::location computeSphereViewLocation(const glm::vec3& center, float radius) const;
|
bool pointIntersectsFrustum(const glm::vec3& point) const;
|
||||||
ViewFrustum::location computeCubeViewLocation(const AACube& cube) const;
|
bool sphereIntersectsFrustum(const glm::vec3& center, float radius) const;
|
||||||
ViewFrustum::location computeBoxViewLocation(const AABox& box) const;
|
bool cubeIntersectsFrustum(const AACube& box) const;
|
||||||
|
bool boxIntersectsFrustum(const AABox& box) const;
|
||||||
|
|
||||||
|
bool sphereIntersectsKeyhole(const glm::vec3& center, float radius) const;
|
||||||
|
bool cubeIntersectsKeyhole(const AACube& cube) const;
|
||||||
|
bool boxIntersectsKeyhole(const AABox& box) const;
|
||||||
|
|
||||||
// some frustum comparisons
|
// some frustum comparisons
|
||||||
bool matches(const ViewFrustum& compareTo, bool debug = false) const;
|
bool matches(const ViewFrustum& compareTo, bool debug = false) const;
|
||||||
|
@ -132,12 +142,6 @@ public:
|
||||||
|
|
||||||
const ::Plane* getPlanes() const { return _planes; }
|
const ::Plane* getPlanes() const { return _planes; }
|
||||||
private:
|
private:
|
||||||
// Used for keyhole calculations
|
|
||||||
ViewFrustum::location pointInKeyhole(const glm::vec3& point) const;
|
|
||||||
ViewFrustum::location sphereInKeyhole(const glm::vec3& center, float radius) const;
|
|
||||||
ViewFrustum::location cubeInKeyhole(const AACube& cube) const;
|
|
||||||
ViewFrustum::location boxInKeyhole(const AABox& box) const;
|
|
||||||
|
|
||||||
// camera location/orientation attributes
|
// camera location/orientation attributes
|
||||||
glm::vec3 _position; // the position in world-frame
|
glm::vec3 _position; // the position in world-frame
|
||||||
glm::quat _orientation;
|
glm::quat _orientation;
|
||||||
|
@ -151,9 +155,7 @@ private:
|
||||||
glm::vec3 _up = IDENTITY_UP;
|
glm::vec3 _up = IDENTITY_UP;
|
||||||
glm::vec3 _right = IDENTITY_RIGHT;
|
glm::vec3 _right = IDENTITY_RIGHT;
|
||||||
|
|
||||||
// keyhole attributes
|
float _centerSphereRadius = DEFAULT_CENTER_SPHERE_RADIUS;
|
||||||
float _keyholeRadius = DEFAULT_KEYHOLE_RADIUS;
|
|
||||||
AACube _keyholeBoundingCube;
|
|
||||||
|
|
||||||
// Calculated values
|
// Calculated values
|
||||||
glm::mat4 _inverseProjection;
|
glm::mat4 _inverseProjection;
|
||||||
|
@ -166,7 +168,7 @@ private:
|
||||||
float _fieldOfView = DEFAULT_FIELD_OF_VIEW_DEGREES;
|
float _fieldOfView = DEFAULT_FIELD_OF_VIEW_DEGREES;
|
||||||
glm::vec4 _corners[8];
|
glm::vec4 _corners[8];
|
||||||
glm::vec3 _cornersWorld[8];
|
glm::vec3 _cornersWorld[8];
|
||||||
::Plane _planes[6]; // How will this be used?
|
::Plane _planes[6]; // plane normals point inside frustum
|
||||||
|
|
||||||
const char* debugPlaneName (int plane) const;
|
const char* debugPlaneName (int plane) const;
|
||||||
|
|
||||||
|
|
|
@ -474,15 +474,12 @@ void ModelMeshPartPayload::render(RenderArgs* args) const {
|
||||||
#ifdef DEBUG_BOUNDING_PARTS
|
#ifdef DEBUG_BOUNDING_PARTS
|
||||||
{
|
{
|
||||||
AABox partBounds = getPartBounds(_meshIndex, partIndex);
|
AABox partBounds = getPartBounds(_meshIndex, partIndex);
|
||||||
bool inView = args->_viewFrustum->computeBoxViewLocation(partBounds) != ViewFrustum::OUTSIDE;
|
|
||||||
|
|
||||||
glm::vec4 cubeColor;
|
glm::vec4 cubeColor(1.0f, 1.0f, 0.0f, 1.0f);
|
||||||
if (isSkinned) {
|
if (isSkinned) {
|
||||||
cubeColor = glm::vec4(0.0f, 1.0f, 1.0f, 1.0f);
|
cubeColor = glm::vec4(0.0f, 1.0f, 1.0f, 1.0f);
|
||||||
} else if (inView) {
|
} else if (args->_viewFrustum->boxIntersectsFrustum(partBounds)) {
|
||||||
cubeColor = glm::vec4(1.0f, 0.0f, 1.0f, 1.0f);
|
cubeColor = glm::vec4(1.0f, 0.0f, 1.0f, 1.0f);
|
||||||
} else {
|
|
||||||
cubeColor = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform transform;
|
Transform transform;
|
||||||
|
|
|
@ -39,12 +39,12 @@ void render::cullItems(const RenderContextPointer& renderContext, const CullFunc
|
||||||
|
|
||||||
// TODO: some entity types (like lights) might want to be rendered even
|
// TODO: some entity types (like lights) might want to be rendered even
|
||||||
// when they are outside of the view frustum...
|
// when they are outside of the view frustum...
|
||||||
bool outOfView;
|
bool inView;
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("computeBoxViewLocation");
|
PerformanceTimer perfTimer("boxIntersectsFrustum");
|
||||||
outOfView = frustum->computeBoxViewLocation(item.bound) == ViewFrustum::OUTSIDE;
|
inView = frustum->boxIntersectsFrustum(item.bound);
|
||||||
}
|
}
|
||||||
if (!outOfView) {
|
if (inView) {
|
||||||
bool bigEnoughToRender;
|
bool bigEnoughToRender;
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("shouldRender");
|
PerformanceTimer perfTimer("shouldRender");
|
||||||
|
@ -237,8 +237,8 @@ void CullSpatialSelection::run(const SceneContextPointer& sceneContext, const Re
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
bool viewTest(const AABox& bound) {
|
bool frustumTest(const AABox& bound) {
|
||||||
if (_args->_viewFrustum->computeBoxViewLocation(bound) == ViewFrustum::OUTSIDE) {
|
if (!_args->_viewFrustum->boxIntersectsFrustum(bound)) {
|
||||||
_renderDetails._outOfView++;
|
_renderDetails._outOfView++;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -302,7 +302,7 @@ void CullSpatialSelection::run(const SceneContextPointer& sceneContext, const Re
|
||||||
auto& item = scene->getItem(id);
|
auto& item = scene->getItem(id);
|
||||||
if (_filter.test(item.getKey())) {
|
if (_filter.test(item.getKey())) {
|
||||||
ItemBound itemBound(id, item.getBound());
|
ItemBound itemBound(id, item.getBound());
|
||||||
if (test.viewTest(itemBound.bound)) {
|
if (test.frustumTest(itemBound.bound)) {
|
||||||
outItems.emplace_back(itemBound);
|
outItems.emplace_back(itemBound);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,7 +316,7 @@ void CullSpatialSelection::run(const SceneContextPointer& sceneContext, const Re
|
||||||
auto& item = scene->getItem(id);
|
auto& item = scene->getItem(id);
|
||||||
if (_filter.test(item.getKey())) {
|
if (_filter.test(item.getKey())) {
|
||||||
ItemBound itemBound(id, item.getBound());
|
ItemBound itemBound(id, item.getBound());
|
||||||
if (test.viewTest(itemBound.bound)) {
|
if (test.frustumTest(itemBound.bound)) {
|
||||||
if (test.solidAngleTest(itemBound.bound)) {
|
if (test.solidAngleTest(itemBound.bound)) {
|
||||||
outItems.emplace_back(itemBound);
|
outItems.emplace_back(itemBound);
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,32 +75,32 @@ void AABox::setBox(const glm::vec3& corner, const glm::vec3& scale) {
|
||||||
_scale = scale;
|
_scale = scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 AABox::getVertexP(const glm::vec3& normal) const {
|
glm::vec3 AABox::getFarthestVertex(const glm::vec3& normal) const {
|
||||||
glm::vec3 result = _corner;
|
glm::vec3 result = _corner;
|
||||||
if (normal.x > 0) {
|
if (normal.x > 0.0f) {
|
||||||
result.x += _scale.x;
|
result.x += _scale.x;
|
||||||
}
|
}
|
||||||
if (normal.y > 0) {
|
if (normal.y > 0.0f) {
|
||||||
result.y += _scale.y;
|
result.y += _scale.y;
|
||||||
}
|
}
|
||||||
if (normal.z > 0) {
|
if (normal.z > 0.0f) {
|
||||||
result.z += _scale.z;
|
result.z += _scale.z;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 AABox::getVertexN(const glm::vec3& normal) const {
|
glm::vec3 AABox::getNearestVertex(const glm::vec3& normal) const {
|
||||||
glm::vec3 result = _corner;
|
glm::vec3 result = _corner;
|
||||||
|
|
||||||
if (normal.x < 0) {
|
if (normal.x < 0.0f) {
|
||||||
result.x += _scale.x;
|
result.x += _scale.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normal.y < 0) {
|
if (normal.y < 0.0f) {
|
||||||
result.y += _scale.y;
|
result.y += _scale.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normal.z < 0) {
|
if (normal.z < 0.0f) {
|
||||||
result.z += _scale.z;
|
result.z += _scale.z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +217,7 @@ bool AABox::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& e
|
||||||
isWithin(start.x + axisDistance*direction.x, expandedCorner.x, expandedSize.x));
|
isWithin(start.x + axisDistance*direction.x, expandedCorner.x, expandedSize.x));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||||
BoxFace& face, glm::vec3& surfaceNormal) const {
|
BoxFace& face, glm::vec3& surfaceNormal) const {
|
||||||
// handle the trivial case where the box contains the origin
|
// handle the trivial case where the box contains the origin
|
||||||
if (contains(origin)) {
|
if (contains(origin)) {
|
||||||
|
@ -281,6 +281,12 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AABox::touchesSphere(const glm::vec3& center, float radius) const {
|
||||||
|
// Avro's algorithm from this paper: http://www.mrtc.mdh.se/projects/3Dgraphics/paperF.pdf
|
||||||
|
glm::vec3 e = glm::max(_corner - center, Vectors::ZERO) + glm::max(center - _corner - _scale, Vectors::ZERO);
|
||||||
|
return glm::length2(e) <= radius * radius;
|
||||||
|
}
|
||||||
|
|
||||||
bool AABox::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const {
|
bool AABox::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const {
|
||||||
glm::vec4 center4 = glm::vec4(center, 1.0f);
|
glm::vec4 center4 = glm::vec4(center, 1.0f);
|
||||||
|
|
||||||
|
@ -537,4 +543,4 @@ void AABox::transform(const Transform& transform) {
|
||||||
scale(transform.getScale());
|
scale(transform.getScale());
|
||||||
rotate(transform.getRotation());
|
rotate(transform.getRotation());
|
||||||
translate(transform.getTranslation());
|
translate(transform.getTranslation());
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,12 +35,12 @@ public:
|
||||||
AABox(const glm::vec3& corner, const glm::vec3& dimensions);
|
AABox(const glm::vec3& corner, const glm::vec3& dimensions);
|
||||||
AABox();
|
AABox();
|
||||||
~AABox() {};
|
~AABox() {};
|
||||||
|
|
||||||
void setBox(const glm::vec3& corner, const glm::vec3& scale);
|
void setBox(const glm::vec3& corner, const glm::vec3& scale);
|
||||||
|
|
||||||
void setBox(const glm::vec3& corner, float scale);
|
void setBox(const glm::vec3& corner, float scale);
|
||||||
glm::vec3 getVertexP(const glm::vec3& normal) const;
|
glm::vec3 getFarthestVertex(const glm::vec3& normal) const; // return vertex most parallel to normal
|
||||||
glm::vec3 getVertexN(const glm::vec3& normal) const;
|
glm::vec3 getNearestVertex(const glm::vec3& normal) const; // return vertex most anti-parallel to normal
|
||||||
|
|
||||||
const glm::vec3& getCorner() const { return _corner; }
|
const glm::vec3& getCorner() const { return _corner; }
|
||||||
const glm::vec3& getScale() const { return _scale; }
|
const glm::vec3& getScale() const { return _scale; }
|
||||||
|
@ -68,11 +68,12 @@ public:
|
||||||
|
|
||||||
bool expandedContains(const glm::vec3& point, float expansion) const;
|
bool expandedContains(const glm::vec3& point, float expansion) const;
|
||||||
bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, 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,
|
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||||
BoxFace& face, glm::vec3& surfaceNormal) const;
|
BoxFace& face, glm::vec3& surfaceNormal) const;
|
||||||
|
bool touchesSphere(const glm::vec3& center, float radius) const; // fast but may generate false positives
|
||||||
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) 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;
|
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const;
|
||||||
|
|
||||||
bool isNull() const { return _scale == glm::vec3(0.0f, 0.0f, 0.0f); }
|
bool isNull() const { return _scale == glm::vec3(0.0f, 0.0f, 0.0f); }
|
||||||
|
|
||||||
AABox clamp(const glm::vec3& min, const glm::vec3& max) const;
|
AABox clamp(const glm::vec3& min, const glm::vec3& max) const;
|
||||||
|
@ -113,7 +114,7 @@ inline bool operator==(const AABox& a, const AABox& b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline QDebug operator<<(QDebug debug, const AABox& box) {
|
inline QDebug operator<<(QDebug debug, const AABox& box) {
|
||||||
debug << "AABox[ ("
|
debug << "AABox[ ("
|
||||||
<< box.getCorner().x << "," << box.getCorner().y << "," << box.getCorner().z << " ) to ("
|
<< box.getCorner().x << "," << box.getCorner().y << "," << box.getCorner().z << " ) to ("
|
||||||
<< box.calcTopFarLeft().x << "," << box.calcTopFarLeft().y << "," << box.calcTopFarLeft().z << ") size: ("
|
<< box.calcTopFarLeft().x << "," << box.calcTopFarLeft().y << "," << box.calcTopFarLeft().z << ") size: ("
|
||||||
<< box.getDimensions().x << "," << box.getDimensions().y << "," << box.getDimensions().z << ")"
|
<< box.getDimensions().x << "," << box.getDimensions().y << "," << box.getDimensions().z << ")"
|
||||||
|
|
|
@ -79,32 +79,32 @@ void AACube::setBox(const glm::vec3& corner, float scale) {
|
||||||
_scale = scale;
|
_scale = scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 AACube::getVertexP(const glm::vec3& normal) const {
|
glm::vec3 AACube::getFarthestVertex(const glm::vec3& normal) const {
|
||||||
glm::vec3 result = _corner;
|
glm::vec3 result = _corner;
|
||||||
if (normal.x > 0) {
|
if (normal.x > 0.0f) {
|
||||||
result.x += _scale;
|
result.x += _scale;
|
||||||
}
|
}
|
||||||
if (normal.y > 0) {
|
if (normal.y > 0.0f) {
|
||||||
result.y += _scale;
|
result.y += _scale;
|
||||||
}
|
}
|
||||||
if (normal.z > 0) {
|
if (normal.z > 0.0f) {
|
||||||
result.z += _scale;
|
result.z += _scale;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 AACube::getVertexN(const glm::vec3& normal) const {
|
glm::vec3 AACube::getNearestVertex(const glm::vec3& normal) const {
|
||||||
glm::vec3 result = _corner;
|
glm::vec3 result = _corner;
|
||||||
|
|
||||||
if (normal.x < 0) {
|
if (normal.x < 0.0f) {
|
||||||
result.x += _scale;
|
result.x += _scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normal.y < 0) {
|
if (normal.y < 0.0f) {
|
||||||
result.y += _scale;
|
result.y += _scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normal.z < 0) {
|
if (normal.z < 0.0f) {
|
||||||
result.z += _scale;
|
result.z += _scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,6 +284,12 @@ bool AACube::findRayIntersection(const glm::vec3& origin, const glm::vec3& direc
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AACube::touchesSphere(const glm::vec3& center, float radius) const {
|
||||||
|
// Avro's algorithm from this paper: http://www.mrtc.mdh.se/projects/3Dgraphics/paperF.pdf
|
||||||
|
glm::vec3 e = glm::max(_corner - center, Vectors::ZERO) + glm::max(center - _corner - glm::vec3(_scale), Vectors::ZERO);
|
||||||
|
return glm::length2(e) <= radius * radius;
|
||||||
|
}
|
||||||
|
|
||||||
bool AACube::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const {
|
bool AACube::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const {
|
||||||
glm::vec4 center4 = glm::vec4(center, 1.0f);
|
glm::vec4 center4 = glm::vec4(center, 1.0f);
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,8 @@ public:
|
||||||
~AACube() {};
|
~AACube() {};
|
||||||
|
|
||||||
void setBox(const glm::vec3& corner, float scale);
|
void setBox(const glm::vec3& corner, float scale);
|
||||||
glm::vec3 getVertexP(const glm::vec3& normal) const;
|
glm::vec3 getFarthestVertex(const glm::vec3& normal) const; // return vertex most parallel to normal
|
||||||
glm::vec3 getVertexN(const glm::vec3& normal) const;
|
glm::vec3 getNearestVertex(const glm::vec3& normal) const; // return vertex most anti-parallel to normal
|
||||||
void scale(float scale);
|
void scale(float scale);
|
||||||
const glm::vec3& getCorner() const { return _corner; }
|
const glm::vec3& getCorner() const { return _corner; }
|
||||||
float getScale() const { return _scale; }
|
float getScale() const { return _scale; }
|
||||||
|
@ -56,8 +56,9 @@ public:
|
||||||
bool touches(const AABox& otherBox) const;
|
bool touches(const AABox& otherBox) const;
|
||||||
bool expandedContains(const glm::vec3& point, float expansion) const;
|
bool expandedContains(const glm::vec3& point, float expansion) const;
|
||||||
bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, 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,
|
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||||
BoxFace& face, glm::vec3& surfaceNormal) const;
|
BoxFace& face, glm::vec3& surfaceNormal) const;
|
||||||
|
bool touchesSphere(const glm::vec3& center, float radius) const;
|
||||||
bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) 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;
|
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const;
|
||||||
|
|
||||||
|
@ -88,7 +89,7 @@ inline bool operator!=(const AACube& a, const AACube& b) {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline QDebug operator<<(QDebug debug, const AACube& cube) {
|
inline QDebug operator<<(QDebug debug, const AACube& cube) {
|
||||||
debug << "AACube[ ("
|
debug << "AACube[ ("
|
||||||
<< cube.getCorner().x << "," << cube.getCorner().y << "," << cube.getCorner().z << " ) to ("
|
<< cube.getCorner().x << "," << cube.getCorner().y << "," << cube.getCorner().z << " ) to ("
|
||||||
<< cube.calcTopFarLeft().x << "," << cube.calcTopFarLeft().y << "," << cube.calcTopFarLeft().z << ") size: ("
|
<< cube.calcTopFarLeft().x << "," << cube.calcTopFarLeft().y << "," << cube.calcTopFarLeft().z << ") size: ("
|
||||||
<< cube.getDimensions().x << "," << cube.getDimensions().y << "," << cube.getDimensions().z << ")"
|
<< cube.getDimensions().x << "," << cube.getDimensions().y << "," << cube.getDimensions().z << ")"
|
||||||
|
|
|
@ -670,9 +670,8 @@ void OctreeTests::byteCountCodingTests() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void OctreeTests::modelItemTests() {
|
void OctreeTests::modelItemTests() {
|
||||||
bool verbose = true;
|
|
||||||
|
|
||||||
#if 0 // TODO - repair/replace these
|
#if 0 // TODO - repair/replace these
|
||||||
|
bool verbose = true;
|
||||||
|
|
||||||
//verbose = true;
|
//verbose = true;
|
||||||
EntityTreeElementExtraEncodeData modelTreeElementExtraEncodeData;
|
EntityTreeElementExtraEncodeData modelTreeElementExtraEncodeData;
|
||||||
|
|
1347
tests/octree/src/ViewFrustumTests.cpp
Normal file
1347
tests/octree/src/ViewFrustumTests.cpp
Normal file
File diff suppressed because it is too large
Load diff
32
tests/octree/src/ViewFrustumTests.h
Normal file
32
tests/octree/src/ViewFrustumTests.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
//
|
||||||
|
// ViewFrustumTests.h
|
||||||
|
// tests/octree/src
|
||||||
|
//
|
||||||
|
// Created by Andrew Meadows on 2016.02.19
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_ViewFruxtumTests_h
|
||||||
|
#define hifi_ViewFruxtumTests_h
|
||||||
|
|
||||||
|
#include <QtTest/QtTest>
|
||||||
|
|
||||||
|
class ViewFrustumTests : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void testInit();
|
||||||
|
void testCubeFrustumIntersection();
|
||||||
|
void testCubeKeyholeIntersection();
|
||||||
|
void testPointIntersectsFrustum();
|
||||||
|
void testSphereIntersectsFrustum();
|
||||||
|
void testBoxIntersectsFrustum();
|
||||||
|
void testSphereIntersectsKeyhole();
|
||||||
|
void testCubeIntersectsKeyhole();
|
||||||
|
void testBoxIntersectsKeyhole();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_ViewFruxtumTests_h
|
153
tests/shared/src/AABoxTests.cpp
Normal file
153
tests/shared/src/AABoxTests.cpp
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
//
|
||||||
|
// AABoxTests.cpp
|
||||||
|
// tests/shared/src
|
||||||
|
//
|
||||||
|
// Created by Andrew Meadows on 2016.02.19
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "AABoxTests.h"
|
||||||
|
|
||||||
|
#include <GLMHelpers.h>
|
||||||
|
#include <NumericalConstants.h>
|
||||||
|
#include <StreamUtils.h>
|
||||||
|
|
||||||
|
#include <../GLMTestUtils.h>
|
||||||
|
#include <../QTestExtensions.h>
|
||||||
|
|
||||||
|
|
||||||
|
QTEST_MAIN(AABoxTests)
|
||||||
|
|
||||||
|
void AABoxTests::testCtorsAndSetters() {
|
||||||
|
const glm::vec3 corner(1.23f, 4.56f, 7.89f);
|
||||||
|
const glm::vec3 scale(2.34f, 7.53f, 9.14f);
|
||||||
|
|
||||||
|
// test ctor
|
||||||
|
AABox box(corner, scale);
|
||||||
|
QCOMPARE_WITH_ABS_ERROR(box.getCorner(), corner, EPSILON);
|
||||||
|
QCOMPARE_WITH_ABS_ERROR(box.getScale(), scale, EPSILON);
|
||||||
|
|
||||||
|
// test copy ctor
|
||||||
|
AABox copyBox(box);
|
||||||
|
QCOMPARE_WITH_ABS_ERROR(copyBox.getCorner(), corner, EPSILON);
|
||||||
|
QCOMPARE_WITH_ABS_ERROR(copyBox.getScale(), scale, EPSILON);
|
||||||
|
|
||||||
|
// test setBox()
|
||||||
|
const glm::vec3 newCorner(9.87f, 6.54f, 3.21f);
|
||||||
|
const glm::vec3 newScale = glm::vec3(4.32f, 8.95f, 10.31f);
|
||||||
|
box.setBox(newCorner, newScale);
|
||||||
|
QCOMPARE_WITH_ABS_ERROR(box.getCorner(), newCorner, EPSILON);
|
||||||
|
QCOMPARE_WITH_ABS_ERROR(box.getScale(), newScale, EPSILON);
|
||||||
|
|
||||||
|
// test misc
|
||||||
|
QCOMPARE_WITH_ABS_ERROR(newCorner, box.getMinimumPoint(), EPSILON);
|
||||||
|
|
||||||
|
glm::vec3 expectedMaxCorner = newCorner + glm::vec3(newScale);
|
||||||
|
QCOMPARE_WITH_ABS_ERROR(expectedMaxCorner, box.getMaximumPoint(), EPSILON);
|
||||||
|
|
||||||
|
glm::vec3 expectedCenter = newCorner + glm::vec3(0.5f * newScale);
|
||||||
|
QCOMPARE_WITH_ABS_ERROR(expectedCenter, box.calcCenter(), EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AABoxTests::testContainsPoint() {
|
||||||
|
const glm::vec3 corner(4.56f, 7.89f, -1.35f);
|
||||||
|
const glm::vec3 scale(2.34f, 7.53f, 9.14f);
|
||||||
|
AABox box(corner, scale);
|
||||||
|
|
||||||
|
float delta = 0.00001f;
|
||||||
|
glm::vec3 center = box.calcCenter();
|
||||||
|
QCOMPARE(box.contains(center), true);
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
glm::vec3 halfScale = Vectors::ZERO;
|
||||||
|
halfScale[i] = 0.5f * scale[i];
|
||||||
|
glm::vec3 deltaOffset = Vectors::ZERO;
|
||||||
|
deltaOffset[i] = delta;
|
||||||
|
|
||||||
|
QCOMPARE(box.contains(center + halfScale + deltaOffset), false); // outside +face
|
||||||
|
QCOMPARE(box.contains(center + halfScale - deltaOffset), true); // inside +face
|
||||||
|
QCOMPARE(box.contains(center - halfScale + deltaOffset), true); // inside -face
|
||||||
|
QCOMPARE(box.contains(center - halfScale - deltaOffset), false); // outside -face
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AABoxTests::testTouchesSphere() {
|
||||||
|
glm::vec3 corner(-4.56f, 7.89f, -1.35f);
|
||||||
|
float scale = 1.23f;
|
||||||
|
AABox box(corner, scale);
|
||||||
|
|
||||||
|
float delta = 0.00001f;
|
||||||
|
glm::vec3 cubeCenter = box.calcCenter();
|
||||||
|
float sphereRadius = 0.468f;
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
int j = (i + 1) % 3;
|
||||||
|
int k = (j + 1) % 3;
|
||||||
|
|
||||||
|
{ // faces
|
||||||
|
glm::vec3 scaleOffset = Vectors::ZERO;
|
||||||
|
scaleOffset[i] = 0.5f * scale + sphereRadius;
|
||||||
|
|
||||||
|
glm::vec3 deltaOffset = Vectors::ZERO;
|
||||||
|
deltaOffset[i] = delta;
|
||||||
|
|
||||||
|
// outside +face
|
||||||
|
glm::vec3 sphereCenter = cubeCenter + scaleOffset + deltaOffset;
|
||||||
|
QCOMPARE(box.touchesSphere(sphereCenter, sphereRadius), false);
|
||||||
|
|
||||||
|
// inside +face
|
||||||
|
sphereCenter = cubeCenter + scaleOffset - deltaOffset;
|
||||||
|
QCOMPARE(box.touchesSphere(sphereCenter, sphereRadius), true);
|
||||||
|
|
||||||
|
// inside -face
|
||||||
|
sphereCenter = cubeCenter - scaleOffset + deltaOffset;
|
||||||
|
QCOMPARE(box.touchesSphere(sphereCenter, sphereRadius), true);
|
||||||
|
|
||||||
|
// outside -face
|
||||||
|
sphereCenter = cubeCenter - scaleOffset - deltaOffset;
|
||||||
|
QCOMPARE(box.touchesSphere(sphereCenter, sphereRadius), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // edges
|
||||||
|
glm::vec3 edgeOffset = Vectors::ZERO;
|
||||||
|
edgeOffset[i] = 0.5f * scale;
|
||||||
|
edgeOffset[j] = 0.5f * scale;
|
||||||
|
glm::vec3 edgeDirection = glm::normalize(edgeOffset);
|
||||||
|
glm::vec3 sphereCenter;
|
||||||
|
|
||||||
|
// inside ij
|
||||||
|
sphereCenter = cubeCenter + edgeOffset + (sphereRadius - delta) * edgeDirection;
|
||||||
|
QCOMPARE(box.touchesSphere(sphereCenter, sphereRadius), true);
|
||||||
|
sphereCenter = cubeCenter - edgeOffset - (sphereRadius - delta) * edgeDirection;
|
||||||
|
QCOMPARE(box.touchesSphere(sphereCenter, sphereRadius), true);
|
||||||
|
|
||||||
|
// outside ij
|
||||||
|
sphereCenter = cubeCenter + edgeOffset + (sphereRadius + delta) * edgeDirection;
|
||||||
|
QCOMPARE(box.touchesSphere(sphereCenter, sphereRadius), false);
|
||||||
|
sphereCenter = cubeCenter - edgeOffset - (sphereRadius + delta) * edgeDirection;
|
||||||
|
QCOMPARE(box.touchesSphere(sphereCenter, sphereRadius), false);
|
||||||
|
|
||||||
|
edgeOffset[j] = 0.0f;
|
||||||
|
edgeOffset[k] = 0.5f * scale;
|
||||||
|
edgeDirection = glm::normalize(edgeOffset);
|
||||||
|
|
||||||
|
// inside ik
|
||||||
|
sphereCenter = cubeCenter + edgeOffset + (sphereRadius - delta) * edgeDirection;
|
||||||
|
QCOMPARE(box.touchesSphere(sphereCenter, sphereRadius), true);
|
||||||
|
sphereCenter = cubeCenter - edgeOffset - (sphereRadius - delta) * edgeDirection;
|
||||||
|
QCOMPARE(box.touchesSphere(sphereCenter, sphereRadius), true);
|
||||||
|
|
||||||
|
// outside ik
|
||||||
|
sphereCenter = cubeCenter + edgeOffset + (sphereRadius + delta) * edgeDirection;
|
||||||
|
QCOMPARE(box.touchesSphere(sphereCenter, sphereRadius), false);
|
||||||
|
sphereCenter = cubeCenter - edgeOffset - (sphereRadius + delta) * edgeDirection;
|
||||||
|
QCOMPARE(box.touchesSphere(sphereCenter, sphereRadius), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
28
tests/shared/src/AABoxTests.h
Normal file
28
tests/shared/src/AABoxTests.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
//
|
||||||
|
// AABoxTests.h
|
||||||
|
// tests/shared/src
|
||||||
|
//
|
||||||
|
// Created by Andrew Meadows on 2016.02.19
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_AABoxTests_h
|
||||||
|
#define hifi_AABoxTests_h
|
||||||
|
|
||||||
|
#include <QtTest/QtTest>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include <AABox.h>
|
||||||
|
|
||||||
|
class AABoxTests : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
private slots:
|
||||||
|
void testCtorsAndSetters();
|
||||||
|
void testContainsPoint();
|
||||||
|
void testTouchesSphere();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_AABoxTests_h
|
154
tests/shared/src/AACubeTests.cpp
Normal file
154
tests/shared/src/AACubeTests.cpp
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
//
|
||||||
|
// AACubeTests.cpp
|
||||||
|
// tests/shared/src
|
||||||
|
//
|
||||||
|
// Created by Andrew Meadows on 2016.02.19
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "AACubeTests.h"
|
||||||
|
|
||||||
|
#include <GLMHelpers.h>
|
||||||
|
#include <NumericalConstants.h>
|
||||||
|
#include <StreamUtils.h>
|
||||||
|
|
||||||
|
#include <../GLMTestUtils.h>
|
||||||
|
#include <../QTestExtensions.h>
|
||||||
|
|
||||||
|
|
||||||
|
QTEST_MAIN(AACubeTests)
|
||||||
|
|
||||||
|
void AACubeTests::ctorsAndSetters() {
|
||||||
|
const glm::vec3 corner(1.23f, 4.56f, 7.89f);
|
||||||
|
const float scale = 2.34f;
|
||||||
|
|
||||||
|
// test ctor
|
||||||
|
AACube cube(corner, scale);
|
||||||
|
QCOMPARE_WITH_ABS_ERROR(cube.getCorner(), corner, EPSILON);
|
||||||
|
QCOMPARE_WITH_ABS_ERROR(cube.getScale(), scale, EPSILON);
|
||||||
|
|
||||||
|
// test copy ctor
|
||||||
|
AACube copyCube(cube);
|
||||||
|
QCOMPARE_WITH_ABS_ERROR(copyCube.getCorner(), corner, EPSILON);
|
||||||
|
QCOMPARE_WITH_ABS_ERROR(copyCube.getScale(), scale, EPSILON);
|
||||||
|
|
||||||
|
// test setBox()
|
||||||
|
const glm::vec3 newCorner(9.87f, 6.54f, 3.21f);
|
||||||
|
const float newScale = 4.32f;
|
||||||
|
cube.setBox(newCorner, newScale);
|
||||||
|
QCOMPARE_WITH_ABS_ERROR(cube.getCorner(), newCorner, EPSILON);
|
||||||
|
QCOMPARE_WITH_ABS_ERROR(cube.getScale(), newScale, EPSILON);
|
||||||
|
|
||||||
|
// test misc
|
||||||
|
QCOMPARE_WITH_ABS_ERROR(cube.getMinimumPoint(), newCorner, EPSILON);
|
||||||
|
|
||||||
|
glm::vec3 expectedMaxCorner = newCorner + glm::vec3(newScale);
|
||||||
|
QCOMPARE_WITH_ABS_ERROR(cube.getMaximumPoint(), expectedMaxCorner, EPSILON);
|
||||||
|
|
||||||
|
glm::vec3 expectedCenter = newCorner + glm::vec3(0.5f * newScale);
|
||||||
|
QCOMPARE_WITH_ABS_ERROR(cube.calcCenter(), expectedCenter, EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AACubeTests::containsPoint() {
|
||||||
|
const glm::vec3 corner(4.56f, 7.89f, -1.35f);
|
||||||
|
const float scale = 1.23f;
|
||||||
|
AACube cube(corner, scale);
|
||||||
|
|
||||||
|
const float delta = scale / 1000.0f;
|
||||||
|
const glm::vec3 center = cube.calcCenter();
|
||||||
|
QCOMPARE(cube.contains(center), true);
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
glm::vec3 scaleOffset = Vectors::ZERO;
|
||||||
|
scaleOffset[i] = 0.5f * scale;
|
||||||
|
|
||||||
|
glm::vec3 deltaOffset = Vectors::ZERO;
|
||||||
|
deltaOffset[i] = delta;
|
||||||
|
|
||||||
|
QCOMPARE(cube.contains(center + scaleOffset + deltaOffset), false); // outside +face
|
||||||
|
QCOMPARE(cube.contains(center + scaleOffset - deltaOffset), true); // inside +face
|
||||||
|
QCOMPARE(cube.contains(center - scaleOffset + deltaOffset), true); // inside -face
|
||||||
|
QCOMPARE(cube.contains(center - scaleOffset - deltaOffset), false); // outside -face
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AACubeTests::touchesSphere() {
|
||||||
|
const glm::vec3 corner(-4.56f, 7.89f, -1.35f);
|
||||||
|
const float scale = 1.23f;
|
||||||
|
AACube cube(corner, scale);
|
||||||
|
|
||||||
|
const float delta = scale / 1000.0f;
|
||||||
|
const glm::vec3 cubeCenter = cube.calcCenter();
|
||||||
|
const float sphereRadius = 0.468f;
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; ++i) {
|
||||||
|
int j = (i + 1) % 3;
|
||||||
|
int k = (j + 1) % 3;
|
||||||
|
|
||||||
|
{ // faces
|
||||||
|
glm::vec3 scaleOffset = Vectors::ZERO;
|
||||||
|
scaleOffset[i] = 0.5f * scale + sphereRadius;
|
||||||
|
|
||||||
|
glm::vec3 deltaOffset = Vectors::ZERO;
|
||||||
|
deltaOffset[i] = delta;
|
||||||
|
|
||||||
|
// outside +face
|
||||||
|
glm::vec3 sphereCenter = cubeCenter + scaleOffset + deltaOffset;
|
||||||
|
QCOMPARE(cube.touchesSphere(sphereCenter, sphereRadius), false);
|
||||||
|
|
||||||
|
// inside +face
|
||||||
|
sphereCenter = cubeCenter + scaleOffset - deltaOffset;
|
||||||
|
QCOMPARE(cube.touchesSphere(sphereCenter, sphereRadius), true);
|
||||||
|
|
||||||
|
// inside -face
|
||||||
|
sphereCenter = cubeCenter - scaleOffset + deltaOffset;
|
||||||
|
QCOMPARE(cube.touchesSphere(sphereCenter, sphereRadius), true);
|
||||||
|
|
||||||
|
// outside -face
|
||||||
|
sphereCenter = cubeCenter - scaleOffset - deltaOffset;
|
||||||
|
QCOMPARE(cube.touchesSphere(sphereCenter, sphereRadius), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // edges
|
||||||
|
glm::vec3 edgeOffset = Vectors::ZERO;
|
||||||
|
edgeOffset[i] = 0.5f * scale;
|
||||||
|
edgeOffset[j] = 0.5f * scale;
|
||||||
|
glm::vec3 edgeDirection = glm::normalize(edgeOffset);
|
||||||
|
glm::vec3 sphereCenter;
|
||||||
|
|
||||||
|
// inside ij
|
||||||
|
sphereCenter = cubeCenter + edgeOffset + (sphereRadius - delta) * edgeDirection;
|
||||||
|
QCOMPARE(cube.touchesSphere(sphereCenter, sphereRadius), true);
|
||||||
|
sphereCenter = cubeCenter - edgeOffset - (sphereRadius - delta) * edgeDirection;
|
||||||
|
QCOMPARE(cube.touchesSphere(sphereCenter, sphereRadius), true);
|
||||||
|
|
||||||
|
// outside ij
|
||||||
|
sphereCenter = cubeCenter + edgeOffset + (sphereRadius + delta) * edgeDirection;
|
||||||
|
QCOMPARE(cube.touchesSphere(sphereCenter, sphereRadius), false);
|
||||||
|
sphereCenter = cubeCenter - edgeOffset - (sphereRadius + delta) * edgeDirection;
|
||||||
|
QCOMPARE(cube.touchesSphere(sphereCenter, sphereRadius), false);
|
||||||
|
|
||||||
|
edgeOffset[j] = 0.0f;
|
||||||
|
edgeOffset[k] = 0.5f * scale;
|
||||||
|
edgeDirection = glm::normalize(edgeOffset);
|
||||||
|
|
||||||
|
// inside ik
|
||||||
|
sphereCenter = cubeCenter + edgeOffset + (sphereRadius - delta) * edgeDirection;
|
||||||
|
QCOMPARE(cube.touchesSphere(sphereCenter, sphereRadius), true);
|
||||||
|
sphereCenter = cubeCenter - edgeOffset - (sphereRadius - delta) * edgeDirection;
|
||||||
|
QCOMPARE(cube.touchesSphere(sphereCenter, sphereRadius), true);
|
||||||
|
|
||||||
|
// outside ik
|
||||||
|
sphereCenter = cubeCenter + edgeOffset + (sphereRadius + delta) * edgeDirection;
|
||||||
|
QCOMPARE(cube.touchesSphere(sphereCenter, sphereRadius), false);
|
||||||
|
sphereCenter = cubeCenter - edgeOffset - (sphereRadius + delta) * edgeDirection;
|
||||||
|
QCOMPARE(cube.touchesSphere(sphereCenter, sphereRadius), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
28
tests/shared/src/AACubeTests.h
Normal file
28
tests/shared/src/AACubeTests.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
//
|
||||||
|
// AACubeTests.h
|
||||||
|
// tests/shared/src
|
||||||
|
//
|
||||||
|
// Created by Andrew Meadows on 2016.02.19
|
||||||
|
// Copyright 2016 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_AACubeTests_h
|
||||||
|
#define hifi_AACubeTests_h
|
||||||
|
|
||||||
|
#include <QtTest/QtTest>
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
|
||||||
|
#include <AACube.h>
|
||||||
|
|
||||||
|
class AACubeTests : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
private slots:
|
||||||
|
void ctorsAndSetters();
|
||||||
|
void containsPoint();
|
||||||
|
void touchesSphere();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_AACubeTests_h
|
|
@ -1,316 +0,0 @@
|
||||||
//
|
|
||||||
// AngularConstraintTests.cpp
|
|
||||||
// tests/physics/src
|
|
||||||
//
|
|
||||||
// Created by Andrew Meadows on 2014.05.30
|
|
||||||
// Copyright 2014 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "AngularConstraintTests.h"
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <AngularConstraint.h>
|
|
||||||
#include <NumericalConstants.h>
|
|
||||||
#include <StreamUtils.h>
|
|
||||||
|
|
||||||
#include "../QTestExtensions.h"
|
|
||||||
|
|
||||||
|
|
||||||
QTEST_MAIN(AngularConstraintTests)
|
|
||||||
|
|
||||||
void AngularConstraintTests::testHingeConstraint() {
|
|
||||||
float minAngle = -PI;
|
|
||||||
float maxAngle = 0.0f;
|
|
||||||
glm::vec3 yAxis(0.0f, 1.0f, 0.0f);
|
|
||||||
glm::vec3 minAngles(0.0f, -PI, 0.0f);
|
|
||||||
glm::vec3 maxAngles(0.0f, 0.0f, 0.0f);
|
|
||||||
|
|
||||||
AngularConstraint* c = AngularConstraint::newAngularConstraint(minAngles, maxAngles);
|
|
||||||
QVERIFY2(c != nullptr, "newAngularConstraint should make a constraint");
|
|
||||||
{ // test in middle of constraint
|
|
||||||
float angle = 0.5f * (minAngle + maxAngle);
|
|
||||||
glm::quat rotation = glm::angleAxis(angle, yAxis);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
|
|
||||||
QVERIFY2(constrained == false, "HingeConstraint should not clamp()");
|
|
||||||
QVERIFY2(rotation == newRotation, "HingeConstraint should not change rotation");
|
|
||||||
}
|
|
||||||
{ // test just inside min edge of constraint
|
|
||||||
float angle = minAngle + 10.0f * EPSILON;
|
|
||||||
glm::quat rotation = glm::angleAxis(angle, yAxis);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
|
|
||||||
QVERIFY2(!constrained, "HingeConstraint should not clamp()");
|
|
||||||
QVERIFY2(newRotation == rotation, "HingeConstraint should not change rotation");
|
|
||||||
}
|
|
||||||
{ // test just inside max edge of constraint
|
|
||||||
float angle = maxAngle - 10.0f * EPSILON;
|
|
||||||
glm::quat rotation = glm::angleAxis(angle, yAxis);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
|
|
||||||
QVERIFY2(!constrained, "HingeConstraint should not clamp()");
|
|
||||||
QVERIFY2(newRotation == rotation, "HingeConstraint should not change rotation");
|
|
||||||
}
|
|
||||||
{ // test just outside min edge of constraint
|
|
||||||
float angle = minAngle - 0.001f;
|
|
||||||
glm::quat rotation = glm::angleAxis(angle, yAxis);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
glm::quat expectedRotation = glm::angleAxis(minAngle, yAxis);
|
|
||||||
|
|
||||||
QVERIFY2(constrained, "HingeConstraint should clamp()");
|
|
||||||
QVERIFY2(newRotation != rotation, "HingeConstraint should change rotation");
|
|
||||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
|
||||||
}
|
|
||||||
{ // test just outside max edge of constraint
|
|
||||||
float angle = maxAngle + 0.001f;
|
|
||||||
glm::quat rotation = glm::angleAxis(angle, yAxis);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
|
|
||||||
QVERIFY2(constrained, "HingeConstraint should clamp()");
|
|
||||||
QVERIFY2(newRotation != rotation, "HingeConstraint should change rotation");
|
|
||||||
QCOMPARE_WITH_ABS_ERROR(newRotation, rotation, EPSILON);
|
|
||||||
}
|
|
||||||
{ // test far outside min edge of constraint (wraps around to max)
|
|
||||||
float angle = minAngle - 0.75f * (TWO_PI - (maxAngle - minAngle));
|
|
||||||
glm::quat rotation = glm::angleAxis(angle, yAxis);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
|
|
||||||
glm::quat expectedRotation = glm::angleAxis(maxAngle, yAxis);
|
|
||||||
QVERIFY2(constrained, "HingeConstraint should clamp()");
|
|
||||||
QVERIFY2(newRotation != rotation, "HingeConstraint should change rotation");
|
|
||||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
|
||||||
}
|
|
||||||
{ // test far outside max edge of constraint (wraps around to min)
|
|
||||||
float angle = maxAngle + 0.75f * (TWO_PI - (maxAngle - minAngle));
|
|
||||||
glm::quat rotation = glm::angleAxis(angle, yAxis);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
glm::quat expectedRotation = glm::angleAxis(minAngle, yAxis);
|
|
||||||
|
|
||||||
QVERIFY2(constrained, "HingeConstraint should clamp()");
|
|
||||||
QVERIFY2(newRotation != rotation, "HingeConstraint should change rotation");
|
|
||||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
|
||||||
}
|
|
||||||
|
|
||||||
float ACCEPTABLE_ERROR = 1.0e-4f;
|
|
||||||
{ // test nearby but off-axis rotation
|
|
||||||
float offAngle = 0.1f;
|
|
||||||
glm::quat offRotation(offAngle, glm::vec3(1.0f, 0.0f, 0.0f));
|
|
||||||
float angle = 0.5f * (maxAngle + minAngle);
|
|
||||||
glm::quat rotation = offRotation * glm::angleAxis(angle, yAxis);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
glm::quat expectedRotation = glm::angleAxis(angle, yAxis);
|
|
||||||
|
|
||||||
QVERIFY2(constrained, "HingeConstraint should clamp()");
|
|
||||||
QVERIFY2(newRotation != rotation, "HingeConstraint should change rotation");
|
|
||||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, ACCEPTABLE_ERROR);
|
|
||||||
}
|
|
||||||
{ // test way off rotation > maxAngle
|
|
||||||
float offAngle = 0.5f;
|
|
||||||
glm::quat offRotation = glm::angleAxis(offAngle, glm::vec3(1.0f, 0.0f, 0.0f));
|
|
||||||
float angle = maxAngle + 0.2f * (TWO_PI - (maxAngle - minAngle));
|
|
||||||
glm::quat rotation = glm::angleAxis(angle, yAxis);
|
|
||||||
rotation = offRotation * glm::angleAxis(angle, yAxis);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
glm::quat expectedRotation = glm::angleAxis(maxAngle, yAxis);
|
|
||||||
|
|
||||||
QVERIFY2(constrained, "HingeConstraint should clamp()");
|
|
||||||
QVERIFY2(newRotation != rotation, "HingeConstraint should change rotation");
|
|
||||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
|
||||||
}
|
|
||||||
{ // test way off rotation < minAngle
|
|
||||||
float offAngle = 0.5f;
|
|
||||||
glm::quat offRotation = glm::angleAxis(offAngle, glm::vec3(1.0f, 0.0f, 0.0f));
|
|
||||||
float angle = minAngle - 0.2f * (TWO_PI - (maxAngle - minAngle));
|
|
||||||
glm::quat rotation = glm::angleAxis(angle, yAxis);
|
|
||||||
rotation = offRotation * glm::angleAxis(angle, yAxis);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
glm::quat expectedRotation = glm::angleAxis(minAngle, yAxis);
|
|
||||||
|
|
||||||
QVERIFY2(constrained, "HingeConstraint should clamp()");
|
|
||||||
QVERIFY2(newRotation != rotation, "HingeConstraint should change rotation");
|
|
||||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
|
||||||
}
|
|
||||||
{ // test way off rotation > maxAngle with wrap over to minAngle
|
|
||||||
float offAngle = -0.5f;
|
|
||||||
glm::quat offRotation = glm::angleAxis(offAngle, glm::vec3(1.0f, 0.0f, 0.0f));
|
|
||||||
float angle = maxAngle + 0.6f * (TWO_PI - (maxAngle - minAngle));
|
|
||||||
glm::quat rotation = glm::angleAxis(angle, yAxis);
|
|
||||||
rotation = offRotation * glm::angleAxis(angle, yAxis);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
glm::quat expectedRotation = glm::angleAxis(minAngle, yAxis);
|
|
||||||
|
|
||||||
QVERIFY2(constrained, "HingeConstraint should clamp()");
|
|
||||||
QVERIFY2(newRotation != rotation, "HingeConstraint should change rotation");
|
|
||||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
|
||||||
}
|
|
||||||
{ // test way off rotation < minAngle with wrap over to maxAngle
|
|
||||||
float offAngle = -0.6f;
|
|
||||||
glm::quat offRotation = glm::angleAxis(offAngle, glm::vec3(1.0f, 0.0f, 0.0f));
|
|
||||||
float angle = minAngle - 0.7f * (TWO_PI - (maxAngle - minAngle));
|
|
||||||
glm::quat rotation = glm::angleAxis(angle, yAxis);
|
|
||||||
rotation = offRotation * glm::angleAxis(angle, yAxis);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
glm::quat expectedRotation = glm::angleAxis(maxAngle, yAxis);
|
|
||||||
|
|
||||||
QVERIFY2(constrained, "HingeConstraint should clamp()");
|
|
||||||
QVERIFY2(newRotation != rotation, "HingeConstraint should change rotation");
|
|
||||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
|
||||||
}
|
|
||||||
delete c;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AngularConstraintTests::testConeRollerConstraint() {
|
|
||||||
float minAngleX = -PI / 5.0f;
|
|
||||||
float minAngleY = -PI / 5.0f;
|
|
||||||
float minAngleZ = -PI / 8.0f;
|
|
||||||
|
|
||||||
float maxAngleX = PI / 4.0f;
|
|
||||||
float maxAngleY = PI / 3.0f;
|
|
||||||
float maxAngleZ = PI / 4.0f;
|
|
||||||
|
|
||||||
glm::vec3 minAngles(minAngleX, minAngleY, minAngleZ);
|
|
||||||
glm::vec3 maxAngles(maxAngleX, maxAngleY, maxAngleZ);
|
|
||||||
AngularConstraint* c = AngularConstraint::newAngularConstraint(minAngles, maxAngles);
|
|
||||||
|
|
||||||
float expectedConeAngle = 0.25f * (maxAngleX - minAngleX + maxAngleY - minAngleY);
|
|
||||||
glm::vec3 middleAngles = 0.5f * (maxAngles + minAngles);
|
|
||||||
glm::quat yaw = glm::angleAxis(middleAngles[1], glm::vec3(0.0f, 1.0f, 0.0f));
|
|
||||||
glm::quat pitch = glm::angleAxis(middleAngles[0], glm::vec3(1.0f, 0.0f, 0.0f));
|
|
||||||
glm::vec3 expectedConeAxis = pitch * yaw * glm::vec3(0.0f, 0.0f, 1.0f);
|
|
||||||
|
|
||||||
glm::vec3 xAxis(1.0f, 0.0f, 0.0f);
|
|
||||||
glm::vec3 perpAxis = glm::normalize(xAxis - glm::dot(xAxis, expectedConeAxis) * expectedConeAxis);
|
|
||||||
|
|
||||||
QVERIFY2(c != nullptr, "newAngularConstraint() should make a constraint");
|
|
||||||
{ // test in middle of constraint
|
|
||||||
glm::vec3 angles(PI/20.0f, 0.0f, PI/10.0f);
|
|
||||||
glm::quat rotation(angles);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
QVERIFY2(!constrained, "ConeRollerConstraint should not clamp()");
|
|
||||||
QVERIFY2(newRotation == rotation, "ConeRollerConstraint should not change rotation");
|
|
||||||
}
|
|
||||||
float deltaAngle = 0.001f;
|
|
||||||
{ // test just inside edge of cone
|
|
||||||
glm::quat rotation = glm::angleAxis(expectedConeAngle - deltaAngle, perpAxis);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
|
|
||||||
QVERIFY2(!constrained, "ConeRollerConstraint should not clamp()");
|
|
||||||
QVERIFY2(newRotation == rotation, "ConeRollerConstraint should not change rotation");
|
|
||||||
}
|
|
||||||
{ // test just outside edge of cone
|
|
||||||
glm::quat rotation = glm::angleAxis(expectedConeAngle + deltaAngle, perpAxis);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
|
|
||||||
QVERIFY2(constrained, "ConeRollerConstraint should clamp()");
|
|
||||||
QVERIFY2(newRotation != rotation, "ConeRollerConstraint should change rotation");
|
|
||||||
}
|
|
||||||
{ // test just inside min edge of roll
|
|
||||||
glm::quat rotation = glm::angleAxis(minAngleZ + deltaAngle, expectedConeAxis);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
|
|
||||||
QVERIFY2(!constrained, "ConeRollerConstraint should not clamp()");
|
|
||||||
QVERIFY2(newRotation == rotation, "ConeRollerConstraint should not change rotation");
|
|
||||||
}
|
|
||||||
{ // test just inside max edge of roll
|
|
||||||
glm::quat rotation = glm::angleAxis(maxAngleZ - deltaAngle, expectedConeAxis);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
|
|
||||||
QVERIFY2(!constrained, "ConeRollerConstraint should not clamp()");
|
|
||||||
QVERIFY2(newRotation == rotation, "ConeRollerConstraint should not change rotation");
|
|
||||||
}
|
|
||||||
{ // test just outside min edge of roll
|
|
||||||
glm::quat rotation = glm::angleAxis(minAngleZ - deltaAngle, expectedConeAxis);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
glm::quat expectedRotation = glm::angleAxis(minAngleZ, expectedConeAxis);
|
|
||||||
|
|
||||||
QVERIFY2(constrained, "ConeRollerConstraint should clamp()");
|
|
||||||
QVERIFY2(newRotation != rotation, "ConeRollerConstraint should change rotation");
|
|
||||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
|
||||||
}
|
|
||||||
{ // test just outside max edge of roll
|
|
||||||
glm::quat rotation = glm::angleAxis(maxAngleZ + deltaAngle, expectedConeAxis);
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
glm::quat expectedRotation = glm::angleAxis(maxAngleZ, expectedConeAxis);
|
|
||||||
|
|
||||||
QVERIFY2(constrained, "ConeRollerConstraint should clamp()");
|
|
||||||
QVERIFY2(newRotation != rotation, "ConeRollerConstraint should change rotation");
|
|
||||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
|
||||||
}
|
|
||||||
deltaAngle = 0.25f * expectedConeAngle;
|
|
||||||
{ // test far outside cone and min roll
|
|
||||||
glm::quat roll = glm::angleAxis(minAngleZ - deltaAngle, expectedConeAxis);
|
|
||||||
glm::quat pitchYaw = glm::angleAxis(expectedConeAngle + deltaAngle, perpAxis);
|
|
||||||
glm::quat rotation = pitchYaw * roll;
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
|
|
||||||
glm::quat expectedRoll = glm::angleAxis(minAngleZ, expectedConeAxis);
|
|
||||||
glm::quat expectedPitchYaw = glm::angleAxis(expectedConeAngle, perpAxis);
|
|
||||||
glm::quat expectedRotation = expectedPitchYaw * expectedRoll;
|
|
||||||
|
|
||||||
QVERIFY2(constrained, "ConeRollerConstraint should clamp()");
|
|
||||||
QVERIFY2(newRotation != rotation, "ConeRollerConstraint should change rotation");
|
|
||||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
|
||||||
}
|
|
||||||
{ // test far outside cone and max roll
|
|
||||||
glm::quat roll = glm::angleAxis(maxAngleZ + deltaAngle, expectedConeAxis);
|
|
||||||
glm::quat pitchYaw = glm::angleAxis(- expectedConeAngle - deltaAngle, perpAxis);
|
|
||||||
glm::quat rotation = pitchYaw * roll;
|
|
||||||
|
|
||||||
glm::quat newRotation = rotation;
|
|
||||||
bool constrained = c->clamp(newRotation);
|
|
||||||
|
|
||||||
glm::quat expectedRoll = glm::angleAxis(maxAngleZ, expectedConeAxis);
|
|
||||||
glm::quat expectedPitchYaw = glm::angleAxis(- expectedConeAngle, perpAxis);
|
|
||||||
glm::quat expectedRotation = expectedPitchYaw * expectedRoll;
|
|
||||||
|
|
||||||
QVERIFY2(constrained, "ConeRollerConstraint should clamp()");
|
|
||||||
QVERIFY2(newRotation != rotation, "ConeRollerConstraint should change rotation");
|
|
||||||
QCOMPARE_WITH_ABS_ERROR(newRotation, expectedRotation, EPSILON);
|
|
||||||
}
|
|
||||||
delete c;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
//
|
|
||||||
// AngularConstraintTests.h
|
|
||||||
// tests/physics/src
|
|
||||||
//
|
|
||||||
// Created by Andrew Meadows on 2014.05.30
|
|
||||||
// Copyright 2014 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef hifi_AngularConstraintTests_h
|
|
||||||
#define hifi_AngularConstraintTests_h
|
|
||||||
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
#include <QtTest/QtTest>
|
|
||||||
|
|
||||||
class AngularConstraintTests : public QObject {
|
|
||||||
Q_OBJECT
|
|
||||||
private slots:
|
|
||||||
void testHingeConstraint();
|
|
||||||
void testConeRollerConstraint();
|
|
||||||
};
|
|
||||||
|
|
||||||
float getErrorDifference(const glm::quat& a, const glm::quat& b);
|
|
||||||
|
|
||||||
#endif // hifi_AngularConstraintTests_h
|
|
Loading…
Reference in a new issue