Functional sixense "laser" oculus selection mode.

This commit is contained in:
barnold1953 2014-07-08 11:43:24 -07:00
parent ba997334ff
commit cc63f706a7
4 changed files with 215 additions and 66 deletions

View file

@ -443,7 +443,15 @@ void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) {
ovrPosef pose = ss.Predicted.Pose;
Quatf orientation = Quatf(pose.Orientation);
orientation.GetEulerAngles<Axis_Y, Axis_X, Axis_Z, Rotate_CCW, Handed_R>(&yaw, &pitch, &roll);
} else {
yaw = 0.0f;
pitch = 0.0f;
roll = 0.0f;
}
#else
yaw = 0.0f;
pitch = 0.0f;
roll = 0.0f;
#endif
}
@ -461,7 +469,7 @@ QSize OculusManager::getRenderTargetSize() {
void OculusManager::renderLaserPointer() {
#ifdef HAVE_LIBOVR
const float PALM_TIP_ROD_RADIUS = 0.009f;
const float PALM_TIP_ROD_RADIUS = 0.002f;
MyAvatar* myAvatar = Application::getInstance()->getAvatar();
@ -482,8 +490,8 @@ void OculusManager::renderLaserPointer() {
glm::vec3 OculusManager::getLaserPointerTipPosition(const PalmData* palm) {
#ifdef HAVE_LIBOVR
const float PALM_TIP_ROD_LENGTH_MULT = 2.0f;
return (palm->getTipPosition() - palm->getPosition()) * PALM_TIP_ROD_LENGTH_MULT;
const float PALM_TIP_ROD_LENGTH_MULT = 11.0f;
return palm->getPosition() + (palm->getTipPosition() - palm->getPosition()) * PALM_TIP_ROD_LENGTH_MULT;
#endif
return glm::vec3(0.0f);
}

View file

@ -13,6 +13,7 @@
#include "Application.h"
#include "SixenseManager.h"
#include "devices/OculusManager.h"
#include "UserActivityLogger.h"
#ifdef HAVE_SIXENSE
@ -358,9 +359,7 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
MyAvatar* avatar = application->getAvatar();
QGLWidget* widget = application->getGLWidget();
QPoint pos;
// Get directon relative to avatar orientation
glm::vec3 direction = glm::inverse(avatar->getOrientation()) * palm->getFingerDirection();
Qt::MouseButton bumperButton;
Qt::MouseButton triggerButton;
@ -372,15 +371,24 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) {
triggerButton = Qt::LeftButton;
}
// Get the angles, scaled between (-0.5,0.5)
float xAngle = (atan2(direction.z, direction.x) + M_PI_2);
float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2));
if (OculusManager::isConnected()) {
pos = application->getApplicationOverlay().getOculusPalmClickLocation(palm);
printf("CLICK: %d %d\n", pos.x(), pos.y());
} else {
// Get directon relative to avatar orientation
glm::vec3 direction = glm::inverse(avatar->getOrientation()) * palm->getFingerDirection();
// Get the pixel range over which the xAngle and yAngle are scaled
float cursorRange = widget->width() * getCursorPixelRangeMult();
// Get the angles, scaled between (-0.5,0.5)
float xAngle = (atan2(direction.z, direction.x) + M_PI_2);
float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2));
pos.setX(widget->width() / 2.0f + cursorRange * xAngle);
pos.setY(widget->height() / 2.0f + cursorRange * yAngle);
// Get the pixel range over which the xAngle and yAngle are scaled
float cursorRange = widget->width() * getCursorPixelRangeMult();
pos.setX(widget->width() / 2.0f + cursorRange * xAngle);
pos.setY(widget->height() / 2.0f + cursorRange * yAngle);
}
//If we are off screen then we should stop processing, and if a trigger or bumper is pressed,
//we should unpress them.

View file

@ -205,6 +205,103 @@ void ApplicationOverlay::getClickLocation(int &x, int &y) const {
}
}
//Checks if the given ray intersects the sphere at the origin. result will store a multiplier that should
//be multiplied by dir and added to origin to get the location of the collision
bool raySphereIntersect(const glm::vec3 &dir, const glm::vec3 &origin, float r, float* result)
{
//Source: http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection
//Compute A, B and C coefficients
float a = glm::dot(dir, dir);
float b = 2 * glm::dot(dir, origin);
float c = glm::dot(origin, origin) - (r * r);
//Find discriminant
float disc = b * b - 4 * a * c;
// if discriminant is negative there are no real roots, so return
// false as ray misses sphere
if (disc < 0) {
return false;
}
// compute q as described above
float distSqrt = sqrtf(disc);
float q;
if (b < 0) {
q = (-b - distSqrt) / 2.0;
} else {
q = (-b + distSqrt) / 2.0;
}
// compute t0 and t1
float t0 = q / a;
float t1 = c / q;
// make sure t0 is smaller than t1
if (t0 > t1) {
// if t0 is bigger than t1 swap them around
float temp = t0;
t0 = t1;
t1 = temp;
}
// if t1 is less than zero, the object is in the ray's negative direction
// and consequently the ray misses the sphere
if (t1 < 0) {
return false;
}
// if t0 is less than zero, the intersection point is at t1
if (t0 < 0) {
*result = t1;
return true;
} else { // else the intersection point is at t0
*result = t0;
return true;
}
}
QPoint ApplicationOverlay::getOculusPalmClickLocation(PalmData *palm) const {
Application* application = Application::getInstance();
QGLWidget* glWidget = application->getGLWidget();
MyAvatar* myAvatar = application->getAvatar();
const int widgetWidth = glWidget->width();
const int widgetHeight = glWidget->height();
glm::vec3 tip = OculusManager::getLaserPointerTipPosition(palm);
glm::vec3 eyePos = myAvatar->getHead()->calculateAverageEyePosition();
glm::quat orientation = glm::inverse(myAvatar->getOrientation());
glm::vec3 dir = orientation * glm::normalize(eyePos - tip); //direction of ray goes towards camera
glm::vec3 tipPos = orientation * (tip - eyePos);
QPoint rv;
float t;
//Find intersection of crosshair ray
if (raySphereIntersect(dir, tipPos, 1, &t)){
glm::vec3 collisionPos = tipPos + dir * t;
float u = asin(collisionPos.x) / (_textureFov)+0.5f;
float v = 1.0 - (asin(collisionPos.y) / (_textureFov)+0.5f);
rv.setX(u * glWidget->width());
rv.setY(v * glWidget->height());
} else {
//if they did not click on the overlay, just set the coords to INT_MAX
rv.setX(INT_MAX);
rv.setY(INT_MAX);
}
return rv;
}
// Draws the FBO texture for Oculus rift.
void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
@ -221,11 +318,14 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
glEnable(GL_BLEND);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture());
glEnable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
renderControllerPointersOculus();
glBindTexture(GL_TEXTURE_2D, getFramebufferObject()->texture());
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
@ -277,8 +377,6 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
renderTexturedHemisphere();
renderControllerPointersOculus();
glPopMatrix();
glDepthMask(GL_TRUE);
@ -559,22 +657,6 @@ void ApplicationOverlay::renderControllerPointers() {
}
}
bool findSphereIntersection(const glm::vec3 &start, const glm::vec3 &end, const glm::vec3 &spos, const float r, glm::vec3 &result) {
double a = pow(end.x - start.x, 2) + pow(end.y - start.y, 2) + pow(end.z - start.z, 2);
double b = 2.0f * ((end.x - start.x) * (start.x - spos.x) + (end.y - start.x) * (start.y - spos.y) + (end.z - start.z) * (start.z - spos.z));
double c = pow(start.x - spos.x, 2) + pow(start.y - spos.y, 2) + pow(start.z - spos.z, 2) - r*r;
double delta = b * b - 4.0 * a * c;
printf("Intersection Delta %lf\n", delta);
if (delta == 0) {
float d = -b / (2.0 * a);
result = start + d * (end - start);
} else {
return false;
}
}
void ApplicationOverlay::renderControllerPointersOculus() {
const bool useLaser = true;
@ -589,54 +671,104 @@ void ApplicationOverlay::renderControllerPointersOculus() {
glBindTexture(GL_TEXTURE_2D, _crosshairTexture);
glDisable(GL_DEPTH_TEST);
for (int i = 0; i < NUMBER_OF_MAGNIFIERS; i++) {
if (i > 0 && useLaser) {
MyAvatar* myAvatar = application->getAvatar();
glMatrixMode(GL_MODELVIEW);
MyAvatar* myAvatar = application->getAvatar();
//Determine how much we need to iterate
const int ITERATIONS = max(myAvatar->getHand()->getNumPalms(), 3);
for (int i = 0; i < ITERATIONS; i++) {
if (useLaser && i < myAvatar->getHand()->getNumPalms()) {
PalmData& palm = myAvatar->getHand()->getPalms()[i];
if (palm.isActive()) {
glm::vec3 tip = OculusManager::getLaserPointerTipPosition(&palm);
glm::vec3 result;
glm::vec3 eyePos = myAvatar->getHead()->calculateAverageEyePosition();
glm::quat orientation = glm::inverse(myAvatar->getOrientation());
glm::vec3 dir = orientation * glm::normalize(eyePos - tip); //direction of ray goes towards camera
glm::vec3 tipPos = (tip - eyePos);
float t;
float length = glm::length(eyePos - tip);
float size = 0.045f * length;
if (findSphereIntersection(myAvatar->getHead()->calculateAverageEyePosition(),
tip, glm::vec3(0, 0, 0), 1, result)){
printf("Intersection Found: ");
printVector(result);
glm::vec3 up = glm::vec3(0.0, 1.0, 0.0) * size;
glm::vec3 right = glm::vec3(1.0, 0.0, 0.0) * size;
glm::vec3 cursorVerts[4];
cursorVerts[0] = -right + up;
cursorVerts[1] = right + up;
cursorVerts[2] = right - up;
cursorVerts[3] = -right - up;
glPushMatrix();
// glLoadIdentity();
// objToCamProj is the vector in world coordinates from the
// local origin to the camera projected in the XZ plane
glm::vec3 cursorToCameraXZ(-tipPos.x, 0, -tipPos.z);
cursorToCameraXZ = glm::normalize(cursorToCameraXZ);
// This is the original lookAt vector for the object
// in world coordinates
glm::vec3 direction(0, 0, 1);
glTranslatef(tip.x, tip.y, tip.z);
// easy fix to determine wether the angle is negative or positive
// for positive angles upAux will be a vector pointing in the
// positive y direction, otherwise upAux will point downwards
// effectively reversing the rotation.
glm::vec3 upAux = glm::cross(direction, cursorToCameraXZ);
// compute the angle
float angleCosine = glm::dot(direction, cursorToCameraXZ);
// perform the rotation. The if statement is used for stability reasons
// if the lookAt and objToCamProj vectors are too close together then
// |angleCosine| could be bigger than 1 due to lack of precision
if ((angleCosine < 0.999999) && (angleCosine > -0.999999)) {
glRotatef(acos(angleCosine) * DEGREES_PER_RADIAN, upAux[0], upAux[1], upAux[2]);
}
// so far it is just like the cylindrical billboard. The code for the
// second rotation comes now
// The second part tilts the object so that it faces the camera
//float lX = sin((newULeft - 0.5f) * _textureFov);
//float rX = sin((newURight - 0.5f) * _textureFov);
//float bY = sin((newVBottom - 0.5f) * _textureFov);
//float tY = sin((newVTop - 0.5f) * _textureFov);
// objToCam is the vector in world coordinates from
// the local origin to the camera
glm::vec3 cursorToCamera = glm::normalize(-tipPos);
//float dist;
////Bottom Left
//dist = sqrt(lX * lX + bY * bY);
//float blZ = sqrt(1.0f - dist * dist);
////Top Left
//dist = sqrt(lX * lX + tY * tY);
//float tlZ = sqrt(1.0f - dist * dist);
////Bottom Right
//dist = sqrt(rX * rX + bY * bY);
//float brZ = sqrt(1.0f - dist * dist);
////Top Right
//dist = sqrt(rX * rX + tY * tY);
//float trZ = sqrt(1.0f - dist * dist);
// Compute the angle between objToCamProj and objToCam,
//i.e. compute the required angle for the lookup vector
//glBegin(GL_QUADS);
angleCosine = glm::dot(cursorToCameraXZ, cursorToCamera);
//glColor4f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], _alpha);
// Tilt the object. The test is done to prevent instability
// when objToCam and objToCamProj have a very small
// angle between them
//glTexCoord2f(0.0f, 0.0f); glVertex3f(lX, tY, -tlZ);
//glTexCoord2f(1.0f, 0.0f); glVertex3f(rX, tY, -trZ);
//glTexCoord2f(1.0f, 1.0f); glVertex3f(rX, bY, -brZ);
//glTexCoord2f(0.0f, 1.0f); glVertex3f(lX, bY, -blZ);
if ((angleCosine < 0.99990) && (angleCosine > -0.9999))
if (cursorToCamera.y < 0) {
glRotatef(acos(angleCosine) * DEGREES_PER_RADIAN, 1, 0, 0);
} else {
glRotatef(acos(angleCosine) * DEGREES_PER_RADIAN, -1, 0, 0);
}
//glEnd();
glBegin(GL_QUADS);
glColor4f(RETICLE_COLOR[0], RETICLE_COLOR[1], RETICLE_COLOR[2], _alpha);
glTexCoord2f(0.0f, 0.0f); glVertex3f(cursorVerts[0].x, cursorVerts[0].y, cursorVerts[0].z);
glTexCoord2f(1.0f, 0.0f); glVertex3f(cursorVerts[1].x, cursorVerts[1].y, cursorVerts[1].z);
glTexCoord2f(1.0f, 1.0f); glVertex3f(cursorVerts[2].x, cursorVerts[2].y, cursorVerts[2].z);
glTexCoord2f(0.0f, 1.0f); glVertex3f(cursorVerts[3].x, cursorVerts[3].y, cursorVerts[3].z);
glEnd();
glPopMatrix();
}
} else {
} else if (i < NUMBER_OF_MAGNIFIERS) {
//Dont render the reticle if its inactive
if (!_reticleActive[i]) {
continue;

View file

@ -32,6 +32,7 @@ public:
void displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov);
void computeOculusPickRay(float x, float y, glm::vec3& direction) const;
void getClickLocation(int &x, int &y) const;
QPoint getOculusPalmClickLocation(PalmData *palm) const;
// Getters
QOpenGLFramebufferObject* getFramebufferObject();