This commit is contained in:
Andrzej Kapolka 2014-01-10 17:52:51 -08:00
commit eb4cb0c8e7
12 changed files with 276 additions and 269 deletions

View file

@ -24,12 +24,8 @@ const long long ASSIGNMENT_REQUEST_INTERVAL_MSECS = 1 * 1000;
int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr"); int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr");
AssignmentClient::AssignmentClient(int &argc, char **argv, AssignmentClient::AssignmentClient(int &argc, char **argv) :
Assignment::Type requestAssignmentType,
const HifiSockAddr& customAssignmentServerSocket,
const char* requestAssignmentPool) :
QCoreApplication(argc, argv), QCoreApplication(argc, argv),
_requestAssignment(Assignment::RequestCommand, requestAssignmentType, requestAssignmentPool),
_currentAssignment(NULL) _currentAssignment(NULL)
{ {
// register meta type is required for queued invoke method on Assignment subclasses // register meta type is required for queued invoke method on Assignment subclasses
@ -37,12 +33,53 @@ AssignmentClient::AssignmentClient(int &argc, char **argv,
// set the logging target to the the CHILD_TARGET_NAME // set the logging target to the the CHILD_TARGET_NAME
Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME);
const char ASSIGNMENT_TYPE_OVVERIDE_OPTION[] = "-t";
const char* assignmentTypeString = getCmdOption(argc, (const char**)argv, ASSIGNMENT_TYPE_OVVERIDE_OPTION);
Assignment::Type requestAssignmentType = Assignment::AllTypes;
if (assignmentTypeString) {
// the user is asking to only be assigned to a particular type of assignment
// so set that as the ::overridenAssignmentType to be used in requests
requestAssignmentType = (Assignment::Type) atoi(assignmentTypeString);
}
const char ASSIGNMENT_POOL_OPTION[] = "--pool";
const char* requestAssignmentPool = getCmdOption(argc, (const char**) argv, ASSIGNMENT_POOL_OPTION);
// setup our _requestAssignment member variable from the passed arguments
_requestAssignment = Assignment(Assignment::RequestCommand, requestAssignmentType, requestAssignmentPool);
// create a NodeList as an unassigned client // create a NodeList as an unassigned client
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_UNASSIGNED); NodeList* nodeList = NodeList::createInstance(NODE_TYPE_UNASSIGNED);
const char CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION[] = "-a";
const char CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION[] = "-p";
// grab the overriden assignment-server hostname from argv, if it exists
const char* customAssignmentServerHostname = getCmdOption(argc, (const char**)argv, CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION);
const char* customAssignmentServerPortString = getCmdOption(argc,(const char**)argv, CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION);
HifiSockAddr customAssignmentSocket;
if (customAssignmentServerHostname || customAssignmentServerPortString) {
// set the custom port or default if it wasn't passed
unsigned short assignmentServerPort = customAssignmentServerPortString
? atoi(customAssignmentServerPortString) : DEFAULT_DOMAIN_SERVER_PORT;
// set the custom hostname or default if it wasn't passed
if (!customAssignmentServerHostname) {
customAssignmentServerHostname = DEFAULT_ASSIGNMENT_SERVER_HOSTNAME;
}
customAssignmentSocket = HifiSockAddr(customAssignmentServerHostname, assignmentServerPort);
}
// set the custom assignment socket if we have it // set the custom assignment socket if we have it
if (!customAssignmentServerSocket.isNull()) { if (!customAssignmentSocket.isNull()) {
nodeList->setAssignmentServerSocket(customAssignmentServerSocket); nodeList->setAssignmentServerSocket(customAssignmentSocket);
} }
// call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required // call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required

View file

@ -16,10 +16,7 @@
class AssignmentClient : public QCoreApplication { class AssignmentClient : public QCoreApplication {
Q_OBJECT Q_OBJECT
public: public:
AssignmentClient(int &argc, char **argv, AssignmentClient(int &argc, char **argv);
Assignment::Type requestAssignmentType = Assignment::AllTypes,
const HifiSockAddr& customAssignmentServerSocket = HifiSockAddr(),
const char* requestAssignmentPool = NULL);
private slots: private slots:
void sendAssignmentRequest(); void sendAssignmentRequest();
void readPendingDatagrams(); void readPendingDatagrams();

View file

@ -0,0 +1,56 @@
//
// AssignmentClientMonitor.cpp
// hifi
//
// Created by Stephen Birarda on 1/10/2014.
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
//
#include <Logging.h>
#include "AssignmentClientMonitor.h"
const char* NUM_FORKS_PARAMETER = "-n";
const char ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME[] = "assignment-client-monitor";
AssignmentClientMonitor::AssignmentClientMonitor(int &argc, char **argv, int numAssignmentClientForks) :
QCoreApplication(argc, argv)
{
// start the Logging class with the parent's target name
Logging::setTargetName(ASSIGNMENT_CLIENT_MONITOR_TARGET_NAME);
_childArguments = arguments();
// remove the parameter for the number of forks so it isn't passed to the child forked processes
int forksParameterIndex = _childArguments.indexOf(NUM_FORKS_PARAMETER);
// this removes both the "-n" parameter and the number of forks passed
_childArguments.removeAt(forksParameterIndex);
_childArguments.removeAt(forksParameterIndex);
// use QProcess to fork off a process for each of the child assignment clients
for (int i = 0; i < numAssignmentClientForks; i++) {
spawnChildClient();
}
}
void AssignmentClientMonitor::spawnChildClient() {
QProcess *assignmentClient = new QProcess(this);
// make sure that the output from the child process appears in our output
assignmentClient->setProcessChannelMode(QProcess::ForwardedChannels);
assignmentClient->start(applicationFilePath(), _childArguments);
// link the child processes' finished slot to our childProcessFinished slot
connect(assignmentClient, SIGNAL(finished(int, QProcess::ExitStatus)), this,
SLOT(childProcessFinished(int, QProcess::ExitStatus)));
qDebug() << "Spawned a child client with PID" << assignmentClient->pid() << "\n";
}
void AssignmentClientMonitor::childProcessFinished(int exitCode, QProcess::ExitStatus exitStatus) {
qDebug() << "Replacing dead child assignment client with a new one.\n";
spawnChildClient();
}

View file

@ -0,0 +1,31 @@
//
// AssignmentClientMonitor.h
// hifi
//
// Created by Stephen Birarda on 1/10/2014.
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
//
#ifndef __hifi__AssignmentClientMonitor__
#define __hifi__AssignmentClientMonitor__
#include <QtCore/QCoreApplication>
#include <QtCore/QProcess>
#include <Assignment.h>
extern const char* NUM_FORKS_PARAMETER;
class AssignmentClientMonitor : public QCoreApplication {
Q_OBJECT
public:
AssignmentClientMonitor(int &argc, char **argv, int numAssignmentClientForks);
private slots:
void childProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
private:
void spawnChildClient();
QStringList _childArguments;
};
#endif /* defined(__hifi__AssignmentClientMonitor__) */

View file

@ -6,172 +6,33 @@
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
// //
#include <arpa/inet.h>
#include <errno.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <Logging.h> #include <Logging.h>
#include <NodeList.h>
#include <PacketHeaders.h>
#include <SharedUtil.h> #include <SharedUtil.h>
#include <VoxelServer.h>
#include "Agent.h"
#include "Assignment.h" #include "Assignment.h"
#include "AssignmentClient.h" #include "AssignmentClient.h"
#include "audio/AudioMixer.h" #include "AssignmentClientMonitor.h"
#include "avatars/AvatarMixer.h"
const char PARENT_TARGET_NAME[] = "assignment-client-monitor";
pid_t* childForks = NULL;
HifiSockAddr customAssignmentSocket;
int numForks = 0;
Assignment::Type overiddenAssignmentType = Assignment::AllTypes;
const char* assignmentPool = NULL;
int argc = 0;
char** argv = NULL;
int childClient() {
AssignmentClient client(::argc, ::argv, ::overiddenAssignmentType, customAssignmentSocket, ::assignmentPool);
return client.exec();
}
void sigchldHandler(int sig) {
pid_t processID;
int status;
while ((processID = waitpid(-1, &status, WNOHANG)) != -1) {
if (processID == 0) {
// there are no more children to process, break out of here
break;
}
int newForkProcessID = 0;
// find the dead process in the array of child forks
for (int i = 0; i < ::numForks; i++) {
if (::childForks[i] == processID) {
newForkProcessID = fork();
if (newForkProcessID == 0) {
// this is the child, call childClient
childClient();
// break out so we don't fork bomb
break;
} else {
// this is the parent, replace the dead process with the new one
::childForks[i] = newForkProcessID;
qDebug("Replaced dead %d with new fork %d\n", processID, newForkProcessID);
break;
}
}
}
}
}
void parentMonitor() {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = sigchldHandler;
sigaction(SIGCHLD, &sa, NULL);
pid_t childID = 0;
// don't bail until all children have finished
while ((childID = waitpid(-1, NULL, 0))) {
if (errno == ECHILD) {
break;
}
}
// delete the array of pid_t holding the forked process IDs
delete[] ::childForks;
}
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
::argc = argc;
::argv = argv;
setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(stdout, NULL, _IOLBF, 0);
// use the verbose message handler in Logging // use the verbose message handler in Logging
qInstallMessageHandler(Logging::verboseMessageHandler); qInstallMessageHandler(Logging::verboseMessageHandler);
// start the Logging class with the parent's target name
Logging::setTargetName(PARENT_TARGET_NAME);
const char CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION[] = "-a";
const char CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION[] = "-p";
// grab the overriden assignment-server hostname from argv, if it exists
const char* customAssignmentServerHostname = getCmdOption(argc, (const char**)argv, CUSTOM_ASSIGNMENT_SERVER_HOSTNAME_OPTION);
const char* customAssignmentServerPortString = getCmdOption(argc,(const char**)argv, CUSTOM_ASSIGNMENT_SERVER_PORT_OPTION);
if (customAssignmentServerHostname || customAssignmentServerPortString) {
// set the custom port or default if it wasn't passed
unsigned short assignmentServerPort = customAssignmentServerPortString
? atoi(customAssignmentServerPortString) : DEFAULT_DOMAIN_SERVER_PORT;
// set the custom hostname or default if it wasn't passed
if (!customAssignmentServerHostname) {
customAssignmentServerHostname = DEFAULT_ASSIGNMENT_SERVER_HOSTNAME;
}
::customAssignmentSocket = HifiSockAddr(customAssignmentServerHostname, assignmentServerPort);
}
const char ASSIGNMENT_TYPE_OVVERIDE_OPTION[] = "-t";
const char* assignmentTypeString = getCmdOption(argc, (const char**)argv, ASSIGNMENT_TYPE_OVVERIDE_OPTION);
if (assignmentTypeString) {
// the user is asking to only be assigned to a particular type of assignment
// so set that as the ::overridenAssignmentType to be used in requests
::overiddenAssignmentType = (Assignment::Type) atoi(assignmentTypeString);
}
const char ASSIGNMENT_POOL_OPTION[] = "--pool";
::assignmentPool = getCmdOption(argc, (const char**) argv, ASSIGNMENT_POOL_OPTION);
const char* NUM_FORKS_PARAMETER = "-n";
const char* numForksString = getCmdOption(argc, (const char**)argv, NUM_FORKS_PARAMETER); const char* numForksString = getCmdOption(argc, (const char**)argv, NUM_FORKS_PARAMETER);
int processID = 0; int numForks = 0;
if (numForksString) { if (numForksString) {
::numForks = atoi(numForksString); numForks = atoi(numForksString);
qDebug("Starting %d assignment clients\n", ::numForks);
::childForks = new pid_t[::numForks];
// fire off as many children as we need (this is one less than the parent since the parent will run as well)
for (int i = 0; i < ::numForks; i++) {
processID = fork();
if (processID == 0) {
// this is in one of the children, break so we don't start a fork bomb
break;
} else {
// this is in the parent, save the ID of the forked process
childForks[i] = processID;
}
}
} }
if (processID == 0 || ::numForks == 0) { if (numForks) {
return childClient(); AssignmentClientMonitor monitor(argc, argv, numForks);
return monitor.exec();
} else { } else {
parentMonitor(); AssignmentClient client(argc, argv);
return client.exec();
} }
} }

View file

@ -58,6 +58,7 @@ void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3
_position = position; _position = position;
_radius = radius; _radius = radius;
_mass = 1.0f;
memcpy(_color, color, sizeof(_color)); memcpy(_color, color, sizeof(_color));
_velocity = velocity; _velocity = velocity;
_damping = damping; _damping = damping;
@ -67,6 +68,11 @@ void Particle::init(glm::vec3 position, float radius, rgbColor color, glm::vec3
_shouldDie = false; _shouldDie = false;
} }
void Particle::setMass(float value) {
if (value > 0.0f) {
_mass = value;
}
}
bool Particle::appendParticleData(OctreePacketData* packetData) const { bool Particle::appendParticleData(OctreePacketData* packetData) const {

View file

@ -69,6 +69,7 @@ public:
const rgbColor& getColor() const { return _color; } const rgbColor& getColor() const { return _color; }
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; } xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
float getRadius() const { return _radius; } float getRadius() const { return _radius; }
float getMass() const { return _mass; }
const glm::vec3& getVelocity() const { return _velocity; } const glm::vec3& getVelocity() const { return _velocity; }
const glm::vec3& getGravity() const { return _gravity; } const glm::vec3& getGravity() const { return _gravity; }
bool getInHand() const { return _inHand; } bool getInHand() const { return _inHand; }
@ -98,6 +99,7 @@ public:
_color[BLUE_INDEX] = value.blue; _color[BLUE_INDEX] = value.blue;
} }
void setRadius(float value) { _radius = value; } void setRadius(float value) { _radius = value; }
void setMass(float value);
void setGravity(const glm::vec3& value) { _gravity = value; } void setGravity(const glm::vec3& value) { _gravity = value; }
void setInHand(bool inHand) { _inHand = inHand; } void setInHand(bool inHand) { _inHand = inHand; }
void setDamping(float value) { _damping = value; } void setDamping(float value) { _damping = value; }
@ -149,6 +151,7 @@ protected:
glm::vec3 _position; glm::vec3 _position;
rgbColor _color; rgbColor _color;
float _radius; float _radius;
float _mass;
glm::vec3 _velocity; glm::vec3 _velocity;
uint32_t _id; uint32_t _id;
static uint32_t _nextID; static uint32_t _nextID;

View file

@ -87,41 +87,50 @@ void ParticleCollisionSystem::updateCollisionWithVoxels(Particle* particle) {
} }
} }
void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particle) { void ParticleCollisionSystem::updateCollisionWithParticles(Particle* particleA) {
glm::vec3 center = particle->getPosition() * (float)(TREE_SCALE); glm::vec3 center = particleA->getPosition() * (float)(TREE_SCALE);
float radius = particle->getRadius() * (float)(TREE_SCALE); float radius = particleA->getRadius() * (float)(TREE_SCALE);
const float ELASTICITY = 1.4f; //const float ELASTICITY = 0.4f;
const float DAMPING = 0.0f; //const float DAMPING = 0.0f;
const float COLLISION_FREQUENCY = 0.5f; const float COLLISION_FREQUENCY = 0.5f;
glm::vec3 penetration; glm::vec3 penetration;
Particle* penetratedParticle; Particle* particleB;
if (_particles->findSpherePenetration(center, radius, penetration, (void**)&penetratedParticle)) { if (_particles->findSpherePenetration(center, radius, penetration, (void**)&particleB)) {
// NOTE: 'penetration' is the depth that 'particleA' overlaps 'particleB'.
// That is, it points from A into B.
// Even if the particles overlap... when the particles are already moving appart
// we don't want to count this as a collision.
glm::vec3 relativeVelocity = particleA->getVelocity() - particleB->getVelocity();
if (glm::dot(relativeVelocity, penetration) > 0.0f) {
particleA->collisionWithParticle(particleB);
particleB->collisionWithParticle(particleA);
// let the particles run their collision scripts if they have them glm::vec3 axis = glm::normalize(penetration);
particle->collisionWithParticle(penetratedParticle); glm::vec3 axialVelocity = glm::dot(relativeVelocity, axis) * axis;
penetratedParticle->collisionWithParticle(particle);
penetration /= (float)(TREE_SCALE); // particles that are in hand are assigned an ureasonably large mass for collisions
updateCollisionSound(particle, penetration, COLLISION_FREQUENCY); // which effectively makes them immovable but allows the other ball to reflect correctly.
const float MAX_MASS = 1.0e6f;
float massA = (particleA->getInHand()) ? MAX_MASS : particleA->getMass();
float massB = (particleB->getInHand()) ? MAX_MASS : particleB->getMass();
float totalMass = massA + massB;
particleA->setVelocity(particleA->getVelocity() - axialVelocity * (2.0f * massB / totalMass));
// apply a hard collision to both particles of half the penetration each ParticleEditHandle particleEditHandle(_packetSender, _particles, particleA->getID());
particleEditHandle.updateParticle(particleA->getPosition(), particleA->getRadius(), particleA->getXColor(), particleA->getVelocity(),
particleA->getGravity(), particleA->getDamping(), particleA->getInHand(), particleA->getScript());
float particleShare, penetratedParticleShare; particleB->setVelocity(particleB->getVelocity() + axialVelocity * (2.0f * massA / totalMass));
if (particle->getInHand() && penetratedParticle->getInHand()) {
particleShare = 0.5f; ParticleEditHandle penetratedparticleEditHandle(_packetSender, _particles, particleB->getID());
penetratedParticleShare = -0.5f; penetratedparticleEditHandle.updateParticle(particleB->getPosition(), particleB->getRadius(), particleB->getXColor(), particleB->getVelocity(),
} else if (particle->getInHand()) { particleB->getGravity(), particleB->getDamping(), particleB->getInHand(), particleB->getScript());
particleShare = 0.f;
penetratedParticleShare = -1.f; penetration /= (float)(TREE_SCALE);
} else if (penetratedParticle->getInHand()) { updateCollisionSound(particleA, penetration, COLLISION_FREQUENCY);
particleShare = -1.f;
penetratedParticleShare = 0.f;
} else {
particleShare = 0.5f;
penetratedParticleShare = -0.5f;
} }
applyHardCollision(particle, penetration * particleShare, ELASTICITY, DAMPING);
applyHardCollision(penetratedParticle, penetration * penetratedParticleShare, ELASTICITY, DAMPING);
} }
} }

View file

@ -12,11 +12,6 @@
#include <Octree.h> #include <Octree.h>
#include "ParticleTreeElement.h" #include "ParticleTreeElement.h"
class ParticleTreeUpdateArgs {
public:
std::vector<Particle> _movingParticles;
};
class NewlyCreatedParticleHook { class NewlyCreatedParticleHook {
public: public:
virtual void particleCreated(const Particle& newParticle, Node* senderNode) = 0; virtual void particleCreated(const Particle& newParticle, Node* senderNode) = 0;

View file

@ -19,7 +19,11 @@
class ParticleTree; class ParticleTree;
class ParticleTreeElement; class ParticleTreeElement;
class ParticleTreeUpdateArgs;
class ParticleTreeUpdateArgs {
public:
std::vector<Particle> _movingParticles;
};
class ParticleTreeElement : public OctreeElement { class ParticleTreeElement : public OctreeElement {
friend class ParticleTree; // to allow createElement to new us... friend class ParticleTree; // to allow createElement to new us...
@ -95,4 +99,4 @@ protected:
std::vector<Particle> _particles; std::vector<Particle> _particles;
}; };
#endif /* defined(__hifi__ParticleTreeElement__) */ #endif /* defined(__hifi__ParticleTreeElement__) */

View file

@ -31,105 +31,107 @@ glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec
} }
} }
bool findSpherePenetration(const glm::vec3& penetratorToPenetratee, const glm::vec3& direction, // Computes the penetration between a point and a sphere (centered at the origin)
float combinedRadius, glm::vec3& penetration) { // if point is inside sphere: returns true and stores the result in 'penetration'
float vectorLength = glm::length(penetratorToPenetratee); // (the vector that would move the point outside the sphere)
// otherwise returns false
bool findSpherePenetration(const glm::vec3& point, const glm::vec3& defaultDirection, float sphereRadius,
glm::vec3& penetration) {
float vectorLength = glm::length(point);
if (vectorLength < EPSILON) { if (vectorLength < EPSILON) {
penetration = direction * combinedRadius; penetration = defaultDirection * sphereRadius;
return true; return true;
} }
float distance = vectorLength - combinedRadius; float distance = vectorLength - sphereRadius;
if (distance < 0.0f) { if (distance < 0.0f) {
penetration = penetratorToPenetratee * (-distance / vectorLength); penetration = point * (-distance / vectorLength);
return true; return true;
} }
return false; return false;
} }
bool findSpherePointPenetration(const glm::vec3& penetratorCenter, float penetratorRadius, bool findSpherePointPenetration(const glm::vec3& sphereCenter, float sphereRadius,
const glm::vec3& penetrateeLocation, glm::vec3& penetration) { const glm::vec3& point, glm::vec3& penetration) {
return findSpherePenetration(penetrateeLocation - penetratorCenter, glm::vec3(0.0f, -1.0f, 0.0f), return findSpherePenetration(point - sphereCenter, glm::vec3(0.0f, -1.0f, 0.0f), sphereRadius, penetration);
penetratorRadius, penetration);
} }
bool findPointSpherePenetration(const glm::vec3& penetratorLocation, const glm::vec3& penetrateeCenter, bool findPointSpherePenetration(const glm::vec3& point, const glm::vec3& sphereCenter,
float penetrateeRadius, glm::vec3& penetration) { float sphereRadius, glm::vec3& penetration) {
return findSpherePenetration(penetrateeCenter - penetratorLocation, glm::vec3(0.0f, -1.0f, 0.0f), return findSpherePenetration(sphereCenter - point, glm::vec3(0.0f, -1.0f, 0.0f), sphereRadius, penetration);
penetrateeRadius, penetration);
} }
bool findSphereSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, bool findSphereSpherePenetration(const glm::vec3& firstCenter, float firstRadius,
const glm::vec3& penetrateeCenter, float penetrateeRadius, glm::vec3& penetration) { const glm::vec3& secondCenter, float secondRadius, glm::vec3& penetration) {
return findSpherePointPenetration(penetratorCenter, penetratorRadius + penetrateeRadius, penetrateeCenter, penetration); return findSpherePointPenetration(firstCenter, firstRadius + secondRadius, secondCenter, penetration);
} }
bool findSphereSegmentPenetration(const glm::vec3& penetratorCenter, float penetratorRadius, bool findSphereSegmentPenetration(const glm::vec3& sphereCenter, float sphereRadius,
const glm::vec3& penetrateeStart, const glm::vec3& penetrateeEnd, glm::vec3& penetration) { const glm::vec3& segmentStart, const glm::vec3& segmentEnd, glm::vec3& penetration) {
return findSpherePenetration(computeVectorFromPointToSegment(penetratorCenter, penetrateeStart, penetrateeEnd), return findSpherePenetration(computeVectorFromPointToSegment(sphereCenter, segmentStart, segmentEnd),
glm::vec3(0.0f, -1.0f, 0.0f), penetratorRadius, penetration); glm::vec3(0.0f, -1.0f, 0.0f), sphereRadius, penetration);
} }
bool findSphereCapsulePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, const glm::vec3& penetrateeStart, bool findSphereCapsulePenetration(const glm::vec3& sphereCenter, float sphereRadius, const glm::vec3& capsuleStart,
const glm::vec3& penetrateeEnd, float penetrateeRadius, glm::vec3& penetration) { const glm::vec3& capsuleEnd, float capsuleRadius, glm::vec3& penetration) {
return findSphereSegmentPenetration(penetratorCenter, penetratorRadius + penetrateeRadius, return findSphereSegmentPenetration(sphereCenter, sphereRadius + capsuleRadius,
penetrateeStart, penetrateeEnd, penetration); capsuleStart, capsuleEnd, penetration);
} }
bool findPointCapsuleConePenetration(const glm::vec3& penetratorLocation, const glm::vec3& penetrateeStart, bool findPointCapsuleConePenetration(const glm::vec3& point, const glm::vec3& capsuleStart,
const glm::vec3& penetrateeEnd, float penetrateeStartRadius, float penetrateeEndRadius, glm::vec3& penetration) { const glm::vec3& capsuleEnd, float startRadius, float endRadius, glm::vec3& penetration) {
// compute the projection of the point vector onto the segment vector // compute the projection of the point vector onto the segment vector
glm::vec3 segmentVector = penetrateeEnd - penetrateeStart; glm::vec3 segmentVector = capsuleEnd - capsuleStart;
float lengthSquared = glm::dot(segmentVector, segmentVector); float lengthSquared = glm::dot(segmentVector, segmentVector);
if (lengthSquared < EPSILON) { // start and end the same if (lengthSquared < EPSILON) { // start and end the same
return findPointSpherePenetration(penetratorLocation, penetrateeStart, return findPointSpherePenetration(point, capsuleStart,
glm::max(penetrateeStartRadius, penetrateeEndRadius), penetration); glm::max(startRadius, endRadius), penetration);
} }
float proj = glm::dot(penetratorLocation - penetrateeStart, segmentVector) / lengthSquared; float proj = glm::dot(point - capsuleStart, segmentVector) / lengthSquared;
if (proj <= 0.0f) { // closest to the start if (proj <= 0.0f) { // closest to the start
return findPointSpherePenetration(penetratorLocation, penetrateeStart, penetrateeStartRadius, penetration); return findPointSpherePenetration(point, capsuleStart, startRadius, penetration);
} else if (proj >= 1.0f) { // closest to the end } else if (proj >= 1.0f) { // closest to the end
return findPointSpherePenetration(penetratorLocation, penetrateeEnd, penetrateeEndRadius, penetration); return findPointSpherePenetration(point, capsuleEnd, endRadius, penetration);
} else { // closest to the middle } else { // closest to the middle
return findPointSpherePenetration(penetratorLocation, penetrateeStart + segmentVector * proj, return findPointSpherePenetration(point, capsuleStart + segmentVector * proj,
glm::mix(penetrateeStartRadius, penetrateeEndRadius, proj), penetration); glm::mix(startRadius, endRadius, proj), penetration);
} }
} }
bool findSphereCapsuleConePenetration(const glm::vec3& penetratorCenter, bool findSphereCapsuleConePenetration(const glm::vec3& sphereCenter,
float penetratorRadius, const glm::vec3& penetrateeStart, const glm::vec3& penetrateeEnd, float sphereRadius, const glm::vec3& capsuleStart, const glm::vec3& capsuleEnd,
float penetrateeStartRadius, float penetrateeEndRadius, glm::vec3& penetration) { float startRadius, float endRadius, glm::vec3& penetration) {
return findPointCapsuleConePenetration(penetratorCenter, penetrateeStart, penetrateeEnd, return findPointCapsuleConePenetration(sphereCenter, capsuleStart, capsuleEnd,
penetrateeStartRadius + penetratorRadius, penetrateeEndRadius + penetratorRadius, penetration); startRadius + sphereRadius, endRadius + sphereRadius, penetration);
} }
bool findSpherePlanePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, bool findSpherePlanePenetration(const glm::vec3& sphereCenter, float sphereRadius,
const glm::vec4& penetrateePlane, glm::vec3& penetration) { const glm::vec4& plane, glm::vec3& penetration) {
float distance = glm::dot(penetrateePlane, glm::vec4(penetratorCenter, 1.0f)) - penetratorRadius; float distance = glm::dot(plane, glm::vec4(sphereCenter, 1.0f)) - sphereRadius;
if (distance < 0.0f) { if (distance < 0.0f) {
penetration = glm::vec3(penetrateePlane) * distance; penetration = glm::vec3(plane) * distance;
return true; return true;
} }
return false; return false;
} }
bool findCapsuleSpherePenetration(const glm::vec3& penetratorStart, const glm::vec3& penetratorEnd, float penetratorRadius, bool findCapsuleSpherePenetration(const glm::vec3& capsuleStart, const glm::vec3& capsuleEnd, float capsuleRadius,
const glm::vec3& penetrateeCenter, float penetrateeRadius, glm::vec3& penetration) { const glm::vec3& sphereCenter, float sphereRadius, glm::vec3& penetration) {
if (findSphereCapsulePenetration(penetrateeCenter, penetrateeRadius, if (findSphereCapsulePenetration(sphereCenter, sphereRadius,
penetratorStart, penetratorEnd, penetratorRadius, penetration)) { capsuleStart, capsuleEnd, capsuleRadius, penetration)) {
penetration = -penetration; penetration = -penetration;
return true; return true;
} }
return false; return false;
} }
bool findCapsulePlanePenetration(const glm::vec3& penetratorStart, const glm::vec3& penetratorEnd, float penetratorRadius, bool findCapsulePlanePenetration(const glm::vec3& capsuleStart, const glm::vec3& capsuleEnd, float capsuleRadius,
const glm::vec4& penetrateePlane, glm::vec3& penetration) { const glm::vec4& plane, glm::vec3& penetration) {
float distance = glm::min(glm::dot(penetrateePlane, glm::vec4(penetratorStart, 1.0f)), float distance = glm::min(glm::dot(plane, glm::vec4(capsuleStart, 1.0f)),
glm::dot(penetrateePlane, glm::vec4(penetratorEnd, 1.0f))) - penetratorRadius; glm::dot(plane, glm::vec4(capsuleEnd, 1.0f))) - capsuleRadius;
if (distance < 0.0f) { if (distance < 0.0f) {
penetration = glm::vec3(penetrateePlane) * distance; penetration = glm::vec3(plane) * distance;
return true; return true;
} }
return false; return false;

View file

@ -13,39 +13,45 @@
glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end); glm::vec3 computeVectorFromPointToSegment(const glm::vec3& point, const glm::vec3& start, const glm::vec3& end);
bool findSpherePenetration(const glm::vec3& penetratorToPenetratee, const glm::vec3& direction, /// Computes the penetration between a point and a sphere (centered at the origin)
float combinedRadius, glm::vec3& penetration); /// \param point the point location relative to sphere center (origin)
/// \param defaultDirection the direction of the pentration when the point is near the origin
/// \param sphereRadius the radius of the sphere
/// \param penetration the displacement that would move the point out of penetration with the sphere
/// \return true if point is inside sphere, otherwise false
bool findSpherePenetration(const glm::vec3& point, const glm::vec3& defaultDirection,
float sphereRadius, glm::vec3& penetration);
bool findSpherePointPenetration(const glm::vec3& penetratorCenter, float penetratorRadius, bool findSpherePointPenetration(const glm::vec3& sphereCenter, float sphereRadius,
const glm::vec3& penetrateeLocation, glm::vec3& penetration); const glm::vec3& point, glm::vec3& penetration);
bool findPointSpherePenetration(const glm::vec3& penetratorLocation, const glm::vec3& penetrateeCenter, bool findPointSpherePenetration(const glm::vec3& point, const glm::vec3& sphereCenter,
float penetrateeRadius, glm::vec3& penetration); float sphereRadius, glm::vec3& penetration);
bool findSphereSpherePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, bool findSphereSpherePenetration(const glm::vec3& firstCenter, float firstRadius,
const glm::vec3& penetrateeCenter, float penetrateeRadius, glm::vec3& penetration); const glm::vec3& secondCenter, float secondRadius, glm::vec3& penetration);
bool findSphereSegmentPenetration(const glm::vec3& penetratorCenter, float penetratorRadius, bool findSphereSegmentPenetration(const glm::vec3& sphereCenter, float sphereRadius,
const glm::vec3& penetrateeStart, const glm::vec3& penetrateeEnd, glm::vec3& penetration); const glm::vec3& segmentStart, const glm::vec3& segmentEnd, glm::vec3& penetration);
bool findSphereCapsulePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, const glm::vec3& penetrateeStart, bool findSphereCapsulePenetration(const glm::vec3& sphereCenter, float sphereRadius, const glm::vec3& capsuleStart,
const glm::vec3& penetrateeEnd, float penetrateeRadius, glm::vec3& penetration); const glm::vec3& capsuleEnd, float capsuleRadius, glm::vec3& penetration);
bool findPointCapsuleConePenetration(const glm::vec3& penetratorLocation, const glm::vec3& penetrateeStart, bool findPointCapsuleConePenetration(const glm::vec3& point, const glm::vec3& capsuleStart,
const glm::vec3& penetrateeEnd, float penetrateeStartRadius, float penetrateeEndRadius, glm::vec3& penetration); const glm::vec3& capsuleEnd, float startRadius, float endRadius, glm::vec3& penetration);
bool findSphereCapsuleConePenetration(const glm::vec3& penetratorCenter, bool findSphereCapsuleConePenetration(const glm::vec3& sphereCenter, float sphereRadius,
float penetratorRadius, const glm::vec3& penetrateeStart, const glm::vec3& penetrateeEnd, const glm::vec3& capsuleStart, const glm::vec3& capsuleEnd,
float penetrateeStartRadius, float penetrateeEndRadius, glm::vec3& penetration); float startRadius, float endRadius, glm::vec3& penetration);
bool findSpherePlanePenetration(const glm::vec3& penetratorCenter, float penetratorRadius, bool findSpherePlanePenetration(const glm::vec3& sphereCenter, float sphereRadius,
const glm::vec4& penetrateePlane, glm::vec3& penetration); const glm::vec4& plane, glm::vec3& penetration);
bool findCapsuleSpherePenetration(const glm::vec3& penetratorStart, const glm::vec3& penetratorEnd, float penetratorRadius, bool findCapsuleSpherePenetration(const glm::vec3& capsuleStart, const glm::vec3& capsuleEnd, float capsuleRadius,
const glm::vec3& penetrateeCenter, float penetrateeRadius, glm::vec3& penetration); const glm::vec3& sphereCenter, float sphereRadius, glm::vec3& penetration);
bool findCapsulePlanePenetration(const glm::vec3& penetratorStart, const glm::vec3& penetratorEnd, float penetratorRadius, bool findCapsulePlanePenetration(const glm::vec3& capsuleStart, const glm::vec3& capsuleEnd, float capsuleRadius,
const glm::vec4& penetrateePlane, glm::vec3& penetration); const glm::vec4& plane, glm::vec3& penetration);
glm::vec3 addPenetrations(const glm::vec3& currentPenetration, const glm::vec3& newPenetration); glm::vec3 addPenetrations(const glm::vec3& currentPenetration, const glm::vec3& newPenetration);