Centrilized Oculus interference in pickRay

This commit is contained in:
Atlante45 2014-12-04 17:26:14 -08:00
parent 3b6936b47d
commit 7026af7b9a
7 changed files with 102 additions and 95 deletions

View file

@ -1131,7 +1131,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
if (!event->isAutoRepeat()) {
// this starts an HFActionEvent
HFActionEvent startActionEvent(HFActionEvent::startType(),
_viewFrustum.computePickRay(0.5f, 0.5f));
_myCamera.computeViewPickRay(0.5f, 0.5f));
sendEvent(this, &startActionEvent);
}
@ -1222,7 +1222,7 @@ void Application::keyReleaseEvent(QKeyEvent* event) {
case Qt::Key_Space: {
if (!event->isAutoRepeat()) {
// this ends the HFActionEvent
HFActionEvent endActionEvent(HFActionEvent::endType(), _viewFrustum.computePickRay(0.5f, 0.5f));
HFActionEvent endActionEvent(HFActionEvent::endType(), _myCamera.computeViewPickRay(0.5f, 0.5f));
sendEvent(this, &endActionEvent);
}
@ -1253,7 +1253,6 @@ void Application::focusOutEvent(QFocusEvent* event) {
}
void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) {
bool showMouse = true;
// Used by application overlay to determine how to draw cursor(s)
@ -2079,8 +2078,10 @@ void Application::updateMouseRay() {
x = _mouseX / (float)_glWidget->width();
y = _mouseY / (float)_glWidget->height();
}
_viewFrustum.computePickRay(x, y, _mouseRayOrigin, _mouseRayDirection);
PickRay pickRay = _myCamera.computeViewPickRay(x, y);
_mouseRayOrigin = pickRay.origin;
_mouseRayDirection = pickRay.direction;
// adjust for mirroring
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
glm::vec3 mouseRayOffset = _mouseRayOrigin - _viewFrustum.getPosition();

View file

@ -97,20 +97,17 @@ void Camera::setFarClip(float f) {
PickRay Camera::computePickRay(float x, float y) {
float screenWidth = Application::getInstance()->getGLWidget()->width();
float screenHeight = Application::getInstance()->getGLWidget()->height();
PickRay result;
if (OculusManager::isConnected()) {
result.origin = getPosition();
Application::getInstance()->getApplicationOverlay().computeOculusPickRay(x / screenWidth, y / screenHeight, result.direction);
} else {
Application::getInstance()->getViewFrustum()->computePickRay(x / screenWidth, y / screenHeight,
result.origin, result.direction);
}
return result;
return computeViewPickRay(x / screenWidth, y / screenHeight);
}
PickRay Camera::computeViewPickRay(float xRatio, float yRatio) {
PickRay result;
Application::getInstance()->getViewFrustum()->computePickRay(xRatio, yRatio, result.origin, result.direction);
if (OculusManager::isConnected()) {
Application::getInstance()->getApplicationOverlay().computeOculusPickRay(xRatio, yRatio, result.origin, result.direction);
} else {
Application::getInstance()->getViewFrustum()->computePickRay(xRatio, yRatio, result.origin, result.direction);
}
return result;
}

View file

@ -635,18 +635,7 @@ void EntityTreeRenderer::deleteReleasedModels() {
}
PickRay EntityTreeRenderer::computePickRay(float x, float y) {
float screenWidth = Application::getInstance()->getGLWidget()->width();
float screenHeight = Application::getInstance()->getGLWidget()->height();
PickRay result;
if (OculusManager::isConnected()) {
Camera* camera = Application::getInstance()->getCamera();
result.origin = camera->getPosition();
Application::getInstance()->getApplicationOverlay().computeOculusPickRay(x / screenWidth, y / screenHeight, result.direction);
} else {
ViewFrustum* viewFrustum = Application::getInstance()->getViewFrustum();
viewFrustum->computePickRay(x / screenWidth, y / screenHeight, result.origin, result.direction);
}
return result;
return Application::getInstance()->getCamera()->computePickRay(x, y);
}

View file

@ -133,7 +133,7 @@ void JoystickScriptingInterface::update() {
// global action events fire in the center of the screen
HFActionEvent actionEvent(actionType,
Application::getInstance()->getViewFrustum()->computePickRay(0.5f, 0.5f));
Application::getInstance()->getCamera()->computeViewPickRay(0.5f, 0.5f));
qApp->sendEvent(qApp, &actionEvent);
}

View file

@ -30,18 +30,19 @@ const quint64 MSECS_TO_USECS = 1000ULL;
const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f };
const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f };
static const float MOUSE_PITCH_RANGE = 1.0f * PI;
static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI;
const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f };
const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f;
static const float MOUSE_PITCH_RANGE = 1.0f * PI;
static const float MOUSE_YAW_RANGE = 0.5f * TWO_PI;
// Return a point's coordinates on a sphere from it's polar (theta) and azimutal (phi) angles.
glm::vec3 getPoint(float radius, float theta, float phi) {
return glm::vec3(radius * glm::sin(theta) * glm::sin(phi),
radius * glm::cos(theta),
radius * glm::sin(theta) * (-glm::cos(phi)));
// Return a point's coordinates on a sphere from pitch and yaw
glm::vec3 getPoint(float yaw, float pitch) {
return glm::vec3(glm::cos(-pitch) * (-glm::sin(yaw)),
glm::sin(-pitch),
glm::cos(-pitch) * (-glm::cos(yaw)));
}
//Checks if the given ray intersects the sphere at the origin. result will store a multiplier that should
@ -104,10 +105,10 @@ bool raySphereIntersect(const glm::vec3 &dir, const glm::vec3 &origin, float r,
void renderReticule(glm::quat orientation, float alpha) {
const float reticleSize = TWO_PI / 80.0f;
glm::vec3 topLeft = getPoint(1.0f, PI_OVER_TWO + reticleSize / 2.0f, - reticleSize / 2.0f);
glm::vec3 topRight = getPoint(1.0f, PI_OVER_TWO + reticleSize / 2.0f, + reticleSize / 2.0f);
glm::vec3 bottomLeft = getPoint(1.0f, PI_OVER_TWO - reticleSize / 2.0f, - reticleSize / 2.0f);
glm::vec3 bottomRight = getPoint(1.0f, PI_OVER_TWO - reticleSize / 2.0f, + reticleSize / 2.0f);
glm::vec3 topLeft = getPoint(reticleSize / 2.0f, -reticleSize / 2.0f);
glm::vec3 topRight = getPoint(-reticleSize / 2.0f, -reticleSize / 2.0f);
glm::vec3 bottomLeft = getPoint(reticleSize / 2.0f, reticleSize / 2.0f);
glm::vec3 bottomRight = getPoint(-reticleSize / 2.0f, reticleSize / 2.0f);
glPushMatrix(); {
glm::vec3 axis = glm::axis(orientation);
@ -284,11 +285,9 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
if (_magSizeMult[i] > 0.0f) {
//Render magnifier, but dont show border for mouse magnifier
float pitch = -(_reticulePosition[MOUSE].y / widgetHeight - 0.5f) * MOUSE_PITCH_RANGE;
float yaw = -(_reticulePosition[MOUSE].x / widgetWidth - 0.5f) * MOUSE_YAW_RANGE;
float projection =
glm::vec2 projection = screenToOverlay(_reticulePosition[i]);
renderMagnifier(_reticulePosition[i], _magSizeMult[i], i != MOUSE);
renderMagnifier(projection, _magSizeMult[i], i != MOUSE);
}
}
@ -296,7 +295,6 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
glDisable(GL_ALPHA_TEST);
glColor4f(1.0f, 1.0f, 1.0f, _alpha);
static float textureFOV = 0.0f, textureAspectRatio = 1.0f;
if (textureFOV != _textureFov ||
@ -417,11 +415,7 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}
void ApplicationOverlay::computeOculusPickRay(float x, float y, glm::vec3& direction) const {
void ApplicationOverlay::computeOculusPickRay(float x, float y, glm::vec3& origin, glm::vec3& direction) const {
const float pitch = (0.5f - y) * MOUSE_PITCH_RANGE;
const float yaw = (0.5f - x) * MOUSE_YAW_RANGE;
const glm::quat orientation(glm::vec3(pitch, yaw, 0.0f));
@ -429,6 +423,7 @@ void ApplicationOverlay::computeOculusPickRay(float x, float y, glm::vec3& direc
//Rotate the UI pick ray by the avatar orientation
const MyAvatar* myAvatar = Application::getInstance()->getAvatar();
origin = myAvatar->getDefaultEyePosition();
direction = myAvatar->getOrientation() * localDirection;
}
@ -497,7 +492,7 @@ bool ApplicationOverlay::calculateRayUICollisionPoint(const glm::vec3& position,
glm::quat orientation = myAvatar->getOrientation();
glm::vec3 relativePosition = orientation * (position - myAvatar->getHead()->getEyePosition());
glm::vec3 relativePosition = orientation * (position - myAvatar->getDefaultEyePosition());
glm::vec3 relativeDirection = orientation * direction;
float t;
@ -655,10 +650,6 @@ void ApplicationOverlay::renderControllerPointers() {
}
void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) {
GLCanvas* glWidget = Application::getInstance()->getGLWidget();
const int widgetWidth = glWidget->width();
const int widgetHeight = glWidget->height();
glBindTexture(GL_TEXTURE_2D, _crosshairTexture);
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_MODELVIEW);
@ -735,10 +726,8 @@ void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) {
//Mouse Pointer
if (_reticleActive[MOUSE]) {
float pitch = -(_reticulePosition[MOUSE].y / widgetHeight - 0.5f) * MOUSE_PITCH_RANGE;
float yaw = -(_reticulePosition[MOUSE].x / widgetWidth - 0.5f) * MOUSE_YAW_RANGE;
glm::quat orientation(glm::vec3(pitch, yaw, 0.0f));
glm::vec2 projection = screenToSpherical(_reticulePosition[MOUSE]);
glm::quat orientation(glm::vec3(-projection.y, projection.x, 0.0f));
renderReticule(orientation, _alpha);
}
@ -753,37 +742,26 @@ void ApplicationOverlay::renderMagnifier(glm::vec2 magPos, float sizeMult, bool
const int widgetWidth = glWidget->width();
const int widgetHeight = glWidget->height();
if (magPos.x < 0 || magPos.x > widgetWidth || magPos.y < 0 || magPos.y > widgetHeight) {
return;
}
const float halfWidth = (MAGNIFY_WIDTH / _textureAspectRatio) * sizeMult / 2.0f;
const float halfHeight = MAGNIFY_HEIGHT * sizeMult / 2.0f;
// Magnification Texture Coordinates
float magnifyULeft = (magPos.x - halfWidth) / (float)widgetWidth;
float magnifyURight = (magPos.x + halfWidth) / (float)widgetWidth;
float magnifyVBottom = 1.0f - (magPos.y - halfHeight) / (float)widgetHeight;
float magnifyVTop = 1.0f - (magPos.y + halfHeight) / (float)widgetHeight;
const float magnifyULeft = (magPos.x - halfWidth) / (float)widgetWidth;
const float magnifyURight = (magPos.x + halfWidth) / (float)widgetWidth;
const float magnifyVTop = 1.0f - (magPos.y - halfHeight) / (float)widgetHeight;
const float magnifyVBottom = 1.0f - (magPos.y + halfHeight) / (float)widgetHeight;
const float newHalfWidth = halfWidth * MAGNIFY_MULT;
const float newHalfHeight = halfHeight * MAGNIFY_MULT;
//Get new UV coordinates from our magnification window
float newULeft = (magPos.x - newHalfWidth) / (float)widgetWidth;
float newURight = (magPos.x + newHalfWidth) / (float)widgetWidth;
float newVBottom = 1.0f - (magPos.y - newHalfHeight) / (float)widgetHeight;
float newVTop = 1.0f - (magPos.y + newHalfHeight) / (float)widgetHeight;
//Get yaw / pitch value for the corners
const glm::vec2 topLeftYawPitch = overlayToSpherical(glm::vec2(magPos.x - newHalfWidth,
magPos.y - newHalfHeight));
const glm::vec2 bottomRightYawPitch = overlayToSpherical(glm::vec2(magPos.x + newHalfWidth,
magPos.y + newHalfHeight));
// Find spherical coordinates from newUV, fov and aspect ratio
float radius = _oculusUIRadius * application->getAvatar()->getScale();
const float leftPhi = (newULeft - 0.5f) * _textureFov * _textureAspectRatio;
const float rightPhi = (newURight - 0.5f) * _textureFov * _textureAspectRatio;
const float bottomTheta = PI_OVER_TWO - (newVBottom - 0.5f) * _textureFov;
const float topTheta = PI_OVER_TWO - (newVTop - 0.5f) * _textureFov;
glm::vec3 bottomLeft = getPoint(radius, bottomTheta, leftPhi);
glm::vec3 bottomRight = getPoint(radius, bottomTheta, rightPhi);
glm::vec3 topLeft = getPoint(radius, topTheta, leftPhi);
glm::vec3 topRight = getPoint(radius, topTheta, rightPhi);
const glm::vec3 bottomLeft = getPoint(topLeftYawPitch.x, bottomRightYawPitch.y);
const glm::vec3 bottomRight = getPoint(bottomRightYawPitch.x, bottomRightYawPitch.y);
const glm::vec3 topLeft = getPoint(topLeftYawPitch.x, topLeftYawPitch.y);
const glm::vec3 topRight = getPoint(bottomRightYawPitch.x, topLeftYawPitch.y);
glPushMatrix(); {
if (showBorder) {
@ -1065,14 +1043,14 @@ void ApplicationOverlay::TexturedHemisphere::buildVBO(const float fov,
for (int i = 0; i < stacks; i++) {
float stacksRatio = (float)i / (float)(stacks - 1); // First stack is 0.0f, last stack is 1.0f
// abs(theta) <= fov / 2.0f
float theta = PI_OVER_TWO - fov * (stacksRatio - 0.5f);
float pitch = -fov * (stacksRatio - 0.5f);
for (int j = 0; j < slices; j++) {
float slicesRatio = (float)j / (float)(slices - 1); // First slice is 0.0f, last slice is 1.0f
// abs(phi) <= fov * aspectRatio / 2.0f
float phi = fov * aspectRatio * (slicesRatio - 0.5f);
float yaw = -fov * aspectRatio * (slicesRatio - 0.5f);
vertexPtr->position = getPoint(1.0f, theta, phi);
vertexPtr->position = getPoint(yaw, pitch);
vertexPtr->uv.x = slicesRatio;
vertexPtr->uv.y = stacksRatio;
vertexPtr++;
@ -1180,3 +1158,43 @@ void ApplicationOverlay::TexturedHemisphere::render() {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
glm::vec2 ApplicationOverlay::screenToSpherical(glm::vec2 screenPos) const {
QSize screenSize = Application::getInstance()->getGLWidget()->getDeviceSize();
float yaw = -(screenPos.x / screenSize.width() - 0.5f) * MOUSE_YAW_RANGE;
float pitch = (screenPos.y / screenSize.height() - 0.5f) * MOUSE_PITCH_RANGE;
return glm::vec2(yaw, pitch);
}
glm::vec2 ApplicationOverlay::sphericalToScreen(glm::vec2 sphericalPos) const {
QSize screenSize = Application::getInstance()->getGLWidget()->getDeviceSize();
float x = (-sphericalPos.x / MOUSE_YAW_RANGE + 0.5f) * screenSize.width();
float y = (sphericalPos.y / MOUSE_PITCH_RANGE + 0.5f) * screenSize.height();
return glm::vec2(x, y);
}
glm::vec2 ApplicationOverlay::sphericalToOverlay(glm::vec2 sphericalPos) const {
QSize screenSize = Application::getInstance()->getGLWidget()->getDeviceSize();
float x = (-sphericalPos.x / (_textureFov * _textureAspectRatio) + 0.5f) * screenSize.width();
float y = (sphericalPos.y / _textureFov + 0.5f) * screenSize.height();
return glm::vec2(x, y);
}
glm::vec2 ApplicationOverlay::overlayToSpherical(glm::vec2 overlayPos) const {
QSize screenSize = Application::getInstance()->getGLWidget()->getDeviceSize();
float yaw = -(overlayPos.x / screenSize.width() - 0.5f) * _textureFov * _textureAspectRatio;
float pitch = (overlayPos.y / screenSize.height() - 0.5f) * _textureFov;
return glm::vec2(yaw, pitch);
}
glm::vec2 ApplicationOverlay::screenToOverlay(glm::vec2 screenPos) const {
return sphericalToOverlay(screenToSpherical(screenPos));
}
glm::vec2 ApplicationOverlay::overlayToScreen(glm::vec2 overlayPos) const {
return sphericalToScreen(overlayToSpherical(overlayPos));
}

View file

@ -30,10 +30,17 @@ public:
void displayOverlayTextureOculus(Camera& whichCamera);
void displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov);
void computeOculusPickRay(float x, float y, glm::vec3& direction) const;
void computeOculusPickRay(float x, float y, glm::vec3& origin, glm::vec3& direction) const;
QPoint getPalmClickLocation(const PalmData *palm) const;
bool calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const;
glm::vec2 screenToSpherical(glm::vec2 screenPos) const;
glm::vec2 sphericalToScreen(glm::vec2 sphericalPos) const;
glm::vec2 sphericalToOverlay(glm::vec2 sphericalPos) const;
glm::vec2 overlayToSpherical(glm::vec2 overlayPos) const;
glm::vec2 screenToOverlay(glm::vec2 screenPos) const;
glm::vec2 overlayToScreen(glm::vec2 overlayPos) const;
private:
// Interleaved vertex data
struct TextureVertex {

View file

@ -38,12 +38,7 @@ void NodeBounds::draw() {
// Compute ray to find selected nodes later on. We can't use the pre-computed ray in Application because it centers
// itself after the cursor disappears.
Application* application = Application::getInstance();
GLCanvas* glWidget = application->getGLWidget();
float mouseX = application->getMouseX() / (float)glWidget->width();
float mouseY = application->getMouseY() / (float)glWidget->height();
glm::vec3 mouseRayOrigin;
glm::vec3 mouseRayDirection;
application->getViewFrustum()->computePickRay(mouseX, mouseY, mouseRayOrigin, mouseRayDirection);
PickRay pickRay = application->getCamera()->computeViewPickRay(application->getMouseX(), application->getMouseY());
// Variables to keep track of the selected node and properties to draw the cube later if needed
Node* selectedNode = NULL;
@ -106,8 +101,8 @@ void NodeBounds::draw() {
float distance;
BoxFace face;
bool inside = serverBounds.contains(mouseRayOrigin);
bool colliding = serverBounds.findRayIntersection(mouseRayOrigin, mouseRayDirection, distance, face);
bool inside = serverBounds.contains(pickRay.origin);
bool colliding = serverBounds.findRayIntersection(pickRay.origin, pickRay.direction, distance, face);
// If the camera is inside a node it will be "selected" if you don't have your cursor over another node
// that you aren't inside.