mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-04-07 23:24:10 +02:00
Merge branch 'core' of https://github.com/highfidelity/hifi into punk
This commit is contained in:
commit
d2360d1406
40 changed files with 318 additions and 2814 deletions
|
@ -169,9 +169,6 @@ public:
|
|||
void setMotionState(AvatarMotionState* motionState) { _motionState = motionState; }
|
||||
AvatarMotionState* getMotionState() { return _motionState; }
|
||||
|
||||
signals:
|
||||
void collisionWithAvatar(const QUuid& myUUID, const QUuid& theirUUID, const CollisionInfo& collision);
|
||||
|
||||
protected:
|
||||
SkeletonModel _skeletonModel;
|
||||
glm::vec3 _skeletonOffset;
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#include <udt/PacketHeaders.h>
|
||||
#include <PathUtils.h>
|
||||
#include <PerfStat.h>
|
||||
#include <ShapeCollider.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <TextRenderer3D.h>
|
||||
#include <UserActivityLogger.h>
|
||||
|
@ -104,7 +103,6 @@ MyAvatar::MyAvatar(RigPointer rig) :
|
|||
_rig(rig),
|
||||
_prevShouldDrawHead(true)
|
||||
{
|
||||
ShapeCollider::initDispatchTable();
|
||||
for (int i = 0; i < MAX_DRIVE_KEYS; i++) {
|
||||
_driveKeys[i] = 0.0f;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,8 @@
|
|||
ControllerScriptingInterface::ControllerScriptingInterface() :
|
||||
_mouseCaptured(false),
|
||||
_touchCaptured(false),
|
||||
_wheelCaptured(false)
|
||||
_wheelCaptured(false),
|
||||
_actionsCaptured(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -58,15 +58,18 @@ void Rig::removeAnimationHandle(const AnimationHandlePointer& handle) {
|
|||
|
||||
void Rig::startAnimation(const QString& url, float fps, float priority,
|
||||
bool loop, bool hold, float firstFrame, float lastFrame, const QStringList& maskedJoints) {
|
||||
//qCDebug(animation) << "startAnimation" << url << fps << priority << loop << hold << firstFrame << lastFrame << maskedJoints;
|
||||
// This is different than startAnimationByRole, in which we use the existing values if the animation already exists.
|
||||
// Here we reuse the animation handle if possible, but in any case, we set the values to those given (or defaulted).
|
||||
AnimationHandlePointer handle = nullptr;
|
||||
foreach (const AnimationHandlePointer& candidate, _animationHandles) {
|
||||
if (candidate->getURL() == url) {
|
||||
candidate->start();
|
||||
return;
|
||||
handle = candidate;
|
||||
}
|
||||
}
|
||||
AnimationHandlePointer handle = createAnimationHandle();
|
||||
handle->setURL(url);
|
||||
if (!handle) {
|
||||
handle = createAnimationHandle();
|
||||
handle->setURL(url);
|
||||
}
|
||||
handle->setFPS(fps);
|
||||
handle->setPriority(priority);
|
||||
handle->setLoop(loop);
|
||||
|
@ -90,8 +93,34 @@ void Rig::addAnimationByRole(const QString& role, const QString& url, float fps,
|
|||
}
|
||||
}
|
||||
AnimationHandlePointer handle = createAnimationHandle();
|
||||
QString standard = "";
|
||||
if (url.isEmpty()) { // Default animations for fight club
|
||||
const QString& base = "https://hifi-public.s3.amazonaws.com/ozan/";
|
||||
if (role == "walk") {
|
||||
standard = base + "support/FightClubBotTest1/Animations/standard_walk.fbx";
|
||||
lastFrame = 60;
|
||||
} else if (role == "leftTurn") {
|
||||
standard = base + "support/FightClubBotTest1/Animations/left_turn_noHipRotation.fbx";
|
||||
lastFrame = 29;
|
||||
} else if (role == "rightTurn") {
|
||||
standard = base + "support/FightClubBotTest1/Animations/right_turn_noHipRotation.fbx";
|
||||
lastFrame = 31;
|
||||
} else if (role == "leftStrafe") {
|
||||
standard = base + "animations/fightclub_bot_anims/side_step_left_inPlace.fbx";
|
||||
lastFrame = 31;
|
||||
} else if (role == "rightStrafe") {
|
||||
standard = base + "animations/fightclub_bot_anims/side_step_right_inPlace.fbx";
|
||||
lastFrame = 31;
|
||||
} else if (role == "idle") {
|
||||
standard = base + "support/FightClubBotTest1/Animations/standard_idle.fbx";
|
||||
fps = 25.0f;
|
||||
}
|
||||
if (!standard.isEmpty()) {
|
||||
loop = true;
|
||||
}
|
||||
}
|
||||
handle->setRole(role);
|
||||
handle->setURL(url);
|
||||
handle->setURL(url.isEmpty() ? standard : url);
|
||||
handle->setFPS(fps);
|
||||
handle->setPriority(priority);
|
||||
handle->setLoop(loop);
|
||||
|
@ -135,6 +164,14 @@ void Rig::addRunningAnimation(AnimationHandlePointer animationHandle) {
|
|||
bool Rig::isRunningAnimation(AnimationHandlePointer animationHandle) {
|
||||
return _runningAnimations.contains(animationHandle);
|
||||
}
|
||||
bool Rig::isRunningRole(const QString& role) { //obviously, there are more efficient ways to do this
|
||||
for (auto animation : _runningAnimations) {
|
||||
if (animation->getRole() == role) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Rig::deleteAnimations() {
|
||||
for (auto animation : _animationHandles) {
|
||||
|
@ -356,37 +393,38 @@ glm::mat4 Rig::getJointVisibleTransform(int jointIndex) const {
|
|||
}
|
||||
|
||||
void Rig::computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation) {
|
||||
if (_enableRig) {
|
||||
glm::vec3 front = worldRotation * IDENTITY_FRONT;
|
||||
float forwardSpeed = glm::dot(worldVelocity, front);
|
||||
float rotationalSpeed = glm::angle(front, _lastFront) / deltaTime;
|
||||
bool isWalking = std::abs(forwardSpeed) > 0.01f;
|
||||
bool isTurning = std::abs(rotationalSpeed) > 0.5f;
|
||||
|
||||
// Crude, until we have blending:
|
||||
isTurning = isTurning && !isWalking; // Only one of walk/turn, walk wins.
|
||||
isTurning = false; // FIXME
|
||||
bool isIdle = !isWalking && !isTurning;
|
||||
auto singleRole = [](bool walking, bool turning, bool idling) {
|
||||
return walking ? "walk" : (turning ? "turn" : (idling ? "idle" : ""));
|
||||
};
|
||||
QString toStop = singleRole(_isWalking && !isWalking, _isTurning && !isTurning, _isIdle && !isIdle);
|
||||
if (!toStop.isEmpty()) {
|
||||
//qCDebug(animation) << "isTurning" << isTurning << "fronts" << front << _lastFront << glm::angle(front, _lastFront) << rotationalSpeed;
|
||||
stopAnimationByRole(toStop);
|
||||
}
|
||||
QString newRole = singleRole(isWalking && !_isWalking, isTurning && !_isTurning, isIdle && !_isIdle);
|
||||
if (!newRole.isEmpty()) {
|
||||
startAnimationByRole(newRole);
|
||||
qCDebug(animation) << deltaTime << ":" << worldVelocity << "." << front << "=> " << forwardSpeed << newRole;
|
||||
}
|
||||
|
||||
_lastPosition = worldPosition;
|
||||
_lastFront = front;
|
||||
_isWalking = isWalking;
|
||||
_isTurning = isTurning;
|
||||
_isIdle = isIdle;
|
||||
if (!_enableRig) {
|
||||
return;
|
||||
}
|
||||
bool isMoving = false;
|
||||
glm::vec3 front = worldRotation * IDENTITY_FRONT;
|
||||
float forwardSpeed = glm::dot(worldVelocity, front);
|
||||
float rightLateralSpeed = glm::dot(worldVelocity, worldRotation * IDENTITY_RIGHT);
|
||||
float rightTurningSpeed = glm::orientedAngle(front, _lastFront, IDENTITY_UP) / deltaTime;
|
||||
auto updateRole = [&](const QString& role, bool isOn) {
|
||||
isMoving = isMoving || isOn;
|
||||
if (isOn) {
|
||||
if (!isRunningRole(role)) {
|
||||
qCDebug(animation) << "Rig STARTING" << role;
|
||||
startAnimationByRole(role);
|
||||
}
|
||||
} else {
|
||||
if (isRunningRole(role)) {
|
||||
qCDebug(animation) << "Rig stopping" << role;
|
||||
stopAnimationByRole(role);
|
||||
}
|
||||
}
|
||||
};
|
||||
updateRole("walk", std::abs(forwardSpeed) > 0.01f);
|
||||
bool isTurning = std::abs(rightTurningSpeed) > 0.5f;
|
||||
updateRole("rightTurn", isTurning && (rightTurningSpeed > 0));
|
||||
updateRole("leftTurn", isTurning && (rightTurningSpeed < 0));
|
||||
bool isStrafing = std::abs(rightLateralSpeed) > 0.01f;
|
||||
updateRole("rightStrafe", isStrafing && (rightLateralSpeed > 0.0f));
|
||||
updateRole("leftStrafe", isStrafing && (rightLateralSpeed < 0.0f));
|
||||
updateRole("idle", !isMoving); // Must be last, as it makes isMoving bogus.
|
||||
_lastFront = front;
|
||||
_lastPosition = worldPosition;
|
||||
}
|
||||
|
||||
void Rig::updateAnimations(float deltaTime, glm::mat4 parentTransform) {
|
||||
|
|
|
@ -76,6 +76,7 @@ public:
|
|||
bool removeRunningAnimation(AnimationHandlePointer animationHandle);
|
||||
void addRunningAnimation(AnimationHandlePointer animationHandle);
|
||||
bool isRunningAnimation(AnimationHandlePointer animationHandle);
|
||||
bool isRunningRole(const QString& role); // There can be multiple animations per role, so this is more general than isRunningAnimation.
|
||||
const QList<AnimationHandlePointer>& getRunningAnimations() const { return _runningAnimations; }
|
||||
void deleteAnimations();
|
||||
const QList<AnimationHandlePointer>& getAnimationHandles() const { return _animationHandles; }
|
||||
|
@ -161,9 +162,6 @@ public:
|
|||
QList<AnimationHandlePointer> _runningAnimations;
|
||||
|
||||
bool _enableRig;
|
||||
bool _isWalking;
|
||||
bool _isTurning;
|
||||
bool _isIdle;
|
||||
glm::vec3 _lastFront;
|
||||
glm::vec3 _lastPosition;
|
||||
};
|
||||
|
|
|
@ -46,7 +46,6 @@ typedef unsigned long long quint64;
|
|||
#include <QtScript/QScriptable>
|
||||
#include <QReadWriteLock>
|
||||
|
||||
#include <CollisionInfo.h>
|
||||
#include <NLPacket.h>
|
||||
#include <Node.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
|
@ -257,10 +256,6 @@ public:
|
|||
const HeadData* getHeadData() const { return _headData; }
|
||||
const HandData* getHandData() const { return _handData; }
|
||||
|
||||
virtual bool findSphereCollisions(const glm::vec3& particleCenter, float particleRadius, CollisionList& collisions) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool hasIdentityChangedAfterParsing(NLPacket& packet);
|
||||
QByteArray identityByteArray();
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include <glm/glm.hpp>
|
||||
|
||||
#include <AnimationCache.h> // for Animation, AnimationCache, and AnimationPointer classes
|
||||
#include <CollisionInfo.h>
|
||||
#include <Octree.h> // for EncodeBitstreamParams class
|
||||
#include <OctreeElement.h> // for OctreeElement::AppendState
|
||||
#include <OctreePacketData.h>
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <CollisionInfo.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <Octree.h>
|
||||
#include <OctreeScriptingInterface.h>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include <QDebug>
|
||||
|
||||
#include <ByteCountCoding.h>
|
||||
#include <PlaneShape.h>
|
||||
#include <GeometryUtil.h>
|
||||
|
||||
#include "EntityTree.h"
|
||||
#include "EntityTreeElement.h"
|
||||
|
@ -128,46 +128,13 @@ void TextEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits
|
|||
|
||||
}
|
||||
|
||||
|
||||
bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const {
|
||||
|
||||
RayIntersectionInfo rayInfo;
|
||||
rayInfo._rayStart = origin;
|
||||
rayInfo._rayDirection = direction;
|
||||
rayInfo._rayLength = std::numeric_limits<float>::max();
|
||||
|
||||
PlaneShape plane;
|
||||
|
||||
const glm::vec3 UNROTATED_NORMAL(0.0f, 0.0f, -1.0f);
|
||||
glm::vec3 normal = getRotation() * UNROTATED_NORMAL;
|
||||
plane.setNormal(normal);
|
||||
plane.setPoint(getPosition()); // the position is definitely a point on our plane
|
||||
|
||||
bool intersects = plane.findRayIntersection(rayInfo);
|
||||
|
||||
if (intersects) {
|
||||
glm::vec3 hitAt = origin + (direction * rayInfo._hitDistance);
|
||||
// now we know the point the ray hit our plane
|
||||
|
||||
glm::mat4 rotation = glm::mat4_cast(getRotation());
|
||||
glm::mat4 translation = glm::translate(getPosition());
|
||||
glm::mat4 entityToWorldMatrix = translation * rotation;
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::vec3 registrationPoint = getRegistrationPoint();
|
||||
glm::vec3 corner = -(dimensions * registrationPoint);
|
||||
AABox entityFrameBox(corner, dimensions);
|
||||
|
||||
glm::vec3 entityFrameHitAt = glm::vec3(worldToEntityMatrix * glm::vec4(hitAt, 1.0f));
|
||||
|
||||
intersects = entityFrameBox.contains(entityFrameHitAt);
|
||||
}
|
||||
|
||||
if (intersects) {
|
||||
distance = rayInfo._hitDistance;
|
||||
}
|
||||
return intersects;
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
|
||||
glm::quat rotation = getRotation();
|
||||
glm::vec3 position = getPosition() + rotation *
|
||||
(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT));
|
||||
return findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <QDebug>
|
||||
|
||||
#include <ByteCountCoding.h>
|
||||
#include <PlaneShape.h>
|
||||
#include <GeometryUtil.h>
|
||||
|
||||
#include "EntityTree.h"
|
||||
#include "EntityTreeElement.h"
|
||||
|
@ -98,50 +98,17 @@ void WebEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitst
|
|||
APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, _sourceUrl);
|
||||
}
|
||||
|
||||
|
||||
bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const {
|
||||
|
||||
RayIntersectionInfo rayInfo;
|
||||
rayInfo._rayStart = origin;
|
||||
rayInfo._rayDirection = direction;
|
||||
rayInfo._rayLength = std::numeric_limits<float>::max();
|
||||
|
||||
PlaneShape plane;
|
||||
|
||||
const glm::vec3 UNROTATED_NORMAL(0.0f, 0.0f, -1.0f);
|
||||
glm::vec3 normal = getRotation() * UNROTATED_NORMAL;
|
||||
plane.setNormal(normal);
|
||||
plane.setPoint(getPosition()); // the position is definitely a point on our plane
|
||||
|
||||
bool intersects = plane.findRayIntersection(rayInfo);
|
||||
|
||||
if (intersects) {
|
||||
glm::vec3 hitAt = origin + (direction * rayInfo._hitDistance);
|
||||
// now we know the point the ray hit our plane
|
||||
|
||||
glm::mat4 rotation = glm::mat4_cast(getRotation());
|
||||
glm::mat4 translation = glm::translate(getPosition());
|
||||
glm::mat4 entityToWorldMatrix = translation * rotation;
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::vec3 registrationPoint = getRegistrationPoint();
|
||||
glm::vec3 corner = -(dimensions * registrationPoint);
|
||||
AABox entityFrameBox(corner, dimensions);
|
||||
|
||||
glm::vec3 entityFrameHitAt = glm::vec3(worldToEntityMatrix * glm::vec4(hitAt, 1.0f));
|
||||
|
||||
intersects = entityFrameBox.contains(entityFrameHitAt);
|
||||
}
|
||||
|
||||
if (intersects) {
|
||||
distance = rayInfo._hitDistance;
|
||||
}
|
||||
return intersects;
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::vec2 xyDimensions(dimensions.x, dimensions.y);
|
||||
glm::quat rotation = getRotation();
|
||||
glm::vec3 position = getPosition() + rotation *
|
||||
(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT));
|
||||
return findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance);
|
||||
}
|
||||
|
||||
|
||||
void WebEntityItem::setSourceUrl(const QString& value) {
|
||||
if (_sourceUrl != value) {
|
||||
_sourceUrl = value;
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include <GLMHelpers.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <OctalCode.h>
|
||||
#include <Shape.h>
|
||||
#include <gpu/Format.h>
|
||||
#include <LogHandler.h>
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <NetworkAccessManager.h>
|
||||
#include "FBXReader.h"
|
||||
#include "OBJReader.h"
|
||||
#include "Shape.h"
|
||||
#include "ModelFormatLogging.h"
|
||||
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#include <OctalCode.h>
|
||||
#include <udt/PacketHeaders.h>
|
||||
#include <SharedUtil.h>
|
||||
#include <Shape.h>
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include "CoverageMap.h"
|
||||
|
@ -791,13 +790,6 @@ public:
|
|||
bool found;
|
||||
};
|
||||
|
||||
class ShapeArgs {
|
||||
public:
|
||||
const Shape* shape;
|
||||
CollisionList& collisions;
|
||||
bool found;
|
||||
};
|
||||
|
||||
class ContentArgs {
|
||||
public:
|
||||
AACube cube;
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include <LogHandler.h>
|
||||
#include <NodeList.h>
|
||||
#include <PerfStat.h>
|
||||
#include <AACubeShape.h>
|
||||
|
||||
#include "AACube.h"
|
||||
#include "OctalCode.h"
|
||||
|
@ -640,50 +639,7 @@ OctreeElement* OctreeElement::getOrCreateChildElementAt(float x, float y, float
|
|||
// otherwise, we need to find which of our children we should recurse
|
||||
glm::vec3 ourCenter = _cube.calcCenter();
|
||||
|
||||
int childIndex = CHILD_UNKNOWN;
|
||||
// left half
|
||||
if (x > ourCenter.x) {
|
||||
if (y > ourCenter.y) {
|
||||
// top left
|
||||
if (z > ourCenter.z) {
|
||||
// top left far
|
||||
childIndex = CHILD_TOP_LEFT_FAR;
|
||||
} else {
|
||||
// top left near
|
||||
childIndex = CHILD_TOP_LEFT_NEAR;
|
||||
}
|
||||
} else {
|
||||
// bottom left
|
||||
if (z > ourCenter.z) {
|
||||
// bottom left far
|
||||
childIndex = CHILD_BOTTOM_LEFT_FAR;
|
||||
} else {
|
||||
// bottom left near
|
||||
childIndex = CHILD_BOTTOM_LEFT_NEAR;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// right half
|
||||
if (y > ourCenter.y) {
|
||||
// top right
|
||||
if (z > ourCenter.z) {
|
||||
// top right far
|
||||
childIndex = CHILD_TOP_RIGHT_FAR;
|
||||
} else {
|
||||
// top right near
|
||||
childIndex = CHILD_TOP_RIGHT_NEAR;
|
||||
}
|
||||
} else {
|
||||
// bottom right
|
||||
if (z > ourCenter.z) {
|
||||
// bottom right far
|
||||
childIndex = CHILD_BOTTOM_RIGHT_FAR;
|
||||
} else {
|
||||
// bottom right near
|
||||
childIndex = CHILD_BOTTOM_RIGHT_NEAR;
|
||||
}
|
||||
}
|
||||
}
|
||||
int childIndex = getMyChildContainingPoint(glm::vec3(x, y, z));
|
||||
|
||||
// Now, check if we have a child at that location
|
||||
child = getChildAtIndex(childIndex);
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
#include "ViewFrustum.h"
|
||||
#include "OctreeConstants.h"
|
||||
|
||||
class CollisionList;
|
||||
class EncodeBitstreamParams;
|
||||
class Octree;
|
||||
class OctreeElement;
|
||||
|
|
|
@ -16,12 +16,9 @@
|
|||
#include <glm/gtx/transform.hpp>
|
||||
#include <glm/gtx/norm.hpp>
|
||||
|
||||
#include <CapsuleShape.h>
|
||||
#include <GeometryUtil.h>
|
||||
#include <PathUtils.h>
|
||||
#include <PerfStat.h>
|
||||
#include <ShapeCollider.h>
|
||||
#include <SphereShape.h>
|
||||
#include <ViewFrustum.h>
|
||||
#include <render/Scene.h>
|
||||
#include <gpu/Batch.h>
|
||||
|
|
|
@ -18,9 +18,6 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <CollisionInfo.h>
|
||||
#include <RayIntersectionInfo.h>
|
||||
|
||||
class PhysicsEntity {
|
||||
|
||||
public:
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
#include <AudioConstants.h>
|
||||
#include <AudioEffectOptions.h>
|
||||
#include <AvatarData.h>
|
||||
#include <CollisionInfo.h>
|
||||
#include <EntityScriptingInterface.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <NodeList.h>
|
||||
|
@ -366,8 +365,6 @@ void ScriptEngine::init() {
|
|||
|
||||
// constants
|
||||
globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE)));
|
||||
globalObject().setProperty("COLLISION_GROUP_ENVIRONMENT", newVariant(QVariant(COLLISION_GROUP_ENVIRONMENT)));
|
||||
globalObject().setProperty("COLLISION_GROUP_AVATARS", newVariant(QVariant(COLLISION_GROUP_AVATARS)));
|
||||
}
|
||||
|
||||
QScriptValue ScriptEngine::registerGlobalObject(const QString& name, QObject* object) {
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
//
|
||||
// AACubeShape.cpp
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrew Meadows on 2014.08.22
|
||||
// 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 <glm/glm.hpp>
|
||||
#include <glm/gtx/norm.hpp>
|
||||
|
||||
#include "AACubeShape.h"
|
||||
#include "NumericalConstants.h" // for SQUARE_ROOT_OF_3
|
||||
|
||||
glm::vec3 faceNormals[3] = { glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f) };
|
||||
|
||||
bool AACubeShape::findRayIntersection(RayIntersectionInfo& intersection) const {
|
||||
// A = ray point
|
||||
// B = cube center
|
||||
glm::vec3 BA = _translation - intersection._rayStart;
|
||||
|
||||
// check for ray intersection with cube's bounding sphere
|
||||
// a = distance along line to closest approach to B
|
||||
float a = glm::dot(intersection._rayDirection, BA);
|
||||
// b2 = squared distance from cube center to point of closest approach
|
||||
float b2 = glm::length2(a * intersection._rayDirection - BA);
|
||||
// r = bounding radius of cube
|
||||
float halfSide = 0.5f * _scale;
|
||||
const float r = SQUARE_ROOT_OF_3 * halfSide;
|
||||
if (b2 > r * r) {
|
||||
// line doesn't hit cube's bounding sphere
|
||||
return false;
|
||||
}
|
||||
|
||||
// check for tuncated/short ray
|
||||
// maxLength = maximum possible distance between rayStart and center of cube
|
||||
const float maxLength = glm::min(intersection._rayLength, intersection._hitDistance) + r;
|
||||
if (a * a + b2 > maxLength * maxLength) {
|
||||
// ray is not long enough to reach cube's bounding sphere
|
||||
// NOTE: we don't fall in here when ray's length if FLT_MAX because maxLength^2 will be inf or nan
|
||||
return false;
|
||||
}
|
||||
|
||||
// the trivial checks have been exhausted, so must trace to each face
|
||||
bool hit = false;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (float sign = -1.0f; sign < 2.0f; sign += 2.0f) {
|
||||
glm::vec3 faceNormal = sign * faceNormals[i];
|
||||
float rayDotPlane = glm::dot(intersection._rayDirection, faceNormal);
|
||||
if (glm::abs(rayDotPlane) > EPSILON) {
|
||||
float distanceToFace = (halfSide + glm::dot(BA, faceNormal)) / rayDotPlane;
|
||||
if (distanceToFace >= 0.0f) {
|
||||
glm::vec3 point = distanceToFace * intersection._rayDirection - BA;
|
||||
int j = (i + 1) % 3;
|
||||
int k = (i + 2) % 3;
|
||||
glm::vec3 secondNormal = faceNormals[j];
|
||||
glm::vec3 thirdNormal = faceNormals[k];
|
||||
if (glm::abs(glm::dot(point, secondNormal)) > halfSide ||
|
||||
glm::abs(glm::dot(point, thirdNormal)) > halfSide) {
|
||||
continue;
|
||||
}
|
||||
if (distanceToFace < intersection._hitDistance && distanceToFace < intersection._rayLength) {
|
||||
intersection._hitDistance = distanceToFace;
|
||||
intersection._hitNormal = faceNormal;
|
||||
intersection._hitShape = const_cast<AACubeShape*>(this);
|
||||
hit = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return hit;
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
//
|
||||
// AACubeShape.h
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrew Meadows on 2014.08.22
|
||||
// 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_AACubeShape_h
|
||||
#define hifi_AACubeShape_h
|
||||
|
||||
#include <QDebug>
|
||||
#include "Shape.h"
|
||||
|
||||
class AACubeShape : public Shape {
|
||||
public:
|
||||
AACubeShape() : Shape(AACUBE_SHAPE), _scale(1.0f) { }
|
||||
AACubeShape(float scale) : Shape(AACUBE_SHAPE), _scale(scale) { }
|
||||
AACubeShape(float scale, const glm::vec3& position) : Shape(AACUBE_SHAPE, position), _scale(scale) { }
|
||||
|
||||
virtual ~AACubeShape() { }
|
||||
|
||||
float getScale() const { return _scale; }
|
||||
void setScale(float scale) { _scale = scale; }
|
||||
|
||||
bool findRayIntersection(RayIntersectionInfo& intersection) const;
|
||||
|
||||
float getVolume() const { return _scale * _scale * _scale; }
|
||||
virtual QDebug& dumpToDebug(QDebug& debugConext) const;
|
||||
|
||||
protected:
|
||||
float _scale;
|
||||
};
|
||||
|
||||
inline QDebug& AACubeShape::dumpToDebug(QDebug& debugConext) const {
|
||||
debugConext << "AACubeShape[ ("
|
||||
<< "type: " << getType()
|
||||
<< "position: "
|
||||
<< getTranslation().x << ", " << getTranslation().y << ", " << getTranslation().z
|
||||
<< "scale: "
|
||||
<< getScale()
|
||||
<< "]";
|
||||
|
||||
return debugConext;
|
||||
}
|
||||
|
||||
#endif // hifi_AACubeShape_h
|
|
@ -1,218 +0,0 @@
|
|||
//
|
||||
// CapsuleShape.cpp
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrew Meadows on 02/20/2014.
|
||||
// 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 <iostream>
|
||||
#include <glm/gtx/vector_angle.hpp>
|
||||
|
||||
#include "CapsuleShape.h"
|
||||
#include "GeometryUtil.h"
|
||||
#include "NumericalConstants.h"
|
||||
|
||||
CapsuleShape::CapsuleShape() : Shape(CAPSULE_SHAPE), _radius(0.0f), _halfHeight(0.0f) {}
|
||||
|
||||
CapsuleShape::CapsuleShape(float radius, float halfHeight) : Shape(CAPSULE_SHAPE),
|
||||
_radius(radius), _halfHeight(halfHeight) {
|
||||
updateBoundingRadius();
|
||||
}
|
||||
|
||||
CapsuleShape::CapsuleShape(float radius, float halfHeight, const glm::vec3& position, const glm::quat& rotation) :
|
||||
Shape(CAPSULE_SHAPE, position, rotation), _radius(radius), _halfHeight(halfHeight) {
|
||||
updateBoundingRadius();
|
||||
}
|
||||
|
||||
CapsuleShape::CapsuleShape(float radius, const glm::vec3& startPoint, const glm::vec3& endPoint) :
|
||||
Shape(CAPSULE_SHAPE), _radius(radius), _halfHeight(0.0f) {
|
||||
setEndPoints(startPoint, endPoint);
|
||||
}
|
||||
|
||||
/// \param[out] startPoint is the center of start cap
|
||||
void CapsuleShape::getStartPoint(glm::vec3& startPoint) const {
|
||||
startPoint = _translation - _rotation * glm::vec3(0.0f, _halfHeight, 0.0f);
|
||||
}
|
||||
|
||||
/// \param[out] endPoint is the center of the end cap
|
||||
void CapsuleShape::getEndPoint(glm::vec3& endPoint) const {
|
||||
endPoint = _translation + _rotation * glm::vec3(0.0f, _halfHeight, 0.0f);
|
||||
}
|
||||
|
||||
void CapsuleShape::computeNormalizedAxis(glm::vec3& axis) const {
|
||||
// default axis of a capsule is along the yAxis
|
||||
axis = _rotation * DEFAULT_CAPSULE_AXIS;
|
||||
}
|
||||
|
||||
void CapsuleShape::setRadius(float radius) {
|
||||
_radius = radius;
|
||||
updateBoundingRadius();
|
||||
}
|
||||
|
||||
void CapsuleShape::setHalfHeight(float halfHeight) {
|
||||
_halfHeight = halfHeight;
|
||||
updateBoundingRadius();
|
||||
}
|
||||
|
||||
void CapsuleShape::setRadiusAndHalfHeight(float radius, float halfHeight) {
|
||||
_radius = radius;
|
||||
_halfHeight = halfHeight;
|
||||
updateBoundingRadius();
|
||||
}
|
||||
|
||||
void CapsuleShape::setEndPoints(const glm::vec3& startPoint, const glm::vec3& endPoint) {
|
||||
glm::vec3 axis = endPoint - startPoint;
|
||||
_translation = 0.5f * (endPoint + startPoint);
|
||||
float height = glm::length(axis);
|
||||
if (height > EPSILON) {
|
||||
_halfHeight = 0.5f * height;
|
||||
axis /= height;
|
||||
_rotation = computeNewRotation(axis);
|
||||
}
|
||||
updateBoundingRadius();
|
||||
}
|
||||
|
||||
// helper
|
||||
bool findRayIntersectionWithCap(const glm::vec3& sphereCenter, float sphereRadius,
|
||||
const glm::vec3& capsuleCenter, RayIntersectionInfo& intersection) {
|
||||
float r2 = sphereRadius * sphereRadius;
|
||||
|
||||
// compute closest approach (CA)
|
||||
float a = glm::dot(sphereCenter - intersection._rayStart, intersection._rayDirection); // a = distance from ray-start to CA
|
||||
float b2 = glm::distance2(sphereCenter, intersection._rayStart + a * intersection._rayDirection); // b2 = squared distance from sphere-center to CA
|
||||
if (b2 > r2) {
|
||||
// ray does not hit sphere
|
||||
return false;
|
||||
}
|
||||
float c = sqrtf(r2 - b2); // c = distance from CA to sphere surface along intersection._rayDirection
|
||||
float d2 = glm::distance2(intersection._rayStart, sphereCenter); // d2 = squared distance from sphere-center to ray-start
|
||||
float distance = FLT_MAX;
|
||||
if (a < 0.0f) {
|
||||
// ray points away from sphere-center
|
||||
if (d2 > r2) {
|
||||
// ray starts outside sphere
|
||||
return false;
|
||||
}
|
||||
// ray starts inside sphere
|
||||
distance = c + a;
|
||||
} else if (d2 > r2) {
|
||||
// ray starts outside sphere
|
||||
distance = a - c;
|
||||
} else {
|
||||
// ray starts inside sphere
|
||||
distance = a + c;
|
||||
}
|
||||
if (distance > 0.0f && distance < intersection._rayLength && distance < intersection._hitDistance) {
|
||||
glm::vec3 sphereCenterToHitPoint = intersection._rayStart + distance * intersection._rayDirection - sphereCenter;
|
||||
if (glm::dot(sphereCenterToHitPoint, sphereCenter - capsuleCenter) >= 0.0f) {
|
||||
intersection._hitDistance = distance;
|
||||
intersection._hitNormal = glm::normalize(sphereCenterToHitPoint);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CapsuleShape::findRayIntersectionWithCaps(const glm::vec3& capsuleCenter, RayIntersectionInfo& intersection) const {
|
||||
glm::vec3 capCenter;
|
||||
getStartPoint(capCenter);
|
||||
bool hit = findRayIntersectionWithCap(capCenter, _radius, capsuleCenter, intersection);
|
||||
getEndPoint(capCenter);
|
||||
hit = findRayIntersectionWithCap(capCenter, _radius, capsuleCenter, intersection) || hit;
|
||||
if (hit) {
|
||||
intersection._hitShape = const_cast<CapsuleShape*>(this);
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
bool CapsuleShape::findRayIntersection(RayIntersectionInfo& intersection) const {
|
||||
// ray is U, capsule is V
|
||||
glm::vec3 axisV;
|
||||
computeNormalizedAxis(axisV);
|
||||
glm::vec3 centerV = getTranslation();
|
||||
|
||||
// first handle parallel case
|
||||
float uDotV = glm::dot(axisV, intersection._rayDirection);
|
||||
glm::vec3 UV = intersection._rayStart - centerV;
|
||||
if (glm::abs(1.0f - glm::abs(uDotV)) < EPSILON) {
|
||||
// line and cylinder are parallel
|
||||
float distanceV = glm::dot(UV, intersection._rayDirection);
|
||||
if (glm::length2(UV - distanceV * intersection._rayDirection) <= _radius * _radius) {
|
||||
// ray is inside cylinder's radius and might intersect caps
|
||||
return findRayIntersectionWithCaps(centerV, intersection);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Given a line with point 'U' and normalized direction 'u' and
|
||||
// a cylinder with axial point 'V', radius 'r', and normalized direction 'v'
|
||||
// the intersection of the two is on the line at distance 't' from 'U'.
|
||||
//
|
||||
// Determining the values of t reduces to solving a quadratic equation: At^2 + Bt + C = 0
|
||||
//
|
||||
// where:
|
||||
//
|
||||
// UV = U-V
|
||||
// w = u-(u.v)v
|
||||
// Q = UV-(UV.v)v
|
||||
//
|
||||
// A = w^2
|
||||
// B = 2(w.Q)
|
||||
// C = Q^2 - r^2
|
||||
|
||||
glm::vec3 w = intersection._rayDirection - uDotV * axisV;
|
||||
glm::vec3 Q = UV - glm::dot(UV, axisV) * axisV;
|
||||
|
||||
// we save a few multiplies by storing 2*A rather than just A
|
||||
float A2 = 2.0f * glm::dot(w, w);
|
||||
float B = 2.0f * glm::dot(w, Q);
|
||||
|
||||
// since C is only ever used once (in the determinant) we compute it inline
|
||||
float determinant = B * B - 2.0f * A2 * (glm::dot(Q, Q) - _radius * _radius);
|
||||
if (determinant < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
float hitLow = (-B - sqrtf(determinant)) / A2;
|
||||
float hitHigh = -(hitLow + 2.0f * B / A2);
|
||||
|
||||
if (hitLow > hitHigh) {
|
||||
// re-arrange so hitLow is always the smaller value
|
||||
float temp = hitHigh;
|
||||
hitHigh = hitLow;
|
||||
hitLow = temp;
|
||||
}
|
||||
if (hitLow < 0.0f) {
|
||||
if (hitHigh < 0.0f) {
|
||||
// capsule is completely behind rayStart
|
||||
return false;
|
||||
}
|
||||
hitLow = hitHigh;
|
||||
}
|
||||
|
||||
glm::vec3 p = intersection._rayStart + hitLow * intersection._rayDirection;
|
||||
float d = glm::dot(p - centerV, axisV);
|
||||
if (glm::abs(d) <= getHalfHeight()) {
|
||||
// we definitely hit the cylinder wall
|
||||
intersection._hitDistance = hitLow;
|
||||
intersection._hitNormal = glm::normalize(p - centerV - d * axisV);
|
||||
intersection._hitShape = const_cast<CapsuleShape*>(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
// ray still might hit the caps
|
||||
return findRayIntersectionWithCaps(centerV, intersection);
|
||||
}
|
||||
|
||||
// static
|
||||
glm::quat CapsuleShape::computeNewRotation(const glm::vec3& newAxis) {
|
||||
float angle = glm::angle(newAxis, DEFAULT_CAPSULE_AXIS);
|
||||
if (angle > EPSILON) {
|
||||
glm::vec3 rotationAxis = glm::normalize(glm::cross(DEFAULT_CAPSULE_AXIS, newAxis));
|
||||
return glm::angleAxis(angle, rotationAxis);
|
||||
}
|
||||
return glm::quat();
|
||||
}
|
|
@ -1,62 +0,0 @@
|
|||
//
|
||||
// CapsuleShape.h
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrew Meadows on 02/20/2014.
|
||||
// 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_CapsuleShape_h
|
||||
#define hifi_CapsuleShape_h
|
||||
|
||||
#include "NumericalConstants.h"
|
||||
#include "Shape.h"
|
||||
|
||||
// default axis of CapsuleShape is Y-axis
|
||||
const glm::vec3 DEFAULT_CAPSULE_AXIS(0.0f, 1.0f, 0.0f);
|
||||
|
||||
|
||||
class CapsuleShape : public Shape {
|
||||
public:
|
||||
CapsuleShape();
|
||||
CapsuleShape(float radius, float halfHeight);
|
||||
CapsuleShape(float radius, float halfHeight, const glm::vec3& position, const glm::quat& rotation);
|
||||
CapsuleShape(float radius, const glm::vec3& startPoint, const glm::vec3& endPoint);
|
||||
|
||||
virtual ~CapsuleShape() {}
|
||||
|
||||
float getRadius() const { return _radius; }
|
||||
virtual float getHalfHeight() const { return _halfHeight; }
|
||||
|
||||
/// \param[out] startPoint is the center of start cap
|
||||
virtual void getStartPoint(glm::vec3& startPoint) const;
|
||||
|
||||
/// \param[out] endPoint is the center of the end cap
|
||||
virtual void getEndPoint(glm::vec3& endPoint) const;
|
||||
|
||||
virtual void computeNormalizedAxis(glm::vec3& axis) const;
|
||||
|
||||
void setRadius(float radius);
|
||||
virtual void setHalfHeight(float height);
|
||||
virtual void setRadiusAndHalfHeight(float radius, float height);
|
||||
|
||||
/// Sets the endpoints and updates center, rotation, and halfHeight to agree.
|
||||
virtual void setEndPoints(const glm::vec3& startPoint, const glm::vec3& endPoint);
|
||||
|
||||
bool findRayIntersection(RayIntersectionInfo& intersection) const;
|
||||
|
||||
virtual float getVolume() const { return (PI * _radius * _radius) * (1.3333333333f * _radius + getHalfHeight()); }
|
||||
|
||||
protected:
|
||||
bool findRayIntersectionWithCaps(const glm::vec3& capsuleCenter, RayIntersectionInfo& intersection) const;
|
||||
virtual void updateBoundingRadius() { _boundingRadius = _radius + getHalfHeight(); }
|
||||
static glm::quat computeNewRotation(const glm::vec3& newAxis);
|
||||
|
||||
float _radius;
|
||||
float _halfHeight;
|
||||
};
|
||||
|
||||
#endif // hifi_CapsuleShape_h
|
|
@ -1,110 +0,0 @@
|
|||
//
|
||||
// CollisionInfo.cpp
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrew Meadows on 02/14/2014.
|
||||
// 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 "CollisionInfo.h"
|
||||
#include "NumericalConstants.h"
|
||||
#include "Shape.h"
|
||||
|
||||
CollisionInfo::CollisionInfo() :
|
||||
_data(NULL),
|
||||
_intData(0),
|
||||
_shapeA(NULL),
|
||||
_shapeB(NULL),
|
||||
_damping(0.0f),
|
||||
_elasticity(1.0f),
|
||||
_contactPoint(0.0f),
|
||||
_penetration(0.0f),
|
||||
_addedVelocity(0.0f) {
|
||||
}
|
||||
|
||||
quint64 CollisionInfo::getShapePairKey() const {
|
||||
if (_shapeB == NULL || _shapeA == NULL) {
|
||||
// zero is an invalid key
|
||||
return 0;
|
||||
}
|
||||
quint32 idA = _shapeA->getID();
|
||||
quint32 idB = _shapeB->getID();
|
||||
return idA < idB ? ((quint64)idA << 32) + (quint64)idB : ((quint64)idB << 32) + (quint64)idA;
|
||||
}
|
||||
|
||||
CollisionList::CollisionList(int maxSize) :
|
||||
_maxSize(maxSize),
|
||||
_size(0) {
|
||||
_collisions.resize(_maxSize);
|
||||
}
|
||||
|
||||
void CollisionInfo::apply() {
|
||||
assert(_shapeA);
|
||||
// NOTE: Shape::computeEffectiveMass() has side effects: computes and caches partial Lagrangian coefficients
|
||||
Shape* shapeA = const_cast<Shape*>(_shapeA);
|
||||
float massA = shapeA->computeEffectiveMass(_penetration, _contactPoint);
|
||||
float massB = MAX_SHAPE_MASS;
|
||||
float totalMass = massA + massB;
|
||||
if (_shapeB) {
|
||||
Shape* shapeB = const_cast<Shape*>(_shapeB);
|
||||
massB = shapeB->computeEffectiveMass(-_penetration, _contactPoint - _penetration);
|
||||
totalMass = massA + massB;
|
||||
if (totalMass < EPSILON) {
|
||||
massA = massB = 1.0f;
|
||||
totalMass = 2.0f;
|
||||
}
|
||||
// remember that _penetration points from A into B
|
||||
shapeB->accumulateDelta(massA / totalMass, _penetration);
|
||||
}
|
||||
// NOTE: Shape::accumulateDelta() uses the coefficients from previous call to Shape::computeEffectiveMass()
|
||||
// remember that _penetration points from A into B
|
||||
shapeA->accumulateDelta(massB / totalMass, -_penetration);
|
||||
}
|
||||
|
||||
CollisionInfo* CollisionList::getNewCollision() {
|
||||
// return pointer to existing CollisionInfo, or NULL of list is full
|
||||
return (_size < _maxSize) ? &(_collisions[_size++]) : NULL;
|
||||
}
|
||||
|
||||
void CollisionList::deleteLastCollision() {
|
||||
if (_size > 0) {
|
||||
--_size;
|
||||
}
|
||||
}
|
||||
|
||||
CollisionInfo* CollisionList::getCollision(int index) {
|
||||
return (index > -1 && index < _size) ? &(_collisions[index]) : NULL;
|
||||
}
|
||||
|
||||
CollisionInfo* CollisionList::getLastCollision() {
|
||||
return (_size > 0) ? &(_collisions[_size - 1]) : NULL;
|
||||
}
|
||||
|
||||
void CollisionList::clear() {
|
||||
// we rely on the external context to properly set or clear the data members of CollisionInfos
|
||||
/*
|
||||
for (int i = 0; i < _size; ++i) {
|
||||
// we only clear the important stuff
|
||||
CollisionInfo& collision = _collisions[i];
|
||||
//collision._data = NULL;
|
||||
//collision._intData = 0;
|
||||
//collision._floatDAta = 0.0f;
|
||||
//collision._vecData = glm::vec3(0.0f);
|
||||
//collision._shapeA = NULL;
|
||||
//collision._shapeB = NULL;
|
||||
//collision._damping;
|
||||
//collision._elasticity;
|
||||
//collision._contactPoint;
|
||||
//collision._penetration;
|
||||
//collision._addedVelocity;
|
||||
}
|
||||
*/
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
CollisionInfo* CollisionList::operator[](int index) {
|
||||
return (index > -1 && index < _size) ? &(_collisions[index]) : NULL;
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
//
|
||||
// CollisionInfo.h
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrew Meadows on 02/14/2014.
|
||||
// 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_CollisionInfo_h
|
||||
#define hifi_CollisionInfo_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <QtGlobal>
|
||||
#include <QVector>
|
||||
|
||||
class Shape;
|
||||
|
||||
const quint32 COLLISION_GROUP_ENVIRONMENT = 1U << 0;
|
||||
const quint32 COLLISION_GROUP_AVATARS = 1U << 1;
|
||||
const quint32 COLLISION_GROUP_VOXELS = 1U << 2;
|
||||
const quint32 VALID_COLLISION_GROUPS = 0x0f;
|
||||
|
||||
// CollisionInfo contains details about the collision between two things: BodyA and BodyB.
|
||||
// The assumption is that the context that analyzes the collision knows about BodyA but
|
||||
// does not necessarily know about BodyB. Hence the data storred in the CollisionInfo
|
||||
// is expected to be relative to BodyA (for example the penetration points from A into B).
|
||||
|
||||
class CollisionInfo {
|
||||
public:
|
||||
CollisionInfo();
|
||||
~CollisionInfo() {}
|
||||
|
||||
// TODO: Andrew to get rid of these data members
|
||||
void* _data;
|
||||
int _intData;
|
||||
float _floatData;
|
||||
glm::vec3 _vecData;
|
||||
|
||||
/// accumulates position changes for the shapes in this collision to resolve penetration
|
||||
void apply();
|
||||
|
||||
Shape* getShapeA() const { return const_cast<Shape*>(_shapeA); }
|
||||
Shape* getShapeB() const { return const_cast<Shape*>(_shapeB); }
|
||||
|
||||
/// \return unique key for shape pair
|
||||
quint64 getShapePairKey() const;
|
||||
|
||||
const Shape* _shapeA; // pointer to shapeA in this collision
|
||||
const Shape* _shapeB; // pointer to shapeB in this collision
|
||||
|
||||
void* _extraData; // pointer to extraData for this collision, opaque to the collision info, useful for external data
|
||||
|
||||
float _damping; // range [0,1] of friction coeficient
|
||||
float _elasticity; // range [0,1] of energy conservation
|
||||
glm::vec3 _contactPoint; // world-frame point on BodyA that is deepest into BodyB
|
||||
glm::vec3 _penetration; // depth that BodyA penetrates into BodyB
|
||||
glm::vec3 _addedVelocity; // velocity of BodyB
|
||||
};
|
||||
|
||||
// CollisionList is intended to be a recycled container. Fill the CollisionInfo's,
|
||||
// use them, and then clear them for the next frame or context.
|
||||
|
||||
class CollisionList {
|
||||
public:
|
||||
CollisionList(int maxSize);
|
||||
|
||||
/// \return pointer to next collision. NULL if list is full.
|
||||
CollisionInfo* getNewCollision();
|
||||
|
||||
/// \forget about collision at the end
|
||||
void deleteLastCollision();
|
||||
|
||||
/// \return pointer to collision by index. NULL if index out of bounds.
|
||||
CollisionInfo* getCollision(int index);
|
||||
|
||||
/// \return pointer to last collision on the list. NULL if list is empty
|
||||
CollisionInfo* getLastCollision();
|
||||
|
||||
/// \return true if list is full
|
||||
bool isFull() const { return _size == _maxSize; }
|
||||
|
||||
/// \return number of valid collisions
|
||||
int size() const { return _size; }
|
||||
|
||||
/// Clear valid collisions.
|
||||
void clear();
|
||||
|
||||
CollisionInfo* operator[](int index);
|
||||
|
||||
private:
|
||||
int _maxSize; // the container cannot get larger than this
|
||||
int _size; // the current number of valid collisions in the list
|
||||
QVector<CollisionInfo> _collisions;
|
||||
};
|
||||
|
||||
#endif // hifi_CollisionInfo_h
|
|
@ -10,7 +10,6 @@ QSurfaceFormat getDefaultOpenGlSurfaceFormat() {
|
|||
#ifdef DEBUG
|
||||
format.setOption(QSurfaceFormat::DebugContext);
|
||||
#endif
|
||||
// FIXME move to core as soon as possible
|
||||
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile);
|
||||
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CoreProfile);
|
||||
return format;
|
||||
}
|
||||
|
|
|
@ -11,11 +11,10 @@
|
|||
|
||||
#include <cstring>
|
||||
#include <cmath>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
#include "GeometryUtil.h"
|
||||
#include "NumericalConstants.h"
|
||||
#include "PlaneShape.h"
|
||||
#include "RayIntersectionInfo.h"
|
||||
|
||||
glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end) {
|
||||
// compute the projection of the point vector onto the segment vector
|
||||
|
@ -496,31 +495,45 @@ void PolygonClip::copyCleanArray(int& lengthA, glm::vec2* vertexArrayA, int& len
|
|||
|
||||
bool findRayRectangleIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::quat& rotation,
|
||||
const glm::vec3& position, const glm::vec2& dimensions, float& distance) {
|
||||
RayIntersectionInfo rayInfo;
|
||||
rayInfo._rayStart = origin;
|
||||
rayInfo._rayDirection = direction;
|
||||
rayInfo._rayLength = std::numeric_limits<float>::max();
|
||||
|
||||
PlaneShape plane;
|
||||
|
||||
const glm::vec3 UNROTATED_NORMAL(0.0f, 0.0f, -1.0f);
|
||||
glm::vec3 normal = rotation * UNROTATED_NORMAL;
|
||||
plane.setNormal(normal);
|
||||
plane.setPoint(position); // the position is definitely a point on our plane
|
||||
|
||||
bool intersects = plane.findRayIntersection(rayInfo);
|
||||
bool maybeIntersects = false;
|
||||
float denominator = glm::dot(normal, direction);
|
||||
glm::vec3 offset = origin - position;
|
||||
float normDotOffset = glm::dot(offset, normal);
|
||||
float d = 0.0f;
|
||||
if (fabsf(denominator) < EPSILON) {
|
||||
// line is perpendicular to plane
|
||||
if (fabsf(normDotOffset) < EPSILON) {
|
||||
// ray starts on the plane
|
||||
maybeIntersects = true;
|
||||
|
||||
if (intersects) {
|
||||
distance = rayInfo._hitDistance;
|
||||
|
||||
glm::vec3 hitPosition = origin + (distance * direction);
|
||||
glm::vec3 localHitPosition = glm::inverse(rotation) * (hitPosition - position);
|
||||
|
||||
glm::vec2 halfDimensions = 0.5f * dimensions;
|
||||
|
||||
intersects = -halfDimensions.x <= localHitPosition.x && localHitPosition.x <= halfDimensions.x
|
||||
&& -halfDimensions.y <= localHitPosition.y && localHitPosition.y <= halfDimensions.y;
|
||||
// compute distance to closest approach
|
||||
d = - glm::dot(offset, direction); // distance to closest approach of center of rectangle
|
||||
if (d < 0.0f) {
|
||||
// ray points away from center of rectangle, so ray's start is the closest approach
|
||||
d = 0.0f;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
d = - normDotOffset / denominator;
|
||||
if (d > 0.0f) {
|
||||
// ray points toward plane
|
||||
maybeIntersects = true;
|
||||
}
|
||||
}
|
||||
|
||||
return intersects;
|
||||
if (maybeIntersects) {
|
||||
glm::vec3 hitPosition = origin + (d * direction);
|
||||
glm::vec3 localHitPosition = glm::inverse(rotation) * (hitPosition - position);
|
||||
glm::vec2 halfDimensions = 0.5f * dimensions;
|
||||
if (fabsf(localHitPosition.x) < halfDimensions.x && fabsf(localHitPosition.y) < halfDimensions.y) {
|
||||
// only update distance on intersection
|
||||
distance = d;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
//
|
||||
// ListShape.cpp
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrew Meadows on 02/20/2014.
|
||||
// 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 "ListShape.h"
|
||||
|
||||
// ListShapeEntry
|
||||
|
||||
void ListShapeEntry::updateTransform(const glm::vec3& rootPosition, const glm::quat& rootRotation) {
|
||||
_shape->setTranslation(rootPosition + rootRotation * _localPosition);
|
||||
_shape->setRotation(_localRotation * rootRotation);
|
||||
}
|
||||
|
||||
// ListShape
|
||||
|
||||
ListShape::~ListShape() {
|
||||
clear();
|
||||
}
|
||||
|
||||
void ListShape::setTranslation(const glm::vec3& position) {
|
||||
_subShapeTransformsAreDirty = true;
|
||||
Shape::setTranslation(position);
|
||||
}
|
||||
|
||||
void ListShape::setRotation(const glm::quat& rotation) {
|
||||
_subShapeTransformsAreDirty = true;
|
||||
Shape::setRotation(rotation);
|
||||
}
|
||||
|
||||
const Shape* ListShape::getSubShape(int index) const {
|
||||
if (index < 0 || index > _subShapeEntries.size()) {
|
||||
return NULL;
|
||||
}
|
||||
return _subShapeEntries[index]._shape;
|
||||
}
|
||||
|
||||
void ListShape::updateSubTransforms() {
|
||||
if (_subShapeTransformsAreDirty) {
|
||||
for (int i = 0; i < _subShapeEntries.size(); ++i) {
|
||||
_subShapeEntries[i].updateTransform(_translation, _rotation);
|
||||
}
|
||||
_subShapeTransformsAreDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ListShape::addShape(Shape* shape, const glm::vec3& localPosition, const glm::quat& localRotation) {
|
||||
if (shape) {
|
||||
ListShapeEntry entry;
|
||||
entry._shape = shape;
|
||||
entry._localPosition = localPosition;
|
||||
entry._localRotation = localRotation;
|
||||
_subShapeEntries.push_back(entry);
|
||||
}
|
||||
}
|
||||
|
||||
void ListShape::setShapes(QVector<ListShapeEntry>& shapes) {
|
||||
clear();
|
||||
_subShapeEntries.swap(shapes);
|
||||
// TODO: audit our new list of entries and delete any that have null pointers
|
||||
computeBoundingRadius();
|
||||
}
|
||||
|
||||
void ListShape::clear() {
|
||||
// the ListShape owns its subShapes, so they need to be deleted
|
||||
for (int i = 0; i < _subShapeEntries.size(); ++i) {
|
||||
delete _subShapeEntries[i]._shape;
|
||||
}
|
||||
_subShapeEntries.clear();
|
||||
setBoundingRadius(0.0f);
|
||||
}
|
||||
|
||||
void ListShape::computeBoundingRadius() {
|
||||
float maxRadius = 0.0f;
|
||||
for (int i = 0; i < _subShapeEntries.size(); ++i) {
|
||||
ListShapeEntry& entry = _subShapeEntries[i];
|
||||
float radius = glm::length(entry._localPosition) + entry._shape->getBoundingRadius();
|
||||
if (radius > maxRadius) {
|
||||
maxRadius = radius;
|
||||
}
|
||||
}
|
||||
setBoundingRadius(maxRadius);
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
//
|
||||
// ListShape.h
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrew Meadows on 02/20/2014.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// ListShape: A collection of shapes, each with a local transform.
|
||||
//
|
||||
// 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_ListShape_h
|
||||
#define hifi_ListShape_h
|
||||
|
||||
#include <QVector>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <glm/gtx/norm.hpp>
|
||||
|
||||
#include "Shape.h"
|
||||
|
||||
|
||||
class ListShapeEntry {
|
||||
public:
|
||||
void updateTransform(const glm::vec3& position, const glm::quat& rotation);
|
||||
|
||||
Shape* _shape;
|
||||
glm::vec3 _localPosition;
|
||||
glm::quat _localRotation;
|
||||
};
|
||||
|
||||
class ListShape : public Shape {
|
||||
public:
|
||||
|
||||
ListShape() : Shape(LIST_SHAPE), _subShapeEntries(), _subShapeTransformsAreDirty(false) {}
|
||||
|
||||
ListShape(const glm::vec3& position, const glm::quat& rotation) :
|
||||
Shape(LIST_SHAPE, position, rotation), _subShapeEntries(), _subShapeTransformsAreDirty(false) {}
|
||||
|
||||
~ListShape();
|
||||
|
||||
void setTranslation(const glm::vec3& position);
|
||||
void setRotation(const glm::quat& rotation);
|
||||
|
||||
const Shape* getSubShape(int index) const;
|
||||
|
||||
void updateSubTransforms();
|
||||
|
||||
int size() const { return _subShapeEntries.size(); }
|
||||
|
||||
void addShape(Shape* shape, const glm::vec3& localPosition, const glm::quat& localRotation);
|
||||
|
||||
void setShapes(QVector<ListShapeEntry>& shapes);
|
||||
|
||||
// TODO: either implement this or remove ListShape altogether
|
||||
bool findRayIntersection(RayIntersectionInfo& intersection) const { return false; }
|
||||
|
||||
protected:
|
||||
void clear();
|
||||
void computeBoundingRadius();
|
||||
|
||||
QVector<ListShapeEntry> _subShapeEntries;
|
||||
bool _subShapeTransformsAreDirty;
|
||||
|
||||
private:
|
||||
ListShape(const ListShape& otherList); // don't implement this
|
||||
};
|
||||
|
||||
#endif // hifi_ListShape_h
|
|
@ -1,78 +0,0 @@
|
|||
//
|
||||
// PlaneShape.cpp
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrzej Kapolka on 4/10/2014.
|
||||
// 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 "GLMHelpers.h"
|
||||
#include "NumericalConstants.h"
|
||||
#include "PlaneShape.h"
|
||||
|
||||
const glm::vec3 UNROTATED_NORMAL(0.0f, 1.0f, 0.0f);
|
||||
|
||||
PlaneShape::PlaneShape(const glm::vec4& coefficients) :
|
||||
Shape(PLANE_SHAPE) {
|
||||
|
||||
glm::vec3 normal = glm::vec3(coefficients);
|
||||
_translation = -normal * coefficients.w;
|
||||
|
||||
float angle = acosf(glm::dot(normal, UNROTATED_NORMAL));
|
||||
if (angle > EPSILON) {
|
||||
if (angle > PI - EPSILON) {
|
||||
_rotation = glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f));
|
||||
} else {
|
||||
_rotation = glm::angleAxis(angle, glm::normalize(glm::cross(UNROTATED_NORMAL, normal)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 PlaneShape::getNormal() const {
|
||||
return _rotation * UNROTATED_NORMAL;
|
||||
}
|
||||
|
||||
void PlaneShape::setNormal(const glm::vec3& direction) {
|
||||
glm::vec3 oldTranslation = _translation;
|
||||
_rotation = rotationBetween(UNROTATED_NORMAL, direction);
|
||||
glm::vec3 normal = getNormal();
|
||||
_translation = glm::dot(oldTranslation, normal) * normal;
|
||||
}
|
||||
|
||||
void PlaneShape::setPoint(const glm::vec3& point) {
|
||||
glm::vec3 normal = getNormal();
|
||||
_translation = glm::dot(point, normal) * normal;
|
||||
}
|
||||
|
||||
glm::vec4 PlaneShape::getCoefficients() const {
|
||||
glm::vec3 normal = _rotation * UNROTATED_NORMAL;
|
||||
return glm::vec4(normal.x, normal.y, normal.z, -glm::dot(normal, _translation));
|
||||
}
|
||||
|
||||
bool PlaneShape::findRayIntersection(RayIntersectionInfo& intersection) const {
|
||||
glm::vec3 n = getNormal();
|
||||
float denominator = glm::dot(n, intersection._rayDirection);
|
||||
if (fabsf(denominator) < EPSILON) {
|
||||
// line is parallel to plane
|
||||
if (glm::dot(_translation - intersection._rayStart, n) < EPSILON) {
|
||||
// ray starts on the plane
|
||||
intersection._hitDistance = 0.0f;
|
||||
intersection._hitNormal = n;
|
||||
intersection._hitShape = const_cast<PlaneShape*>(this);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
float d = glm::dot(_translation - intersection._rayStart, n) / denominator;
|
||||
if (d > 0.0f && d < intersection._rayLength && d < intersection._hitDistance) {
|
||||
// ray points toward plane
|
||||
intersection._hitDistance = d;
|
||||
intersection._hitNormal = n;
|
||||
intersection._hitShape = const_cast<PlaneShape*>(this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
//
|
||||
// PlaneShape.h
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrzej Kapolka on 4/9/2014.
|
||||
// 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_PlaneShape_h
|
||||
#define hifi_PlaneShape_h
|
||||
|
||||
#include "Shape.h"
|
||||
|
||||
class PlaneShape : public Shape {
|
||||
public:
|
||||
PlaneShape(const glm::vec4& coefficients = glm::vec4(0.0f, 1.0f, 0.0f, 0.0f));
|
||||
|
||||
glm::vec3 getNormal() const;
|
||||
glm::vec4 getCoefficients() const;
|
||||
|
||||
void setNormal(const glm::vec3& normal);
|
||||
void setPoint(const glm::vec3& point);
|
||||
|
||||
bool findRayIntersection(RayIntersectionInfo& intersection) const;
|
||||
};
|
||||
|
||||
#endif // hifi_PlaneShape_h
|
|
@ -1,37 +0,0 @@
|
|||
//
|
||||
// RayIntersectionInfo.h
|
||||
// libraries/physcis/src
|
||||
//
|
||||
// Created by Andrew Meadows 2014.09.09
|
||||
// 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_RayIntersectionInfo_h
|
||||
#define hifi_RayIntersectionInfo_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class Shape;
|
||||
|
||||
class RayIntersectionInfo {
|
||||
public:
|
||||
RayIntersectionInfo() : _rayStart(0.0f), _rayDirection(1.0f, 0.0f, 0.0f), _rayLength(FLT_MAX),
|
||||
_hitDistance(FLT_MAX), _hitNormal(1.0f, 0.0f, 0.0f), _hitShape(NULL) { }
|
||||
|
||||
glm::vec3 getIntersectionPoint() const { return _rayStart + _hitDistance * _rayDirection; }
|
||||
|
||||
// input
|
||||
glm::vec3 _rayStart;
|
||||
glm::vec3 _rayDirection;
|
||||
float _rayLength;
|
||||
|
||||
// output
|
||||
float _hitDistance;
|
||||
glm::vec3 _hitNormal;
|
||||
Shape* _hitShape;
|
||||
};
|
||||
|
||||
#endif // hifi_RayIntersectionInfo_h
|
|
@ -1,144 +0,0 @@
|
|||
//
|
||||
// Shape.h
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrew Meadows on 2014.
|
||||
// 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_Shape_h
|
||||
#define hifi_Shape_h
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <QDebug>
|
||||
#include <QtGlobal>
|
||||
#include <QVector>
|
||||
|
||||
#include "RayIntersectionInfo.h"
|
||||
|
||||
class PhysicsEntity;
|
||||
|
||||
const float MAX_SHAPE_MASS = 1.0e18f; // something less than sqrt(FLT_MAX)
|
||||
|
||||
// DANGER: until ShapeCollider goes away the order of these values matter. Specifically,
|
||||
// UNKNOWN_SHAPE must be equal to the number of shapes that ShapeCollider actually supports.
|
||||
const quint8 SPHERE_SHAPE = 0;
|
||||
const quint8 CAPSULE_SHAPE = 1;
|
||||
const quint8 PLANE_SHAPE = 2;
|
||||
const quint8 AACUBE_SHAPE = 3;
|
||||
const quint8 LIST_SHAPE = 4;
|
||||
const quint8 UNKNOWN_SHAPE = 5;
|
||||
const quint8 INVALID_SHAPE = 5;
|
||||
|
||||
// new shapes to be supported by Bullet
|
||||
const quint8 BOX_SHAPE = 7;
|
||||
const quint8 CYLINDER_SHAPE = 8;
|
||||
|
||||
class Shape {
|
||||
public:
|
||||
|
||||
typedef quint8 Type;
|
||||
|
||||
static quint32 getNextID() { static quint32 nextID = 0; return ++nextID; }
|
||||
|
||||
Shape() : _type(UNKNOWN_SHAPE), _owningEntity(NULL), _boundingRadius(0.0f),
|
||||
_translation(0.0f), _rotation(), _mass(MAX_SHAPE_MASS) {
|
||||
_id = getNextID();
|
||||
}
|
||||
virtual ~Shape() { }
|
||||
|
||||
Type getType() const { return _type; }
|
||||
quint32 getID() const { return _id; }
|
||||
|
||||
void setEntity(PhysicsEntity* entity) { _owningEntity = entity; }
|
||||
PhysicsEntity* getEntity() const { return _owningEntity; }
|
||||
|
||||
float getBoundingRadius() const { return _boundingRadius; }
|
||||
|
||||
virtual const glm::quat& getRotation() const { return _rotation; }
|
||||
virtual void setRotation(const glm::quat& rotation) { _rotation = rotation; }
|
||||
|
||||
virtual void setTranslation(const glm::vec3& translation) { _translation = translation; }
|
||||
virtual const glm::vec3& getTranslation() const { return _translation; }
|
||||
|
||||
virtual void setMass(float mass) { _mass = mass; }
|
||||
virtual float getMass() const { return _mass; }
|
||||
|
||||
virtual bool findRayIntersection(RayIntersectionInfo& intersection) const = 0;
|
||||
|
||||
/// \param penetration of collision
|
||||
/// \param contactPoint of collision
|
||||
/// \return the effective mass for the collision
|
||||
/// For most shapes has side effects: computes and caches the partial Lagrangian coefficients which will be
|
||||
/// used in the next accumulateDelta() call.
|
||||
virtual float computeEffectiveMass(const glm::vec3& penetration, const glm::vec3& contactPoint) { return _mass; }
|
||||
|
||||
/// \param relativeMassFactor the final ingredient for partial Lagrangian coefficients from computeEffectiveMass()
|
||||
/// \param penetration the delta movement
|
||||
virtual void accumulateDelta(float relativeMassFactor, const glm::vec3& penetration) {}
|
||||
|
||||
virtual void applyAccumulatedDelta() {}
|
||||
|
||||
/// \return volume of shape in cubic meters
|
||||
virtual float getVolume() const { return 1.0; }
|
||||
|
||||
virtual QDebug& dumpToDebug(QDebug& debugConext) const;
|
||||
|
||||
protected:
|
||||
// these ctors are protected (used by derived classes only)
|
||||
Shape(Type type) : _type(type), _owningEntity(NULL),
|
||||
_boundingRadius(0.0f), _translation(0.0f),
|
||||
_rotation(), _mass(MAX_SHAPE_MASS) {
|
||||
_id = getNextID();
|
||||
}
|
||||
|
||||
Shape(Type type, const glm::vec3& position) :
|
||||
_type(type), _owningEntity(NULL),
|
||||
_boundingRadius(0.0f), _translation(position),
|
||||
_rotation(), _mass(MAX_SHAPE_MASS) {
|
||||
_id = getNextID();
|
||||
}
|
||||
|
||||
Shape(Type type, const glm::vec3& position, const glm::quat& rotation) : _type(type), _owningEntity(NULL),
|
||||
_boundingRadius(0.0f), _translation(position),
|
||||
_rotation(rotation), _mass(MAX_SHAPE_MASS) {
|
||||
_id = getNextID();
|
||||
}
|
||||
|
||||
void setBoundingRadius(float radius) { _boundingRadius = radius; }
|
||||
|
||||
Type _type;
|
||||
quint32 _id;
|
||||
PhysicsEntity* _owningEntity;
|
||||
float _boundingRadius;
|
||||
glm::vec3 _translation;
|
||||
glm::quat _rotation;
|
||||
float _mass;
|
||||
};
|
||||
|
||||
inline QDebug& Shape::dumpToDebug(QDebug& debugConext) const {
|
||||
debugConext << "Shape[ ("
|
||||
<< "type: " << getType()
|
||||
<< "position: "
|
||||
<< getTranslation().x << ", " << getTranslation().y << ", " << getTranslation().z
|
||||
<< "radius: "
|
||||
<< getBoundingRadius()
|
||||
<< "]";
|
||||
|
||||
return debugConext;
|
||||
}
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const Shape& shape) {
|
||||
return shape.dumpToDebug(debug);
|
||||
}
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const Shape* shape) {
|
||||
return shape->dumpToDebug(debug);
|
||||
}
|
||||
|
||||
|
||||
#endif // hifi_Shape_h
|
File diff suppressed because it is too large
Load diff
|
@ -1,156 +0,0 @@
|
|||
//
|
||||
// ShapeCollider.h
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrew Meadows on 02/20/2014.
|
||||
// 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_ShapeCollider_h
|
||||
#define hifi_ShapeCollider_h
|
||||
|
||||
#include <QVector>
|
||||
|
||||
#include "CollisionInfo.h"
|
||||
#include "RayIntersectionInfo.h"
|
||||
#include "SharedUtil.h"
|
||||
|
||||
|
||||
class Shape;
|
||||
class SphereShape;
|
||||
class CapsuleShape;
|
||||
|
||||
namespace ShapeCollider {
|
||||
|
||||
/// MUST CALL this FIRST before using the ShapeCollider
|
||||
void initDispatchTable();
|
||||
|
||||
/// \param shapeA pointer to first shape (cannot be NULL)
|
||||
/// \param shapeB pointer to second shape (cannot be NULL)
|
||||
/// \param collisions[out] collision details
|
||||
/// \return true if shapes collide
|
||||
bool collideShapes(const Shape* shapeA, const Shape* shapeB, CollisionList& collisions);
|
||||
|
||||
bool collideShapeWithShapes(const Shape* shapeA, const QVector<Shape*>& shapes, int startIndex, CollisionList& collisions);
|
||||
bool collideShapesWithShapes(const QVector<Shape*>& shapesA, const QVector<Shape*>& shapesB, CollisionList& collisions);
|
||||
|
||||
/// \param shapeA a pointer to a shape (cannot be NULL)
|
||||
/// \param cubeCenter center of cube
|
||||
/// \param cubeSide lenght of side of cube
|
||||
/// \param collisions[out] average collision details
|
||||
/// \return true if shapeA collides with axis aligned cube
|
||||
bool collideShapeWithAACubeLegacy(const Shape* shapeA, const glm::vec3& cubeCenter, float cubeSide, CollisionList& collisions);
|
||||
|
||||
/// \param sphereA pointer to first shape (cannot be NULL)
|
||||
/// \param sphereB pointer to second shape (cannot be NULL)
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool sphereVsSphere(const Shape* sphereA, const Shape* sphereB, CollisionList& collisions);
|
||||
|
||||
/// \param sphereA pointer to first shape (cannot be NULL)
|
||||
/// \param capsuleB pointer to second shape (cannot be NULL)
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool sphereVsCapsule(const Shape* sphereA, const Shape* capsuleB, CollisionList& collisions);
|
||||
|
||||
/// \param sphereA pointer to first shape (cannot be NULL)
|
||||
/// \param planeB pointer to second shape (cannot be NULL)
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool sphereVsPlane(const Shape* sphereA, const Shape* planeB, CollisionList& collisions);
|
||||
|
||||
/// \param capsuleA pointer to first shape (cannot be NULL)
|
||||
/// \param sphereB pointer to second shape (cannot be NULL)
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool capsuleVsSphere(const Shape* capsuleA, const Shape* sphereB, CollisionList& collisions);
|
||||
|
||||
/// \param capsuleA pointer to first shape (cannot be NULL)
|
||||
/// \param capsuleB pointer to second shape (cannot be NULL)
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool capsuleVsCapsule(const Shape* capsuleA, const Shape* capsuleB, CollisionList& collisions);
|
||||
|
||||
/// \param capsuleA pointer to first shape (cannot be NULL)
|
||||
/// \param planeB pointer to second shape (cannot be NULL)
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool capsuleVsPlane(const Shape* capsuleA, const Shape* planeB, CollisionList& collisions);
|
||||
|
||||
/// \param planeA pointer to first shape (cannot be NULL)
|
||||
/// \param sphereB pointer to second shape (cannot be NULL)
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool planeVsSphere(const Shape* planeA, const Shape* sphereB, CollisionList& collisions);
|
||||
|
||||
/// \param planeA pointer to first shape (cannot be NULL)
|
||||
/// \param capsuleB pointer to second shape (cannot be NULL)
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool planeVsCapsule(const Shape* planeA, const Shape* capsuleB, CollisionList& collisions);
|
||||
|
||||
/// \param planeA pointer to first shape (cannot be NULL)
|
||||
/// \param planeB pointer to second shape (cannot be NULL)
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool planeVsPlane(const Shape* planeA, const Shape* planeB, CollisionList& collisions);
|
||||
|
||||
/// helper function for *VsAACube() methods
|
||||
/// \param sphereCenter center of sphere
|
||||
/// \param sphereRadius radius of sphere
|
||||
/// \param cubeCenter center of AACube
|
||||
/// \param cubeSide scale of cube
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return valid pointer to CollisionInfo if sphere and cube overlap or NULL if not
|
||||
CollisionInfo* sphereVsAACubeHelper(const glm::vec3& sphereCenter, float sphereRadius,
|
||||
const glm::vec3& cubeCenter, float cubeSide, CollisionList& collisions);
|
||||
|
||||
bool sphereVsAACube(const Shape* shapeA, const Shape* shapeB, CollisionList& collisions);
|
||||
bool capsuleVsAACube(const Shape* shapeA, const Shape* shapeB, CollisionList& collisions);
|
||||
bool aaCubeVsSphere(const Shape* shapeA, const Shape* shapeB, CollisionList& collisions);
|
||||
bool aaCubeVsCapsule(const Shape* shapeA, const Shape* shapeB, CollisionList& collisions);
|
||||
bool aaCubeVsAACube(const Shape* shapeA, const Shape* shapeB, CollisionList& collisions);
|
||||
|
||||
/// \param shapeA pointer to first shape (cannot be NULL)
|
||||
/// \param listB pointer to second shape (cannot be NULL)
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool shapeVsList(const Shape* shapeA, const Shape* listB, CollisionList& collisions);
|
||||
|
||||
/// \param listA pointer to first shape (cannot be NULL)
|
||||
/// \param shapeB pointer to second shape (cannot be NULL)
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool listVsShape(const Shape* listA, const Shape* shapeB, CollisionList& collisions);
|
||||
|
||||
/// \param listA pointer to first shape (cannot be NULL)
|
||||
/// \param listB pointer to second shape (cannot be NULL)
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool listVsList(const Shape* listA, const Shape* listB, CollisionList& collisions);
|
||||
|
||||
/// \param sphereA pointer to sphere (cannot be NULL)
|
||||
/// \param cubeCenter center of cube
|
||||
/// \param cubeSide lenght of side of cube
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if sphereA collides with axis aligned cube
|
||||
bool sphereVsAACubeLegacy(const SphereShape* sphereA, const glm::vec3& cubeCenter, float cubeSide, CollisionList& collisions);
|
||||
|
||||
/// \param capsuleA pointer to capsule (cannot be NULL)
|
||||
/// \param cubeCenter center of cube
|
||||
/// \param cubeSide lenght of side of cube
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if capsuleA collides with axis aligned cube
|
||||
bool capsuleVsAACubeLegacy(const CapsuleShape* capsuleA, const glm::vec3& cubeCenter, float cubeSide, CollisionList& collisions);
|
||||
|
||||
/// \param shapes list of pointers to shapes (shape pointers may be NULL)
|
||||
/// \param intersection[out] struct with info about Ray and hit
|
||||
/// \return true if ray hits any shape in shapes
|
||||
bool findRayIntersection(const QVector<Shape*>& shapes, RayIntersectionInfo& intersection);
|
||||
|
||||
} // namespace ShapeCollider
|
||||
|
||||
#endif // hifi_ShapeCollider_h
|
|
@ -1,51 +0,0 @@
|
|||
//
|
||||
// SphereShape.cpp
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrew Meadows on 2014.06.17
|
||||
// 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 <glm/gtx/norm.hpp>
|
||||
|
||||
#include "SphereShape.h"
|
||||
|
||||
bool SphereShape::findRayIntersection(RayIntersectionInfo& intersection) const {
|
||||
float r2 = _boundingRadius * _boundingRadius;
|
||||
|
||||
// compute closest approach (CA)
|
||||
float a = glm::dot(_translation - intersection._rayStart, intersection._rayDirection); // a = distance from ray-start to CA
|
||||
float b2 = glm::distance2(_translation, intersection._rayStart + a * intersection._rayDirection); // b2 = squared distance from sphere-center to CA
|
||||
if (b2 > r2) {
|
||||
// ray does not hit sphere
|
||||
return false;
|
||||
}
|
||||
float c = sqrtf(r2 - b2); // c = distance from CA to sphere surface along intersection._rayDirection
|
||||
float d2 = glm::distance2(intersection._rayStart, _translation); // d2 = squared distance from sphere-center to ray-start
|
||||
float distance = FLT_MAX;
|
||||
if (a < 0.0f) {
|
||||
// ray points away from sphere-center
|
||||
if (d2 > r2) {
|
||||
// ray starts outside sphere
|
||||
return false;
|
||||
}
|
||||
// ray starts inside sphere
|
||||
distance = c + a;
|
||||
} else if (d2 > r2) {
|
||||
// ray starts outside sphere
|
||||
distance = a - c;
|
||||
} else {
|
||||
// ray starts inside sphere
|
||||
distance = a + c;
|
||||
}
|
||||
if (distance > 0.0f && distance < intersection._rayLength && distance < intersection._hitDistance) {
|
||||
intersection._hitDistance = distance;
|
||||
intersection._hitNormal = glm::normalize(intersection._rayStart + distance * intersection._rayDirection - _translation);
|
||||
intersection._hitShape = const_cast<SphereShape*>(this);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
//
|
||||
// SphereShape.h
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrew Meadows on 2014.
|
||||
// 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_SphereShape_h
|
||||
#define hifi_SphereShape_h
|
||||
|
||||
#include "NumericalConstants.h"
|
||||
#include "Shape.h"
|
||||
|
||||
class SphereShape : public Shape {
|
||||
public:
|
||||
SphereShape() : Shape(SPHERE_SHAPE) {}
|
||||
|
||||
SphereShape(float radius) : Shape(SPHERE_SHAPE) {
|
||||
_boundingRadius = radius;
|
||||
}
|
||||
|
||||
SphereShape(float radius, const glm::vec3& position) : Shape(SPHERE_SHAPE, position) {
|
||||
_boundingRadius = radius;
|
||||
}
|
||||
|
||||
virtual ~SphereShape() {}
|
||||
|
||||
float getRadius() const { return _boundingRadius; }
|
||||
|
||||
void setRadius(float radius) { _boundingRadius = radius; }
|
||||
|
||||
bool findRayIntersection(RayIntersectionInfo& intersection) const;
|
||||
|
||||
float getVolume() const { return 1.3333333333f * PI * _boundingRadius * _boundingRadius * _boundingRadius; }
|
||||
};
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const SphereShape& shape) {
|
||||
debug << "SphereShape[ ("
|
||||
<< "position: "
|
||||
<< shape.getTranslation().x << ", " << shape.getTranslation().y << ", " << shape.getTranslation().z
|
||||
<< "radius: "
|
||||
<< shape.getRadius()
|
||||
<< "]";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const SphereShape* shape) {
|
||||
debug << "SphereShape[ ("
|
||||
<< "center: "
|
||||
<< shape->getTranslation().x << ", " << shape->getTranslation().y << ", " << shape->getTranslation().z
|
||||
<< "radius: "
|
||||
<< shape->getRadius()
|
||||
<< "]";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
||||
#endif // hifi_SphereShape_h
|
|
@ -65,38 +65,6 @@ QDataStream& operator>>(QDataStream& in, glm::quat& quaternion) {
|
|||
return in >> quaternion.x >> quaternion.y >> quaternion.z >> quaternion.w;
|
||||
}
|
||||
|
||||
// less common utils can be enabled with DEBUG
|
||||
// FIXME, remove the second defined clause once these compile, or remove the
|
||||
// functions.
|
||||
#if defined(DEBUG) && defined(FIXED_STREAMS)
|
||||
|
||||
std::ostream& operator<<(std::ostream& s, const CollisionInfo& c) {
|
||||
s << "{penetration=" << c._penetration
|
||||
<< ", contactPoint=" << c._contactPoint
|
||||
<< ", addedVelocity=" << c._addedVelocity
|
||||
<< "}";
|
||||
return s;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& s, const SphereShape& sphere) {
|
||||
s << "{type='sphere', center=" << sphere.getPosition()
|
||||
<< ", radius=" << sphere.getRadius()
|
||||
<< "}";
|
||||
return s;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& s, const CapsuleShape& capsule) {
|
||||
s << "{type='capsule', center=" << capsule.getPosition()
|
||||
<< ", radius=" << capsule.getRadius()
|
||||
<< ", length=" << (2.0f * capsule.getHalfHeight())
|
||||
<< ", begin=" << capsule.getStartPoint()
|
||||
<< ", end=" << capsule.getEndPoint()
|
||||
<< "}";
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif // DEBUG
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
#include <QDebug>
|
||||
|
||||
|
|
|
@ -37,16 +37,6 @@ QDataStream& operator>>(QDataStream& in, glm::vec3& vector);
|
|||
QDataStream& operator<<(QDataStream& out, const glm::quat& quaternion);
|
||||
QDataStream& operator>>(QDataStream& in, glm::quat& quaternion);
|
||||
|
||||
// less common utils can be enabled with DEBUG
|
||||
#ifdef DEBUG
|
||||
class CollisionInfo;
|
||||
class SphereShape;
|
||||
class CapsuleShape;
|
||||
std::ostream& operator<<(std::ostream& s, const CollisionInfo& c);
|
||||
std::ostream& operator<<(std::ostream& s, const SphereShape& shape);
|
||||
std::ostream& operator<<(std::ostream& s, const CapsuleShape& capsule);
|
||||
#endif // DEBUG
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
class QDebug;
|
||||
// Add support for writing these to qDebug().
|
||||
|
|
160
tests/shared/src/GeometryUtilTests.cpp
Normal file
160
tests/shared/src/GeometryUtilTests.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
//
|
||||
// GeometryUtilTests.cpp
|
||||
// tests/physics/src
|
||||
//
|
||||
// Created by Andrew Meadows on 2015.07.27
|
||||
// Copyright 2015 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 "GeometryUtilTests.h"
|
||||
|
||||
#include <GeometryUtil.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <StreamUtils.h>
|
||||
|
||||
#include <../QTestExtensions.h>
|
||||
|
||||
|
||||
QTEST_MAIN(GeometryUtilTests)
|
||||
|
||||
float getErrorDifference(const float& a, const float& b) {
|
||||
return fabsf(a - b);
|
||||
}
|
||||
|
||||
float getErrorDifference(const glm::vec3& a, const glm::vec3& b) {
|
||||
return glm::distance(a, b);
|
||||
}
|
||||
|
||||
void GeometryUtilTests::testLocalRayRectangleIntersection() {
|
||||
glm::vec3 xAxis(1.0f, 0.0f, 0.0f);
|
||||
glm::vec3 yAxis(0.0f, 1.0f, 0.0f);
|
||||
glm::vec3 zAxis(0.0f, 0.0f, 1.0f);
|
||||
|
||||
// create a rectangle in the local frame on the XY plane with normal along -zAxis
|
||||
// (this is the assumed local orientation of the rectangle in findRayRectangleIntersection())
|
||||
glm::vec2 rectDimensions(3.0f, 5.0f);
|
||||
glm::vec3 rectCenter(0.0f, 0.0f, 0.0f);
|
||||
glm::quat rectRotation = glm::quat(); // identity
|
||||
|
||||
// create points for generating rays that hit the plane and don't
|
||||
glm::vec3 rayStart(1.0f, 2.0f, 3.0f);
|
||||
float delta = 0.1f;
|
||||
|
||||
{ // verify hit
|
||||
glm::vec3 rayEnd = rectCenter + rectRotation * ((0.5f * rectDimensions.x - delta) * xAxis);
|
||||
glm::vec3 rayHitDirection = glm::normalize(rayEnd - rayStart);
|
||||
float expectedDistance = glm::length(rayEnd - rayStart);
|
||||
|
||||
float distance = FLT_MAX;
|
||||
bool hit = findRayRectangleIntersection(rayStart, rayHitDirection, rectRotation, rectCenter, rectDimensions, distance);
|
||||
QCOMPARE(hit, true);
|
||||
QCOMPARE_WITH_ABS_ERROR(distance, expectedDistance, EPSILON);
|
||||
}
|
||||
|
||||
{ // verify miss
|
||||
glm::vec3 rayEnd = rectCenter + rectRotation * ((0.5f * rectDimensions.y + delta) * yAxis);
|
||||
glm::vec3 rayMissDirection = glm::normalize(rayEnd - rayStart);
|
||||
float distance = FLT_MAX;
|
||||
bool hit = findRayRectangleIntersection(rayStart, rayMissDirection, rectRotation, rectCenter, rectDimensions, distance);
|
||||
QCOMPARE(hit, false);
|
||||
QCOMPARE(distance, FLT_MAX); // distance should be unchanged
|
||||
}
|
||||
|
||||
{ // hit with co-planer line
|
||||
float yFraction = 0.25f;
|
||||
rayStart = rectCenter + rectRotation * (rectDimensions.x * xAxis + yFraction * rectDimensions.y * yAxis);
|
||||
|
||||
glm::vec3 rayEnd = rectCenter - rectRotation * (rectDimensions.x * xAxis + yFraction * rectDimensions.y * yAxis);
|
||||
glm::vec3 rayHitDirection = glm::normalize(rayEnd - rayStart);
|
||||
float expectedDistance = rectDimensions.x;
|
||||
|
||||
float distance = FLT_MAX;
|
||||
bool hit = findRayRectangleIntersection(rayStart, rayHitDirection, rectRotation, rectCenter, rectDimensions, distance);
|
||||
QCOMPARE(hit, true);
|
||||
QCOMPARE_WITH_ABS_ERROR(distance, expectedDistance, EPSILON);
|
||||
}
|
||||
|
||||
{ // miss with co-planer line
|
||||
float yFraction = 0.75f;
|
||||
rayStart = rectCenter + rectRotation * (rectDimensions.x * xAxis + (yFraction * rectDimensions.y) * yAxis);
|
||||
|
||||
glm::vec3 rayEnd = rectCenter + rectRotation * (- rectDimensions.x * xAxis + (yFraction * rectDimensions.y) * yAxis);
|
||||
glm::vec3 rayHitDirection = glm::normalize(rayEnd - rayStart);
|
||||
|
||||
float distance = FLT_MAX;
|
||||
bool hit = findRayRectangleIntersection(rayStart, rayHitDirection, rectRotation, rectCenter, rectDimensions, distance);
|
||||
QCOMPARE(hit, false);
|
||||
QCOMPARE(distance, FLT_MAX); // distance should be unchanged
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryUtilTests::testWorldRayRectangleIntersection() {
|
||||
glm::vec3 xAxis(1.0f, 0.0f, 0.0f);
|
||||
glm::vec3 yAxis(0.0f, 1.0f, 0.0f);
|
||||
glm::vec3 zAxis(0.0f, 0.0f, 1.0f);
|
||||
|
||||
// create a rectangle in the local frame on the XY plane with normal along -zAxis
|
||||
// (this is the assumed local orientation of the rectangle in findRayRectangleIntersection())
|
||||
// and then rotate and shift everything into the world frame
|
||||
glm::vec2 rectDimensions(3.0f, 5.0f);
|
||||
glm::vec3 rectCenter(0.7f, 0.5f, -0.3f);
|
||||
glm::quat rectRotation = glm::quat(); // identity
|
||||
|
||||
|
||||
// create points for generating rays that hit the plane and don't
|
||||
glm::vec3 rayStart(1.0f, 2.0f, 3.0f);
|
||||
float delta = 0.1f;
|
||||
|
||||
{ // verify hit
|
||||
glm::vec3 rayEnd = rectCenter + rectRotation * ((0.5f * rectDimensions.x - delta) * xAxis);
|
||||
glm::vec3 rayHitDirection = glm::normalize(rayEnd - rayStart);
|
||||
float expectedDistance = glm::length(rayEnd - rayStart);
|
||||
|
||||
float distance = FLT_MAX;
|
||||
bool hit = findRayRectangleIntersection(rayStart, rayHitDirection, rectRotation, rectCenter, rectDimensions, distance);
|
||||
QCOMPARE(hit, true);
|
||||
QCOMPARE_WITH_ABS_ERROR(distance, expectedDistance, EPSILON);
|
||||
}
|
||||
|
||||
{ // verify miss
|
||||
glm::vec3 rayEnd = rectCenter + rectRotation * ((0.5f * rectDimensions.y + delta) * yAxis);
|
||||
glm::vec3 rayMissDirection = glm::normalize(rayEnd - rayStart);
|
||||
float distance = FLT_MAX;
|
||||
bool hit = findRayRectangleIntersection(rayStart, rayMissDirection, rectRotation, rectCenter, rectDimensions, distance);
|
||||
QCOMPARE(hit, false);
|
||||
QCOMPARE(distance, FLT_MAX); // distance should be unchanged
|
||||
}
|
||||
|
||||
{ // hit with co-planer line
|
||||
float yFraction = 0.25f;
|
||||
rayStart = rectCenter + rectRotation * (rectDimensions.x * xAxis + (yFraction * rectDimensions.y) * yAxis);
|
||||
|
||||
glm::vec3 rayEnd = rectCenter - rectRotation * (rectDimensions.x * xAxis + (yFraction * rectDimensions.y) * yAxis);
|
||||
glm::vec3 rayHitDirection = glm::normalize(rayEnd - rayStart);
|
||||
float expectedDistance = rectDimensions.x;
|
||||
|
||||
float distance = FLT_MAX;
|
||||
bool hit = findRayRectangleIntersection(rayStart, rayHitDirection, rectRotation, rectCenter, rectDimensions, distance);
|
||||
QCOMPARE(hit, true);
|
||||
QCOMPARE_WITH_ABS_ERROR(distance, expectedDistance, EPSILON);
|
||||
}
|
||||
|
||||
{ // miss with co-planer line
|
||||
float yFraction = 0.75f;
|
||||
rayStart = rectCenter + rectRotation * (rectDimensions.x * xAxis + (yFraction * rectDimensions.y) * yAxis);
|
||||
|
||||
glm::vec3 rayEnd = rectCenter + rectRotation * (-rectDimensions.x * xAxis + (yFraction * rectDimensions.y) * yAxis);
|
||||
glm::vec3 rayHitDirection = glm::normalize(rayEnd - rayStart);
|
||||
|
||||
float distance = FLT_MAX;
|
||||
bool hit = findRayRectangleIntersection(rayStart, rayHitDirection, rectRotation, rectCenter, rectDimensions, distance);
|
||||
QCOMPARE(hit, false);
|
||||
QCOMPARE(distance, FLT_MAX); // distance should be unchanged
|
||||
}
|
||||
}
|
||||
|
28
tests/shared/src/GeometryUtilTests.h
Normal file
28
tests/shared/src/GeometryUtilTests.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
//
|
||||
// GeometryUtilTests.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 <QtTest/QtTest>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class GeometryUtilTests : public QObject {
|
||||
Q_OBJECT
|
||||
private slots:
|
||||
void testLocalRayRectangleIntersection();
|
||||
void testWorldRayRectangleIntersection();
|
||||
};
|
||||
|
||||
float getErrorDifference(const float& a, const float& b);
|
||||
float getErrorDifference(const glm::vec3& a, const glm::vec3& b);
|
||||
|
||||
#endif // hifi_AngularConstraintTests_h
|
Loading…
Reference in a new issue