1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-02-02 06:45:31 +00:00

RTT camera

This commit is contained in:
Mads Buvik Sandvei 2020-03-01 23:05:38 +01:00
parent de2354abda
commit f25be2a44a
6 changed files with 173 additions and 82 deletions

View file

@ -4,10 +4,82 @@
#include "openxrmanagerimpl.hpp"
#include <openxr/openxr.h>
#include <osg/Texture2D>
#include <osg/ClipNode>
#include <osg/FrontFace>
#include <components/sceneutil/visitor.hpp>
#include <components/sceneutil/shadow.hpp>
#include <osgViewer/Renderer>
#include "../mwrender/util.hpp"
namespace MWVR
{
class Menus : public osg::Camera
{
public:
Menus()
{
setRenderOrder(osg::Camera::PRE_RENDER);
setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
setReferenceFrame(osg::Camera::ABSOLUTE_RF);
setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water"));
setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
setName("ReflectionCamera");
setCullMask(MWRender::Mask_GUI);
setNodeMask(MWRender::Mask_RenderToTexture);
unsigned int rttSize = 1000;
setViewport(0, 0, rttSize, rttSize);
// No need for Update traversal since the mSceneRoot is already updated as part of the main scene graph
// A double update would mess with the light collection (in addition to being plain redundant)
setUpdateCallback(new MWRender::NoTraverseCallback);
mMenuTexture = new osg::Texture2D;
mMenuTexture->setTextureSize(rttSize, rttSize);
mMenuTexture->setInternalFormat(GL_RGB);
mMenuTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
mMenuTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
mMenuTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
mMenuTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
attach(osg::Camera::COLOR_BUFFER, mMenuTexture);
// XXX: should really flip the FrontFace on each renderable instead of forcing clockwise.
//osg::ref_ptr<osg::FrontFace> frontFace(new osg::FrontFace);
//frontFace->setMode(osg::FrontFace::CLOCKWISE);
//getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON);
//mClipCullNode = new ClipCullNode;
//addChild(mClipCullNode);
SceneUtil::ShadowManager::disableShadowsForStateSet(getOrCreateStateSet());
}
void setScene(osg::Node* scene)
{
if (mScene)
removeChild(mScene);
mScene = scene;
addChild(scene);
}
osg::Texture2D* getMenuTexture() const
{
return mMenuTexture.get();
}
private:
osg::ref_ptr<osg::Texture2D> mMenuTexture;
osg::ref_ptr<osg::Node> mScene;
};
class PredrawCallback : public osg::Camera::DrawCallback
{
public:
@ -38,7 +110,7 @@ namespace MWVR
OpenXRMenu::OpenXRMenu(
osg::ref_ptr<osg::Group> parent,
osg::ref_ptr<osg::Group> menuSubgraph,
osg::ref_ptr<osg::Node> menuSubgraph,
const std::string& title,
osg::Vec2 extent_meters,
Pose pose,
@ -50,11 +122,6 @@ namespace MWVR
, mParent(parent)
, mMenuSubgraph(menuSubgraph)
{
mMenuTexture->setTextureSize(width, height);
mMenuTexture->setInternalFormat(GL_RGBA);
mMenuTexture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR);
mMenuTexture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR);
osg::ref_ptr<osg::Vec3Array> vertices{ new osg::Vec3Array(4) };
osg::ref_ptr<osg::Vec2Array> texCoords{ new osg::Vec2Array(4) };
osg::ref_ptr<osg::Vec3Array> normals{ new osg::Vec3Array(1) };
@ -87,7 +154,10 @@ namespace MWVR
mGeometry->setDataVariance(osg::Object::DYNAMIC);
mGeometry->setSupportsDisplayList(false);
mStateSet->setTextureAttributeAndModes(0, mMenuTexture, osg::StateAttribute::ON);
mMenuCamera = new Menus();
mMenuCamera->setScene(menuSubgraph);
mStateSet->setTextureAttributeAndModes(0, menuTexture(), osg::StateAttribute::ON);
mStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
mGeometry->setStateSet(mStateSet);
@ -104,58 +174,29 @@ namespace MWVR
mMenuCamera->setClearColor(clearColor);
mMenuCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// This is based on the osgprerender example.
// I'm not sure this part is meaningful when all i'm rendering is the GUI.
//auto& bs = mMenuSubgraph->getBound();
//if (!bs.valid())
// Log(Debug::Verbose) << "OpenXRMenu: Invalid bound";
//float znear = 1.0f * bs.radius();
//float zfar = 3.0f * bs.radius();
//float proj_top = 0.25f * znear;
//float proj_right = 0.5f * znear;
//znear *= 0.9f;
//zfar *= 1.1f;
//mMenuCamera->setProjectionMatrixAsFrustum(-proj_right, proj_right, -proj_top, proj_top, znear, zfar);
//mMenuCamera->setViewMatrixAsLookAt(bs.center() - osg::Vec3(0.0f, 2.0f, 0.0f) * bs.radius(), bs.center(), osg::Vec3(0.0f, 0.0f, 1.0f));
mMenuCamera->setViewMatrix(viewer->getCamera()->getViewMatrix());
mMenuCamera->setProjectionMatrix(viewer->getCamera()->getProjectionMatrix());
// Camera details
mMenuCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
mMenuCamera->setViewport(0, 0, width, height);
mMenuCamera->setRenderOrder(osg::Camera::PRE_RENDER);
mMenuCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
mMenuCamera->attach(osg::Camera::COLOR_BUFFER, mMenuTexture);
mMenuCamera->addChild(mMenuSubgraph);
mMenuCamera->setCullMask(MWRender::Mask_GUI);
mMenuCamera->setPreDrawCallback(new PredrawCallback(this));
mMenuCamera->setPostDrawCallback(new PostdrawCallback(this));
mMenuCamera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
mMenuCamera->setAllowEventFocus(false);
mParent->addChild(mMenuCamera);
mParent->addChild(mMenuCamera.get());
}
OpenXRMenu::~OpenXRMenu()
{
mParent->removeChild(mTransform);
mParent->removeChild(mMenuCamera);
mParent->removeChild(mMenuCamera.get());
}
void OpenXRMenu::updateCallback()
{
}
void OpenXRMenu::postRenderCallback(osg::RenderInfo& renderInfo)
osg::Camera* OpenXRMenu::camera()
{
Log(Debug::Verbose) << "Menu: PostRender";
return mMenuCamera.get();
}
osg::ref_ptr<osg::Texture2D> OpenXRMenu::menuTexture()
{
if (mMenuCamera)
return mMenuCamera->getMenuTexture();
return nullptr;
}
void OpenXRMenu::updatePose(Pose pose)
@ -164,10 +205,6 @@ namespace MWVR
mTransform->setPosition(pose.position);
}
void OpenXRMenu::preRenderCallback(osg::RenderInfo& renderInfo)
{
Log(Debug::Verbose) << "Menu: PreRender";
}
OpenXRMenuManager::OpenXRMenuManager(
osg::ref_ptr<osgViewer::Viewer> viewer)

View file

@ -13,12 +13,14 @@
struct XrCompositionLayerQuad;
namespace MWVR
{
class Menus;
class OpenXRMenu
{
public:
OpenXRMenu(
osg::ref_ptr<osg::Group> parent,
osg::ref_ptr<osg::Group> menuSubgraph,
osg::ref_ptr<osg::Node> menuSubgraph,
const std::string& title,
osg::Vec2 extent_meters,
Pose pose,
@ -32,21 +34,22 @@ namespace MWVR
void preRenderCallback(osg::RenderInfo& renderInfo);
void postRenderCallback(osg::RenderInfo& renderInfo);
osg::Camera* camera() { return mMenuCamera; }
osg::Camera* camera();
osg::ref_ptr<osg::Texture2D> menuTexture();
void updatePose(Pose pose);
protected:
public:
std::string mTitle;
osg::ref_ptr<osg::Group> mParent;
osg::ref_ptr<osg::Geometry> mGeometry{ new osg::Geometry };
osg::ref_ptr<osg::Geode> mGeode{ new osg::Geode };
osg::ref_ptr<osg::PositionAttitudeTransform> mTransform{ new osg::PositionAttitudeTransform };
osg::ref_ptr<osg::Group> mMenuSubgraph;
osg::ref_ptr<osg::Camera> mMenuCamera{ new osg::Camera };
osg::ref_ptr<osg::Texture2D> mMenuTexture{ new osg::Texture2D };
osg::ref_ptr<osg::Node> mMenuSubgraph;
osg::ref_ptr<osg::StateSet> mStateSet{ new osg::StateSet };
osg::ref_ptr<Menus> mMenuCamera;
};
class OpenXRMenuManager
@ -61,11 +64,13 @@ namespace MWVR
void updatePose(void);
OpenXRMenu* getMenu(void) const { return mMenu.get(); }
private:
Pose mPose{};
osg::ref_ptr<osgViewer::Viewer> mOsgViewer{ nullptr };
osg::ref_ptr<osg::Group> mMenusRoot{ new osg::Group };
osg::ref_ptr<osg::Group> mGuiRoot{ new osg::Group };
osg::ref_ptr<osg::Node> mGuiRoot{ nullptr };
std::unique_ptr<OpenXRMenu> mMenu{ nullptr };
};
}

View file

@ -107,6 +107,8 @@ namespace MWVR
auto state = gc->getState();
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, mFBO);
Log(Debug::Verbose) << "Bound FBO: " << mFBO;
}
void OpenXRTextureBuffer::endFrame(osg::GraphicsContext* gc, uint32_t blitTarget)
@ -130,4 +132,17 @@ namespace MWVR
gl->glBlitFramebuffer(0, 0, mWidth, mHeight, x, y, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
}
void OpenXRTextureBuffer::blit(osg::GraphicsContext* gc, int x, int y, int w, int h, int blitTarget)
{
auto* state = gc->getState();
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
gl->glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, mBlitFBO);
gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, mFBO);
gl->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, blitTarget, 0);
gl->glBlitFramebuffer(0, 0, mWidth, mHeight, x, y, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
gl->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0);
gl->glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, 0);
gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
}
}

View file

@ -26,9 +26,11 @@ namespace MWVR
void endFrame(osg::GraphicsContext* gc, uint32_t blitTarget);
uint32_t fbo(void) const { return mFBO; }
uint32_t colorBuffer(void) const { return mColorBuffer; }
//! Blit to region in currently bound draw fbo
void blit(osg::GraphicsContext* gc, int x, int y, int w, int h);
void blit(osg::GraphicsContext* gc, int x, int y, int w, int h, int target);
private:
// Set aside a weak pointer to the constructor state to use when freeing FBOs, if no state is given to destroy()

View file

@ -38,7 +38,7 @@ namespace MWVR {
camera->setClearColor(clearColor);
camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
camera->setRenderOrder(osg::Camera::PRE_RENDER, eye);
camera->setRenderOrder(osg::Camera::PRE_RENDER, eye + 2);
camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
camera->setAllowEventFocus(false);
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
@ -50,8 +50,12 @@ namespace MWVR {
return camera.release();
}
static GLint wfbo = 0;
static GLint rfbo = 0;
void OpenXRView::prerenderCallback(osg::RenderInfo& renderInfo)
{
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING_EXT, &wfbo);
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING_EXT, &rfbo);
if (mSwapchain)
{
mSwapchain->beginFrame(renderInfo.getState()->getGraphicsContext());
@ -66,6 +70,10 @@ namespace MWVR {
mTimer.checkpoint("Postrender");
Log(Debug::Verbose) << "XRView: PostRender";
auto state = renderInfo.getState();
auto gl = osg::GLExtensions::Get(state->getContextID(), false);
gl->glBindFramebuffer(GL_DRAW_FRAMEBUFFER_EXT, wfbo);
gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, rfbo);
}
void OpenXRView::swapBuffers(osg::GraphicsContext* gc)

View file

@ -123,12 +123,14 @@ namespace MWVR
leftCamera->setPreDrawCallback(mPreDraw);
rightCamera->setPreDrawCallback(mPreDraw);
leftCamera->setPostDrawCallback(mPostDraw);
rightCamera->setPostDrawCallback(mPostDraw);
//leftCamera->setPostDrawCallback(mPostDraw);
//rightCamera->setPostDrawCallback(mPostDraw);
leftCamera->setFinalDrawCallback(mPostDraw);
rightCamera->setFinalDrawCallback(mPostDraw);
// Stereo cameras should only draw the scene (AR layers should later add minimap, health, etc.)
//leftCamera->setCullMask(~MWRender::Mask_GUI);
//rightCamera->setCullMask(~MWRender::Mask_GUI);
leftCamera->setCullMask(~MWRender::Mask_GUI);
rightCamera->setCullMask(~MWRender::Mask_GUI);
leftCamera->setName("LeftEye");
rightCamera->setName("RightEye");
@ -153,19 +155,6 @@ namespace MWVR
// It's just convenient.
mMirrorTextureSwapchain.reset(new OpenXRSwapchain(xr, context->getState(), config));
//auto menuView = new OpenXRMenu(xr, config, context->getState(), "MainMenu", osg::Vec2(1.f, 1.f));
//mViews["MenuView"] = menuView;
//auto menuCamera = mCameras["MenuView"] = menuView->createCamera(2, clearColor, context);
//mMenus.reset(new OpenXRMenu(mMenusRoot, "MainMenu", osg::Vec2(1.f, 1.f), MWVR::Pose(), config.width, config.height, osg::Vec4(0.f, 0.f, 0.f, 0.f), context));
//auto menuCamera = mMenus->camera();
//menuCamera->setCullMask(MWRender::Mask_GUI);
//menuCamera->setName("MenuView");
//menuCamera->setPreDrawCallback(mPreDraw);
//menuCamera->setPostDrawCallback(mPostDraw);
//mViewer->addSlave(menuCamera, true);
mViewer->getSlave(0)._updateSlaveCallback = new OpenXRWorldView::UpdateSlaveCallback(xr, session, leftView, context);
mViewer->getSlave(1)._updateSlaveCallback = new OpenXRWorldView::UpdateSlaveCallback(xr, session, rightView, context);
@ -173,14 +162,13 @@ namespace MWVR
mainCamera->getGraphicsContext()->setSwapCallback(new OpenXRViewer::SwapBuffersCallback(this));
mainCamera->setGraphicsContext(nullptr);
session->setLayer(OpenXRLayerStack::WORLD_VIEW_LAYER, this);
//session->setLayer(OpenXRLayerStack::MENU_VIEW_LAYER, dynamic_cast<OpenXRLayer*>(mViews["MenuView"].get()));
mConfigured = true;
}
void OpenXRViewer::blitEyesToMirrorTexture(osg::GraphicsContext* gc, bool includeMenu)
{
includeMenu = false;
//includeMenu = false;
mMirrorTextureSwapchain->beginFrame(gc);
int mirror_width = 0;
@ -193,15 +181,51 @@ namespace MWVR
mViews["RightEye"]->swapchain().renderBuffer()->blit(gc, 0, 0, mirror_width, mMirrorTextureSwapchain->height());
mViews["LeftEye"]->swapchain().renderBuffer()->blit(gc, mirror_width, 0, 2 * mirror_width, mMirrorTextureSwapchain->height());
//if(includeMenu)
// mViews["MenuView"]->swapchain().renderBuffer()->blit(gc, 2 * mirror_width, 0, 3 * mirror_width, mMirrorTextureSwapchain->height());
auto* state = gc->getState();
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
if (includeMenu)
{
auto menuManager = OpenXREnvironment::get().getMenuManager();
if (menuManager)
{
auto menu = menuManager->getMenu();
if (menu)
{
auto texture = menu->menuTexture();
if (texture)
{
auto textureObject = texture->getTextureObject(state->getContextID());
if (textureObject)
{
auto textureId = textureObject->id();
Log(Debug::Verbose) << "texture id: " << textureId;
GLuint fbo = 0;
gl->glGenFramebuffers(1, &fbo);
gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, fbo);
gl->glFramebufferTexture2D(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, textureId, 0);
gl->glBlitFramebuffer(0, 0, texture->getTextureWidth(), texture->getTextureHeight(), 2 * mirror_width, 0, 3 * mirror_width, mMirrorTextureSwapchain->height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
gl->glFramebufferTexture2D(GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0);
gl->glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, 0);
gl->glDeleteFramebuffers(1, &fbo);
}
else
{
Log(Debug::Warning) << "Texture object was null";
}
}
}
}
}
mMirrorTextureSwapchain->endFrame(gc);
auto* state = gc->getState();
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
mMirrorTextureSwapchain->renderBuffer()->blit(gc, 0, 0, mMirrorTextureSwapchain->width(), mMirrorTextureSwapchain->height());
}