Merge pull request #886 from ey6es/master

Glowing "laser pointer" for transmitter, when not in drive mode.  Also, make the avatar spheres glow.
This commit is contained in:
ZappoMan 2013-08-22 17:43:23 -07:00
commit 69356f6fa1
6 changed files with 133 additions and 26 deletions

View file

@ -1384,7 +1384,9 @@ Avatar* Application::isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3
if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) {
Avatar* avatar = (Avatar *) node->getLinkedData();
glm::vec3 headPosition = avatar->getHead().getPosition();
if (rayIntersectsSphere(mouseRayOrigin, mouseRayDirection, headPosition, HEAD_SPHERE_RADIUS * avatar->getScale())) {
float distance;
if (rayIntersectsSphere(mouseRayOrigin, mouseRayDirection, headPosition,
HEAD_SPHERE_RADIUS * avatar->getScale(), distance)) {
eyePosition = avatar->getHead().getEyePosition();
_lookatIndicatorScale = avatar->getScale();
_lookatOtherPosition = headPosition;
@ -1722,6 +1724,40 @@ void Application::update(float deltaTime) {
_myAvatar.simulate(deltaTime, NULL, Menu::getInstance()->getGyroCameraSensitivity());
}
// no transmitter drive implies transmitter pick
if (!Menu::getInstance()->isOptionChecked(MenuOption::TransmitterDrive) && _myTransmitter.isConnected()) {
_transmitterPickStart = _myAvatar.getSkeleton().joint[AVATAR_JOINT_CHEST].position;
glm::vec3 direction = _myAvatar.getOrientation() *
glm::quat(glm::radians(_myTransmitter.getEstimatedRotation())) * IDENTITY_FRONT;
// check against voxels, avatars
const float MAX_PICK_DISTANCE = 100.0f;
float minDistance = MAX_PICK_DISTANCE;
VoxelDetail detail;
float distance;
BoxFace face;
if (_voxels.findRayIntersection(_transmitterPickStart, direction, detail, distance, face)) {
minDistance = min(minDistance, distance);
}
for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
node->lock();
if (node->getLinkedData() != NULL) {
Avatar *avatar = (Avatar*)node->getLinkedData();
if (!avatar->isInitialized()) {
avatar->init();
}
if (avatar->findRayIntersection(_transmitterPickStart, direction, distance)) {
minDistance = min(minDistance, distance);
}
}
node->unlock();
}
_transmitterPickEnd = _transmitterPickStart + direction * minDistance;
} else {
_transmitterPickStart = _transmitterPickEnd = glm::vec3();
}
if (!OculusManager::isConnected()) {
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
if (_myCamera.getMode() != CAMERA_MODE_MIRROR) {
@ -2271,6 +2307,27 @@ void Application::displaySide(Camera& whichCamera) {
}
renderFollowIndicator();
// render transmitter pick ray, if non-empty
if (_transmitterPickStart != _transmitterPickEnd) {
Glower glower;
const float TRANSMITTER_PICK_COLOR[] = { 1.0f, 1.0f, 0.0f };
glColor3fv(TRANSMITTER_PICK_COLOR);
glLineWidth(3.0f);
glBegin(GL_LINES);
glVertex3f(_transmitterPickStart.x, _transmitterPickStart.y, _transmitterPickStart.z);
glVertex3f(_transmitterPickEnd.x, _transmitterPickEnd.y, _transmitterPickEnd.z);
glEnd();
glLineWidth(1.0f);
glPushMatrix();
glTranslatef(_transmitterPickEnd.x, _transmitterPickEnd.y, _transmitterPickEnd.z);
const float PICK_END_RADIUS = 0.025f;
glutSolidSphere(PICK_END_RADIUS, 8, 8);
glPopMatrix();
}
}
void Application::displayOverlay() {

View file

@ -298,6 +298,9 @@ private:
glm::vec3 _lookatOtherPosition;
float _lookatIndicatorScale;
glm::vec3 _transmitterPickStart;
glm::vec3 _transmitterPickEnd;
bool _perfStatsOn; // Do we want to display perfStats?
ChatEntry _chatEntry; // chat entry field

View file

@ -598,13 +598,35 @@ float loadSetting(QSettings* settings, const char* name, float defaultValue) {
return value;
}
bool rayIntersectsSphere(glm::vec3& rayStarting, glm::vec3& rayNormalizedDirection, glm::vec3& sphereCenter, double sphereRadius) {
glm::vec3 vecFromRayToSphereCenter = sphereCenter - rayStarting;
double projection = glm::dot(vecFromRayToSphereCenter, rayNormalizedDirection);
double shortestDistance = sqrt(glm::dot(vecFromRayToSphereCenter, vecFromRayToSphereCenter) - projection * projection);
if (shortestDistance <= sphereRadius) {
return true;
bool rayIntersectsSphere(const glm::vec3& rayStarting, const glm::vec3& rayNormalizedDirection,
const glm::vec3& sphereCenter, float sphereRadius, float& distance) {
glm::vec3 relativeOrigin = rayStarting - sphereCenter;
// compute the b, c terms of the quadratic equation (a is dot(direction, direction), which is one)
float b = 2.0f * glm::dot(rayNormalizedDirection, relativeOrigin);
float c = glm::dot(relativeOrigin, relativeOrigin) - sphereRadius * sphereRadius;
// compute the radicand of the quadratic. if less than zero, there's no intersection
float radicand = b * b - 4.0f * c;
if (radicand < 0.0f) {
return false;
}
// compute the first solution of the quadratic
float root = sqrtf(radicand);
float firstSolution = -b - root;
if (firstSolution > 0.0f) {
distance = firstSolution / 2.0f;
return true; // origin is outside the sphere
}
// now try the second solution
float secondSolution = -b + root;
if (secondSolution > 0.0f) {
distance = 0.0f;
return true; // origin is inside the sphere
}
return false;
}
@ -615,4 +637,4 @@ bool pointInSphere(glm::vec3& point, glm::vec3& sphereCenter, double sphereRadiu
return true;
}
return false;
}
}

View file

@ -74,7 +74,8 @@ void runTimingTests();
float loadSetting(QSettings* settings, const char* name, float defaultValue);
bool rayIntersectsSphere(glm::vec3& rayStarting, glm::vec3& rayNormalizedDirection, glm::vec3& sphereCenter, double sphereRadius);
bool rayIntersectsSphere(const glm::vec3& rayStarting, const glm::vec3& rayNormalizedDirection,
const glm::vec3& sphereCenter, float sphereRadius, float& distance);
bool pointInSphere(glm::vec3& point, glm::vec3& sphereCenter, double sphereRadius);

View file

@ -486,22 +486,27 @@ void Avatar::render(bool lookingInMirror, bool renderAvatarBalls) {
// render a simple round on the ground projected down from the avatar's position
renderDiskShadow(_position, glm::vec3(0.0f, 1.0f, 0.0f), _scale * 0.1f, 0.2f);
// render body
renderBody(lookingInMirror, renderAvatarBalls);
{
// glow when moving
Glower glower(_moving ? 1.0f : 0.0f);
// render body
renderBody(lookingInMirror, renderAvatarBalls);
// render sphere when far away
const float MAX_ANGLE = 10.f;
glm::vec3 toTarget = _position - Application::getInstance()->getAvatar()->getPosition();
glm::vec3 delta = _height * (_head.getCameraOrientation() * IDENTITY_UP) / 2.f;
float angle = abs(angleBetween(toTarget + delta, toTarget - delta));
// render sphere when far away
const float MAX_ANGLE = 10.f;
glm::vec3 toTarget = _position - Application::getInstance()->getAvatar()->getPosition();
glm::vec3 delta = _height * (_head.getCameraOrientation() * IDENTITY_UP) / 2.f;
float angle = abs(angleBetween(toTarget + delta, toTarget - delta));
if (angle < MAX_ANGLE) {
glColor4f(0.5f, 0.8f, 0.8f, 1.f - angle / MAX_ANGLE);
glPushMatrix();
glTranslatef(_position.x, _position.y, _position.z);
glScalef(_height / 2.f, _height / 2.f, _height / 2.f);
glutSolidSphere(1.2f + _head.getAverageLoudness() * .0005f, 20, 20);
glPopMatrix();
if (angle < MAX_ANGLE) {
glColor4f(0.5f, 0.8f, 0.8f, 1.f - angle / MAX_ANGLE);
glPushMatrix();
glTranslatef(_position.x, _position.y, _position.z);
glScalef(_height / 2.f, _height / 2.f, _height / 2.f);
glutSolidSphere(1.2f + _head.getAverageLoudness() * .0005f, 20, 20);
glPopMatrix();
}
}
// Render the balls
@ -697,9 +702,6 @@ float Avatar::getBallRenderAlpha(int ball, bool lookingInMirror) const {
void Avatar::renderBody(bool lookingInMirror, bool renderAvatarBalls) {
// glow when moving
Glower glower(_moving ? 1.0f : 0.0f);
if (_head.getFace().isFullFrame()) {
// Render the full-frame video
float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, lookingInMirror);
@ -798,6 +800,21 @@ void Avatar::getBodyBallTransform(AvatarJointID jointID, glm::vec3& position, gl
rotation = _bodyBall[jointID].rotation;
}
bool Avatar::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
float minDistance = FLT_MAX;
for (int i = 0; i < NUM_AVATAR_BODY_BALLS; i++) {
float distance;
if (rayIntersectsSphere(origin, direction, _bodyBall[i].position, _bodyBall[i].radius, distance)) {
minDistance = min(minDistance, distance);
}
}
if (minDistance == FLT_MAX) {
return false;
}
distance = minDistance;
return true;
}
int Avatar::parseData(unsigned char* sourceBuffer, int numBytes) {
// change in position implies movement
glm::vec3 oldPosition = _position;

View file

@ -164,6 +164,13 @@ public:
// Get the position/rotation of a single body ball
void getBodyBallTransform(AvatarJointID jointID, glm::vec3& position, glm::quat& rotation) const;
/// Checks for an intersection between the described ray and any of the avatar's body balls.
/// \param origin the origin of the ray
/// \param direction the unit direction vector
/// \param[out] distance the variable in which to store the distance to intersection
/// \return whether or not the ray intersected
bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const;
virtual int parseData(unsigned char* sourceBuffer, int numBytes);
static void renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2);