Working on oculus rendering

This commit is contained in:
Brad Davis 2015-05-27 12:42:05 -07:00
parent e8868478d2
commit 810db39233
10 changed files with 392 additions and 129 deletions

View file

@ -9,8 +9,8 @@ if (WIN32)
ExternalProject_Add(
${EXTERNAL_NAME}
URL http://static.oculus.com/sdk-downloads/ovr_sdk_win_0.5.0.1.zip
URL_MD5 d3fc4c02db9be5ff08af4ef4c97b32f9
URL http://static.oculus.com/sdk-downloads/0.6.0.0/1431634088/ovr_sdk_win_0.6.0.0.zip
URL_MD5 a3dfdab037a854fdcf7e6033fa8d7028
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""

View file

@ -21,7 +21,7 @@
#include <glm/gtc/quaternion.hpp>
#include <RegisteredMetaTypes.h>
enum class Eye {
enum Eye {
Left,
Right,
Mono

View file

@ -0,0 +1,41 @@
//
// OculusBaseDisplayPlugin.cpp
//
// Created by Bradley Austin Davis on 2014/04/13.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "OculusBaseDisplayPlugin.h"
#include <ViewFrustum.h>
#include "OculusHelpers.h"
void OculusBaseDisplayPlugin::activate() {
ovr_for_each_eye([&](ovrEyeType eye) {
ovrEyeRenderDesc erd = ovrHmd_GetRenderDesc(_hmd, eye, _hmd->MaxEyeFov[eye]);
ovrMatrix4f ovrPerspectiveProjection =
ovrMatrix4f_Projection(erd.Fov, DEFAULT_NEAR_CLIP, DEFAULT_FAR_CLIP, ovrProjection_RightHanded);
_eyeProjections[eye] = toGlm(ovrPerspectiveProjection);
_eyeOffsets[eye] = erd.HmdToEyeViewOffset;
});
}
void OculusBaseDisplayPlugin::deactivate() {
}
void OculusBaseDisplayPlugin::preRender() {
ovrHmd_GetEyePoses(_hmd, _frameIndex, _eyeOffsets, _eyePoses, nullptr);
}
glm::mat4 OculusBaseDisplayPlugin::getProjection(Eye eye, const glm::mat4& baseProjection) const {
return _eyeProjections[eye];
}
glm::mat4 OculusBaseDisplayPlugin::getModelview(Eye eye, const glm::mat4& baseModelview) const {
return toGlm(_eyePoses[eye]);
}

View file

@ -0,0 +1,32 @@
//
// OculusBaseDisplayPlugin.h
//
// Created by Bradley Austin Davis on 2014/04/13.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#include "HmdDisplayPlugin.h"
#include <OVR_CAPI.h>
class OculusBaseDisplayPlugin : public HmdDisplayPlugin {
public:
// Stereo specific methods
virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const;
virtual glm::mat4 getModelview(Eye eye, const glm::mat4& baseModelview) const;
virtual void activate();
virtual void deactivate();
virtual void preRender();
virtual void configureRendering() = 0;
protected:
ovrHmd _hmd;
unsigned int _frameIndex{ 0 };
ovrPosef _eyePoses[2];
ovrVector3f _eyeOffsets[2];
glm::mat4 _eyeProjections[2];
};

View file

@ -1,96 +0,0 @@
//
// OculusDisplayPlugin.cpp
//
// Created by Bradley Austin Davis on 2014/04/13.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "OculusDisplayPlugin.h"
#include <OVR_CAPI.h>
bool OculusDisplayPlugin::isSupported() {
ovr_Initialize();
bool result = false;
if (ovrHmd_Detect() != 0) {
result = true;
}
ovr_Shutdown();
return result;
}
void OculusDisplayPlugin::activate() {
}
void OculusDisplayPlugin::deactivate() {
}
void OculusDisplayPlugin::init() {
}
void OculusDisplayPlugin::deinit() {
}
void OculusDisplayPlugin::overrideOffAxisFrustum(
float& left, float& right, float& bottom, float& top,
float& nearVal, float& farVal,
glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const {
}
#if 0
// Set the desired FBO texture size. If it hasn't changed, this does nothing.
// Otherwise, it must rebuild the FBOs
if (OculusManager::isConnected()) {
DependencyManager::get<TextureCache>()->setFrameBufferSize(OculusManager::getRenderTargetSize());
} else {
#endif
#if 0
// Update camera position
if (!OculusManager::isConnected()) {
_myCamera.update(1.0f / _fps);
}
#endif
#if 0
if (OculusManager::isConnected()) {
//When in mirror mode, use camera rotation. Otherwise, use body rotation
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
OculusManager::display(_myCamera.getRotation(), _myCamera.getPosition(), _myCamera);
} else {
OculusManager::display(_myAvatar->getWorldAlignedOrientation(), _myAvatar->getDefaultEyePosition(), _myCamera);
}
_myCamera.update(1.0f / _fps);
#endif
#if 0
OculusManager::abandonCalibration();
#endif
#if 0
if (OculusManager::isConnected()) {
return getMouseX() >= 0 && getMouseX() <= _glWidget->getDeviceWidth() &&
getMouseY() >= 0 && getMouseY() <= _glWidget->getDeviceHeight();
}
#endif
#if 0
if (OculusManager::isConnected()) {
glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseX(), getTrueMouseY()));
return pos.x;
}
#endif
#if 0
if (OculusManager::isConnected()) {
glm::vec2 pos = _applicationOverlay.screenToOverlay(glm::vec2(getTrueMouseX(), getTrueMouseY()));
return pos.y;
}
#endif

View file

@ -1,30 +0,0 @@
//
// OculusBaseDisplayPlugin.h
//
// Created by Bradley Austin Davis on 2014/04/13.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#include "HmdDisplayPlugin.h"
#include <functional>
class OculusDisplayPlugin : public HmdDisplayPlugin {
public:
virtual bool isSupported();
virtual void init();
virtual void deinit();
virtual void activate();
virtual void deactivate();
virtual void overrideOffAxisFrustum(
float& left, float& right, float& bottom, float& top,
float& nearVal, float& farVal,
glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const;
};

View file

@ -0,0 +1,75 @@
//
// Created by Bradley Austin Davis on 2015/05/26.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#include <OVR_CAPI.h>
#include <GLMHelpers.h>
#include <glm/gtc/type_ptr.hpp>
// Convenience method for looping over each eye with a lambda
template <typename Function>
inline void ovr_for_each_eye(Function function) {
for (ovrEyeType eye = ovrEyeType::ovrEye_Left;
eye < ovrEyeType::ovrEye_Count;
eye = static_cast<ovrEyeType>(eye + 1)) {
function(eye);
}
}
inline glm::mat4 toGlm(const ovrMatrix4f & om) {
return glm::transpose(glm::make_mat4(&om.M[0][0]));
}
inline glm::mat4 toGlm(const ovrFovPort & fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) {
return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true));
}
inline glm::vec3 toGlm(const ovrVector3f & ov) {
return glm::make_vec3(&ov.x);
}
inline glm::vec2 toGlm(const ovrVector2f & ov) {
return glm::make_vec2(&ov.x);
}
inline glm::uvec2 toGlm(const ovrSizei & ov) {
return glm::uvec2(ov.w, ov.h);
}
inline glm::quat toGlm(const ovrQuatf & oq) {
return glm::make_quat(&oq.x);
}
inline glm::mat4 toGlm(const ovrPosef & op) {
glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation));
glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position));
return translation * orientation;
}
inline ovrMatrix4f ovrFromGlm(const glm::mat4 & m) {
ovrMatrix4f result;
glm::mat4 transposed(glm::transpose(m));
memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16);
return result;
}
inline ovrVector3f ovrFromGlm(const glm::vec3 & v) {
return{ v.x, v.y, v.z };
}
inline ovrVector2f ovrFromGlm(const glm::vec2 & v) {
return{ v.x, v.y };
}
inline ovrSizei ovrFromGlm(const glm::uvec2 & v) {
return{ (int)v.x, (int)v.y };
}
inline ovrQuatf ovrFromGlm(const glm::quat & q) {
return{ q.x, q.y, q.z, q.w };
}

View file

@ -0,0 +1,200 @@
//
// Created by Bradley Austin Davis on 2014/04/13.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "OculusWin32DisplayPlugin.h"
#include <OVR_CAPI_GL.h>
bool OculusWin32DisplayPlugin::isSupported() {
ovr_Initialize();
bool result = false;
if (ovrHmd_Detect() != 0) {
result = true;
}
ovr_Shutdown();
return result;
}
// A basic wrapper for constructing a framebuffer with a renderbuffer
// for the depth attachment and an undefined type for the color attachement
// This allows us to reuse the basic framebuffer code for both the Mirror
// FBO as well as the Oculus swap textures we will use to render the scene
// Though we don't really need depth at all for the mirror FBO, or even an
// FBO, but using one means I can just use a glBlitFramebuffer to get it onto
// the screen.
template <typename C = GLuint, typename D = GLuint>
struct FramebufferWrapper {
glm::uvec2 size;
oglplus::Framebuffer fbo;
C color{ 0 };
GLuint depth{ 0 };
virtual ~FramebufferWrapper() {
}
FramebufferWrapper() {}
virtual void Init(const uvec2 & size) {
this->size = size;
if (!fbo) {
glGenFramebuffers(1, &fbo);
}
initColor();
initDepth();
initDone();
}
template <typename F>
void Bound(F f) {
Bound(GL_FRAMEBUFFER, f);
}
template <typename F>
void Bound(GLenum target, F f) {
glBindFramebuffer(target, fbo);
onBind(target);
f();
onUnbind(target);
glBindFramebuffer(target, 0);
}
void Viewport() {
glViewport(0, 0, size.x, size.y);
}
private:
virtual void onBind(GLenum target) {}
virtual void onUnbind(GLenum target) {}
virtual void initDepth() {
glGenRenderbuffers(1, &depth);
assert(depth);
glBindRenderbuffer(GL_RENDERBUFFER, depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size.x, size.y);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
virtual void initColor() = 0;
virtual void initDone() = 0;
};
// A base class for FBO wrappers that need to use the Oculus C
// API to manage textures via ovrHmd_CreateSwapTextureSetGL,
// ovrHmd_CreateMirrorTextureGL, etc
template <typename C>
struct RiftFramebufferWrapper : public FramebufferWrapper<C> {
ovrHmd hmd;
RiftFramebufferWrapper(const ovrHmd & hmd) : hmd(hmd) {};
};
// A wrapper for constructing and using a swap texture set,
// where each frame you draw to a texture via the FBO,
// then submit it and increment to the next texture.
// The Oculus SDK manages the creation and destruction of
// the textures
struct SwapTextureFramebufferWrapper : public RiftFramebufferWrapper<ovrSwapTextureSet*>{
SwapTextureFramebufferWrapper(const ovrHmd & hmd)
: RiftFramebufferWrapper(hmd) {}
~SwapTextureFramebufferWrapper() {
if (color) {
ovrHmd_DestroySwapTextureSet(hmd, color);
color = nullptr;
}
}
void Increment() {
++color->CurrentIndex;
color->CurrentIndex %= color->TextureCount;
}
protected:
virtual void initColor() {
if (color) {
ovrHmd_DestroySwapTextureSet(hmd, color);
color = nullptr;
}
if (!OVR_SUCCESS(ovrHmd_CreateSwapTextureSetGL(hmd, GL_RGBA, size.x, size.y, &color))) {
FAIL("Unable to create swap textures");
}
for (int i = 0; i < color->TextureCount; ++i) {
ovrGLTexture& ovrTex = (ovrGLTexture&)color->Textures[i];
glBindTexture(GL_TEXTURE_2D, ovrTex.OGL.TexId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
glBindTexture(GL_TEXTURE_2D, 0);
}
virtual void initDone() {
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depth);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
virtual void onBind(GLenum target) {
ovrGLTexture& tex = (ovrGLTexture&)(color->Textures[color->CurrentIndex]);
glFramebufferTexture2D(target, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.OGL.TexId, 0);
}
virtual void onUnbind(GLenum target) {
glFramebufferTexture2D(target, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
}
};
using SwapTexFboPtr = std::shared_ptr<SwapTextureFramebufferWrapper>;
// We use a FBO to wrap the mirror texture because it makes it easier to
// render to the screen via glBlitFramebuffer
struct MirrorFramebufferWrapper : public RiftFramebufferWrapper<ovrGLTexture*>{
float targetAspect;
MirrorFramebufferWrapper(const ovrHmd & hmd)
: RiftFramebufferWrapper(hmd) {}
~MirrorFramebufferWrapper() {
if (color) {
ovrHmd_DestroyMirrorTexture(hmd, (ovrTexture*)color);
color = nullptr;
}
}
void Resize(const uvec2 & size) {
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
this->size = size;
initColor();
initDone();
}
private:
virtual void initDepth() {
}
void initColor() {
if (color) {
ovrHmd_DestroyMirrorTexture(hmd, (ovrTexture*)color);
color = nullptr;
}
ovrResult result = ovrHmd_CreateMirrorTextureGL(hmd, GL_RGBA, size.x, size.y, (ovrTexture**)&color);
assert(OVR_SUCCESS(result));
}
void initDone() {
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color->OGL.TexId, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
};
using MirrorFboPtr = std::shared_ptr<MirrorFramebufferWrapper>;

View file

@ -0,0 +1,15 @@
//
// Created by Bradley Austin Davis on 2015/05/26.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#include "OculusBaseDisplayPlugin.h"
class OculusWin32DisplayPlugin : public OculusBaseDisplayPlugin {
public:
virtual bool isSupported();
};

View file

@ -0,0 +1,26 @@
//
// Created by Bradley Austin Davis on 2015/05/26.
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#define OGLPLUS_USE_GLEW 1
#define OGLPLUS_USE_GLCOREARB_H 0
#define OGLPLUS_USE_BOOST_CONFIG 1
#define OGLPLUS_NO_SITE_CONFIG 1
#define OGLPLUS_LOW_PROFILE 1
#include <GL/glew.h>
#include <oglplus/gl.hpp>
#include <oglplus/all.hpp>
#include <oglplus/interop/glm.hpp>
#include <oglplus/bound/texture.hpp>
#include <oglplus/bound/framebuffer.hpp>
#include <oglplus/bound/renderbuffer.hpp>
#include <oglplus/shapes/wrapper.hpp>
#include <oglplus/shapes/plane.hpp>
typedef std::shared_ptr<oglplus::Framebuffer> FramebufferPtr;