mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-02 04:15:32 +00:00
RTT camera
This commit is contained in:
parent
de2354abda
commit
f25be2a44a
6 changed files with 173 additions and 82 deletions
|
@ -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)
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue