mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 01:37:02 +02:00
Merge pull request #1452 from ey6es/master
First cut at orbit behavior (plus ray/capsule intersection test for avatar picking).
This commit is contained in:
commit
607d8332e3
11 changed files with 170 additions and 22 deletions
|
@ -1105,9 +1105,24 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activeWindow() == _window) {
|
if (activeWindow() == _window) {
|
||||||
|
int deltaX = event->x() - _mouseX;
|
||||||
|
int deltaY = event->y() - _mouseY;
|
||||||
|
|
||||||
_mouseX = event->x();
|
_mouseX = event->x();
|
||||||
_mouseY = event->y();
|
_mouseY = event->y();
|
||||||
|
|
||||||
|
// orbit behavior
|
||||||
|
if (_mousePressed && !Menu::getInstance()->isVoxelModeActionChecked()) {
|
||||||
|
if (_lookatTargetAvatar) {
|
||||||
|
_myAvatar.orbit(_lookatTargetAvatar->getPosition(), deltaX, deltaY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_isHoverVoxel) {
|
||||||
|
_myAvatar.orbit(glm::vec3(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z) * (float)TREE_SCALE, deltaX, deltaY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// detect drag
|
// detect drag
|
||||||
glm::vec3 mouseVoxelPos(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z);
|
glm::vec3 mouseVoxelPos(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z);
|
||||||
if (!_justEditedVoxel && mouseVoxelPos != _lastMouseVoxelPos) {
|
if (!_justEditedVoxel && mouseVoxelPos != _lastMouseVoxelPos) {
|
||||||
|
@ -1151,7 +1166,8 @@ void Application::mousePressEvent(QMouseEvent* event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_palette.isActive() && (!_isHoverVoxel || _lookatTargetAvatar)) {
|
if (!_palette.isActive() && (!_isHoverVoxel || _lookatTargetAvatar)) {
|
||||||
_pieMenu.mousePressEvent(_mouseX, _mouseY);
|
// disable for now
|
||||||
|
// _pieMenu.mousePressEvent(_mouseX, _mouseY);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode) && _pasteMode) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode) && _pasteMode) {
|
||||||
|
@ -1952,7 +1968,9 @@ void Application::updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, cons
|
||||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||||
PerformanceWarning warn(showWarnings, "Application::updateLookatTargetAvatar()");
|
PerformanceWarning warn(showWarnings, "Application::updateLookatTargetAvatar()");
|
||||||
|
|
||||||
_lookatTargetAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePosition, DEFAULT_NODE_ID_REF);
|
if (!_mousePressed) {
|
||||||
|
_lookatTargetAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePosition, DEFAULT_NODE_ID_REF);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
||||||
|
@ -1961,17 +1979,15 @@ Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, con
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||||
if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) {
|
if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) {
|
||||||
Avatar* avatar = (Avatar *) node->getLinkedData();
|
Avatar* avatar = (Avatar*)node->getLinkedData();
|
||||||
glm::vec3 headPosition = avatar->getHead().getPosition();
|
|
||||||
float distance;
|
float distance;
|
||||||
if (rayIntersectsSphere(mouseRayOrigin, mouseRayDirection, headPosition,
|
if (avatar->findRayIntersection(mouseRayOrigin, mouseRayDirection, distance)) {
|
||||||
HEAD_SPHERE_RADIUS * avatar->getHead().getScale(), distance)) {
|
|
||||||
// rescale to compensate for head embiggening
|
// rescale to compensate for head embiggening
|
||||||
eyePosition = (avatar->getHead().calculateAverageEyePosition() - avatar->getHead().getScalePivot()) *
|
eyePosition = (avatar->getHead().calculateAverageEyePosition() - avatar->getHead().getScalePivot()) *
|
||||||
(avatar->getScale() / avatar->getHead().getScale()) + avatar->getHead().getScalePivot();
|
(avatar->getScale() / avatar->getHead().getScale()) + avatar->getHead().getScalePivot();
|
||||||
|
|
||||||
_lookatIndicatorScale = avatar->getHead().getScale();
|
_lookatIndicatorScale = avatar->getHead().getScale();
|
||||||
_lookatOtherPosition = headPosition;
|
_lookatOtherPosition = avatar->getHead().getPosition();
|
||||||
nodeUUID = avatar->getOwningNode()->getUUID();
|
nodeUUID = avatar->getOwningNode()->getUUID();
|
||||||
return avatar;
|
return avatar;
|
||||||
}
|
}
|
||||||
|
@ -2213,7 +2229,7 @@ void Application::updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin,
|
||||||
glm::vec4 oldVoxel(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s);
|
glm::vec4 oldVoxel(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s);
|
||||||
// only do this work if MAKE_SOUND_ON_VOXEL_HOVER or MAKE_SOUND_ON_VOXEL_CLICK is enabled,
|
// only do this work if MAKE_SOUND_ON_VOXEL_HOVER or MAKE_SOUND_ON_VOXEL_CLICK is enabled,
|
||||||
// and make sure the tree is not already busy... because otherwise you'll have to wait.
|
// and make sure the tree is not already busy... because otherwise you'll have to wait.
|
||||||
if (!_voxels.treeIsBusy()) {
|
if (!(_voxels.treeIsBusy() || _mousePressed)) {
|
||||||
{
|
{
|
||||||
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels() _voxels.findRayIntersection()");
|
PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels() _voxels.findRayIntersection()");
|
||||||
_isHoverVoxel = _voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _hoverVoxel, distance, face);
|
_isHoverVoxel = _voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _hoverVoxel, distance, face);
|
||||||
|
|
|
@ -190,10 +190,6 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
|
||||||
// update avatar skeleton
|
// update avatar skeleton
|
||||||
_skeleton.update(deltaTime, getOrientation(), _position);
|
_skeleton.update(deltaTime, getOrientation(), _position);
|
||||||
|
|
||||||
|
|
||||||
// if this is not my avatar, then hand position comes from transmitted data
|
|
||||||
_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = _handPosition;
|
|
||||||
|
|
||||||
_hand.simulate(deltaTime, false);
|
_hand.simulate(deltaTime, false);
|
||||||
_skeletonModel.simulate(deltaTime);
|
_skeletonModel.simulate(deltaTime);
|
||||||
_head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll));
|
_head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll));
|
||||||
|
@ -340,8 +336,24 @@ void Avatar::getSkinColors(glm::vec3& lighter, glm::vec3& darker) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Avatar::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
|
||||||
|
float minDistance = FLT_MAX;
|
||||||
|
float modelDistance;
|
||||||
|
if (_skeletonModel.findRayIntersection(origin, direction, modelDistance)) {
|
||||||
|
minDistance = qMin(minDistance, modelDistance);
|
||||||
|
}
|
||||||
|
if (_head.getFaceModel().findRayIntersection(origin, direction, modelDistance)) {
|
||||||
|
minDistance = qMin(minDistance, modelDistance);
|
||||||
|
}
|
||||||
|
if (minDistance < FLT_MAX) {
|
||||||
|
distance = minDistance;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Avatar::findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
bool Avatar::findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||||
glm::vec3& penetration, int skeletonSkipIndex) {
|
glm::vec3& penetration, int skeletonSkipIndex) const {
|
||||||
bool didPenetrate = false;
|
bool didPenetrate = false;
|
||||||
glm::vec3 totalPenetration;
|
glm::vec3 totalPenetration;
|
||||||
glm::vec3 skeletonPenetration;
|
glm::vec3 skeletonPenetration;
|
||||||
|
|
|
@ -160,6 +160,8 @@ public:
|
||||||
|
|
||||||
void getSkinColors(glm::vec3& lighter, glm::vec3& darker);
|
void getSkinColors(glm::vec3& lighter, glm::vec3& darker);
|
||||||
|
|
||||||
|
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
|
||||||
|
|
||||||
/// Checks for penetration between the described sphere and the avatar.
|
/// Checks for penetration between the described sphere and the avatar.
|
||||||
/// \param penetratorCenter the center of the penetration test sphere
|
/// \param penetratorCenter the center of the penetration test sphere
|
||||||
/// \param penetratorRadius the radius of the penetration test sphere
|
/// \param penetratorRadius the radius of the penetration test sphere
|
||||||
|
@ -167,7 +169,7 @@ public:
|
||||||
/// \param skeletonSkipIndex if not -1, the index of a joint to skip (along with its descendents) in the skeleton model
|
/// \param skeletonSkipIndex if not -1, the index of a joint to skip (along with its descendents) in the skeleton model
|
||||||
/// \return whether or not the sphere penetrated
|
/// \return whether or not the sphere penetrated
|
||||||
bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||||
glm::vec3& penetration, int skeletonSkipIndex = -1);
|
glm::vec3& penetration, int skeletonSkipIndex = -1) const;
|
||||||
|
|
||||||
virtual int parseData(unsigned char* sourceBuffer, int numBytes);
|
virtual int parseData(unsigned char* sourceBuffer, int numBytes);
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,7 @@ public:
|
||||||
|
|
||||||
VideoFace& getVideoFace() { return _videoFace; }
|
VideoFace& getVideoFace() { return _videoFace; }
|
||||||
FaceModel& getFaceModel() { return _faceModel; }
|
FaceModel& getFaceModel() { return _faceModel; }
|
||||||
|
const FaceModel& getFaceModel() const { return _faceModel; }
|
||||||
|
|
||||||
const bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected)
|
const bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected)
|
||||||
float getAverageLoudness() const { return _averageLoudness; }
|
float getAverageLoudness() const { return _averageLoudness; }
|
||||||
|
|
|
@ -542,6 +542,16 @@ void MyAvatar::loadData(QSettings* settings) {
|
||||||
settings->endGroup();
|
settings->endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyAvatar::orbit(const glm::vec3& position, int deltaX, int deltaY) {
|
||||||
|
glm::vec3 vector = getPosition() - position;
|
||||||
|
glm::quat orientation = getOrientation();
|
||||||
|
glm::vec3 up = orientation * IDENTITY_UP;
|
||||||
|
const float ANGULAR_SCALE = 0.5f;
|
||||||
|
glm::quat rotation = glm::angleAxis(deltaX * -ANGULAR_SCALE, up);
|
||||||
|
const float LINEAR_SCALE = 0.01f;
|
||||||
|
setPosition(position + rotation * vector + up * (deltaY * LINEAR_SCALE * _scale));
|
||||||
|
setOrientation(rotation * orientation);
|
||||||
|
}
|
||||||
|
|
||||||
float MyAvatar::getAbsoluteHeadYaw() const {
|
float MyAvatar::getAbsoluteHeadYaw() const {
|
||||||
return glm::yaw(_head.getOrientation());
|
return glm::yaw(_head.getOrientation());
|
||||||
|
@ -757,15 +767,11 @@ void MyAvatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMov
|
||||||
glm::vec3 farVector = _mouseRayOrigin + pointDirection * (float)TREE_SCALE - shoulderPosition;
|
glm::vec3 farVector = _mouseRayOrigin + pointDirection * (float)TREE_SCALE - shoulderPosition;
|
||||||
const float ARM_RETRACTION = 0.75f;
|
const float ARM_RETRACTION = 0.75f;
|
||||||
float retractedLength = _skeletonModel.getRightArmLength() * ARM_RETRACTION;
|
float retractedLength = _skeletonModel.getRightArmLength() * ARM_RETRACTION;
|
||||||
_skeleton.joint[AVATAR_JOINT_RIGHT_FINGERTIPS].position = shoulderPosition +
|
setHandPosition(shoulderPosition + glm::normalize(farVector) * retractedLength);
|
||||||
glm::normalize(farVector) * retractedLength;
|
|
||||||
pointing = true;
|
pointing = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Set right hand position and state to be transmitted, and also tell AvatarTouch about it
|
|
||||||
setHandPosition(_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position);
|
|
||||||
|
|
||||||
if (_mousePressed) {
|
if (_mousePressed) {
|
||||||
_handState = HAND_STATE_GRASPING;
|
_handState = HAND_STATE_GRASPING;
|
||||||
} else if (pointing) {
|
} else if (pointing) {
|
||||||
|
@ -919,8 +925,9 @@ void MyAvatar::updateChatCircle(float deltaTime) {
|
||||||
// remove members whose accumulated circles are too far away to influence us
|
// remove members whose accumulated circles are too far away to influence us
|
||||||
const float CIRCUMFERENCE_PER_MEMBER = 0.5f;
|
const float CIRCUMFERENCE_PER_MEMBER = 0.5f;
|
||||||
const float CIRCLE_INFLUENCE_SCALE = 2.0f;
|
const float CIRCLE_INFLUENCE_SCALE = 2.0f;
|
||||||
|
const float MIN_RADIUS = 0.3f;
|
||||||
for (int i = sortedAvatars.size() - 1; i >= 0; i--) {
|
for (int i = sortedAvatars.size() - 1; i >= 0; i--) {
|
||||||
float radius = (CIRCUMFERENCE_PER_MEMBER * (i + 2)) / PI_TIMES_TWO;
|
float radius = qMax(MIN_RADIUS, (CIRCUMFERENCE_PER_MEMBER * (i + 2)) / PI_TIMES_TWO);
|
||||||
if (glm::distance(_position, sortedAvatars[i].accumulatedCenter) > radius * CIRCLE_INFLUENCE_SCALE) {
|
if (glm::distance(_position, sortedAvatars[i].accumulatedCenter) > radius * CIRCLE_INFLUENCE_SCALE) {
|
||||||
sortedAvatars.remove(i);
|
sortedAvatars.remove(i);
|
||||||
} else {
|
} else {
|
||||||
|
@ -931,7 +938,7 @@ void MyAvatar::updateChatCircle(float deltaTime) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
center = sortedAvatars.last().accumulatedCenter;
|
center = sortedAvatars.last().accumulatedCenter;
|
||||||
float radius = (CIRCUMFERENCE_PER_MEMBER * (sortedAvatars.size() + 1)) / PI_TIMES_TWO;
|
float radius = qMax(MIN_RADIUS, (CIRCUMFERENCE_PER_MEMBER * (sortedAvatars.size() + 1)) / PI_TIMES_TWO);
|
||||||
|
|
||||||
// compute the average up vector
|
// compute the average up vector
|
||||||
glm::vec3 up = getWorldAlignedOrientation() * IDENTITY_UP;
|
glm::vec3 up = getWorldAlignedOrientation() * IDENTITY_UP;
|
||||||
|
|
|
@ -69,6 +69,8 @@ public:
|
||||||
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
|
void addThrust(glm::vec3 newThrust) { _thrust += newThrust; };
|
||||||
glm::vec3 getThrust() { return _thrust; };
|
glm::vec3 getThrust() { return _thrust; };
|
||||||
|
|
||||||
|
void orbit(const glm::vec3& position, int deltaX, int deltaY);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _mousePressed;
|
bool _mousePressed;
|
||||||
float _bodyPitchDelta;
|
float _bodyPitchDelta;
|
||||||
|
|
|
@ -546,6 +546,35 @@ glm::vec4 Model::computeAverageColor() const {
|
||||||
return _geometry ? _geometry->computeAverageColor() : glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
return _geometry ? _geometry->computeAverageColor() : glm::vec4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Model::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
|
||||||
|
const glm::vec3 relativeOrigin = origin - _translation;
|
||||||
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
|
float minDistance = FLT_MAX;
|
||||||
|
float radiusScale = extractUniformScale(_scale);
|
||||||
|
for (int i = 0; i < _jointStates.size(); i++) {
|
||||||
|
const FBXJoint& joint = geometry.joints[i];
|
||||||
|
glm::vec3 end = extractTranslation(_jointStates[i].transform);
|
||||||
|
float endRadius = joint.boneRadius * radiusScale;
|
||||||
|
glm::vec3 start = end;
|
||||||
|
float startRadius = joint.boneRadius * radiusScale;
|
||||||
|
if (joint.parentIndex != -1) {
|
||||||
|
start = extractTranslation(_jointStates[joint.parentIndex].transform);
|
||||||
|
startRadius = geometry.joints[joint.parentIndex].boneRadius * radiusScale;
|
||||||
|
}
|
||||||
|
// for now, use average of start and end radii
|
||||||
|
float capsuleDistance;
|
||||||
|
if (findRayCapsuleIntersection(relativeOrigin, direction, start, end,
|
||||||
|
(startRadius + endRadius) / 2.0f, capsuleDistance)) {
|
||||||
|
minDistance = qMin(minDistance, capsuleDistance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (minDistance < FLT_MAX) {
|
||||||
|
distance = minDistance;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Model::findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
bool Model::findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||||
glm::vec3& penetration, float boneScale, int skipIndex) const {
|
glm::vec3& penetration, float boneScale, int skipIndex) const {
|
||||||
const glm::vec3 relativeCenter = penetratorCenter - _translation;
|
const glm::vec3 relativeCenter = penetratorCenter - _translation;
|
||||||
|
|
|
@ -125,6 +125,8 @@ public:
|
||||||
/// Returns the average color of all meshes in the geometry.
|
/// Returns the average color of all meshes in the geometry.
|
||||||
glm::vec4 computeAverageColor() const;
|
glm::vec4 computeAverageColor() const;
|
||||||
|
|
||||||
|
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
|
||||||
|
|
||||||
bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||||
glm::vec3& penetration, float boneScale = 1.0f, int skipIndex = -1) const;
|
glm::vec3& penetration, float boneScale = 1.0f, int skipIndex = -1) const;
|
||||||
|
|
||||||
|
|
|
@ -115,7 +115,7 @@ public:
|
||||||
/// \param skeletonSkipIndex if not -1, the index of a joint to skip (along with its descendents) in the skeleton model
|
/// \param skeletonSkipIndex if not -1, the index of a joint to skip (along with its descendents) in the skeleton model
|
||||||
/// \return whether or not the sphere penetrated
|
/// \return whether or not the sphere penetrated
|
||||||
virtual bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
virtual bool findSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||||
glm::vec3& penetration, int skeletonSkipIndex = -1) { return false; }
|
glm::vec3& penetration, int skeletonSkipIndex = -1) const { return false; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QUuid _uuid;
|
QUuid _uuid;
|
||||||
|
|
|
@ -154,6 +154,77 @@ glm::vec3 addPenetrations(const glm::vec3& currentPenetration, const glm::vec3&
|
||||||
newPenetration - (currentDirection * directionalComponent);
|
newPenetration - (currentDirection * directionalComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool findRaySphereIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||||
|
const glm::vec3& center, float radius, float& distance) {
|
||||||
|
glm::vec3 relativeOrigin = origin - center;
|
||||||
|
float c = glm::dot(relativeOrigin, relativeOrigin) - radius * radius;
|
||||||
|
if (c < 0.0f) {
|
||||||
|
distance = 0.0f;
|
||||||
|
return true; // starts inside the sphere
|
||||||
|
}
|
||||||
|
float b = glm::dot(direction, relativeOrigin);
|
||||||
|
float radicand = b * b - c;
|
||||||
|
if (radicand < 0.0f) {
|
||||||
|
return false; // doesn't hit the sphere
|
||||||
|
}
|
||||||
|
float t = -b - sqrtf(radicand);
|
||||||
|
if (t < 0.0f) {
|
||||||
|
return false; // doesn't hit the sphere
|
||||||
|
}
|
||||||
|
distance = t;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool findRayCapsuleIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||||
|
const glm::vec3& start, const glm::vec3& end, float radius, float& distance) {
|
||||||
|
if (start == end) {
|
||||||
|
return findRaySphereIntersection(origin, direction, start, radius, distance); // handle degenerate case
|
||||||
|
}
|
||||||
|
glm::vec3 relativeOrigin = origin - start;
|
||||||
|
glm::vec3 relativeEnd = end - start;
|
||||||
|
float capsuleLength = glm::length(relativeEnd);
|
||||||
|
relativeEnd /= capsuleLength;
|
||||||
|
float originProjection = glm::dot(relativeEnd, relativeOrigin);
|
||||||
|
glm::vec3 constant = relativeOrigin - relativeEnd * originProjection;
|
||||||
|
float c = glm::dot(constant, constant) - radius * radius;
|
||||||
|
if (c < 0.0f) { // starts inside cylinder
|
||||||
|
if (originProjection < 0.0f) { // below start
|
||||||
|
return findRaySphereIntersection(origin, direction, start, radius, distance);
|
||||||
|
|
||||||
|
} else if (originProjection > capsuleLength) { // above end
|
||||||
|
return findRaySphereIntersection(origin, direction, end, radius, distance);
|
||||||
|
|
||||||
|
} else { // between start and end
|
||||||
|
distance = 0.0f;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glm::vec3 coefficient = direction - relativeEnd * glm::dot(relativeEnd, direction);
|
||||||
|
float a = glm::dot(coefficient, coefficient);
|
||||||
|
if (a == 0.0f) {
|
||||||
|
return false; // parallel to enclosing cylinder
|
||||||
|
}
|
||||||
|
float b = 2.0f * glm::dot(constant, coefficient);
|
||||||
|
float radicand = b * b - 4.0f * a * c;
|
||||||
|
if (radicand < 0.0f) {
|
||||||
|
return false; // doesn't hit the enclosing cylinder
|
||||||
|
}
|
||||||
|
float t = (-b - sqrtf(radicand)) / (2.0f * a);
|
||||||
|
if (t < 0.0f) {
|
||||||
|
return false; // doesn't hit the enclosing cylinder
|
||||||
|
}
|
||||||
|
glm::vec3 intersection = relativeOrigin + direction * t;
|
||||||
|
float intersectionProjection = glm::dot(relativeEnd, intersection);
|
||||||
|
if (intersectionProjection < 0.0f) { // below start
|
||||||
|
return findRaySphereIntersection(origin, direction, start, radius, distance);
|
||||||
|
|
||||||
|
} else if (intersectionProjection > capsuleLength) { // above end
|
||||||
|
return findRaySphereIntersection(origin, direction, end, radius, distance);
|
||||||
|
}
|
||||||
|
distance = t; // between start and end
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Do line segments (r1p1.x, r1p1.y)--(r1p2.x, r1p2.y) and (r2p1.x, r2p1.y)--(r2p2.x, r2p2.y) intersect?
|
// Do line segments (r1p1.x, r1p1.y)--(r1p2.x, r1p2.y) and (r2p1.x, r2p1.y)--(r2p2.x, r2p2.y) intersect?
|
||||||
// from: http://ptspts.blogspot.com/2010/06/how-to-determine-if-two-line-segments.html
|
// from: http://ptspts.blogspot.com/2010/06/how-to-determine-if-two-line-segments.html
|
||||||
bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2) {
|
bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2) {
|
||||||
|
|
|
@ -49,6 +49,12 @@ bool findCapsulePlanePenetration(const glm::vec3& penetratorStart, const glm::ve
|
||||||
|
|
||||||
glm::vec3 addPenetrations(const glm::vec3& currentPenetration, const glm::vec3& newPenetration);
|
glm::vec3 addPenetrations(const glm::vec3& currentPenetration, const glm::vec3& newPenetration);
|
||||||
|
|
||||||
|
bool findRaySphereIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||||
|
const glm::vec3& center, float radius, float& distance);
|
||||||
|
|
||||||
|
bool findRayCapsuleIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||||
|
const glm::vec3& start, const glm::vec3& end, float radius, float& distance);
|
||||||
|
|
||||||
bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2);
|
bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2);
|
||||||
bool isOnSegment(float xi, float yi, float xj, float yj, float xk, float yk);
|
bool isOnSegment(float xi, float yi, float xj, float yj, float xk, float yk);
|
||||||
int computeDirection(float xi, float yi, float xj, float yj, float xk, float yk);
|
int computeDirection(float xi, float yi, float xj, float yj, float xk, float yk);
|
||||||
|
|
Loading…
Reference in a new issue