mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-31 14:07:38 +00:00
Attempting to fix gamma by properly managing state.
This commit is contained in:
parent
2923174f9a
commit
b2445e4a89
5 changed files with 212 additions and 93 deletions
|
@ -163,7 +163,6 @@ namespace MWVR
|
|||
{
|
||||
if (frameMeta->mShouldRender)
|
||||
{
|
||||
viewer.blit(gc);
|
||||
gc->swapBuffersImplementation();
|
||||
std::array<CompositionLayerProjectionView, 2> layerStack{};
|
||||
layerStack[(int)Side::LEFT_SIDE].subImage = viewer.subImage(Side::LEFT_SIDE);
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
#include "../mwrender/vismask.hpp"
|
||||
|
||||
#include <osgViewer/Renderer>
|
||||
#include <osg/StateAttribute>
|
||||
#include <osg/BufferObject>
|
||||
#include <osg/VertexArrayState>
|
||||
|
||||
#include <components/debug/gldebug.hpp>
|
||||
|
||||
|
@ -44,6 +47,7 @@ namespace MWVR
|
|||
: mViewer(viewer)
|
||||
, mPreDraw(new PredrawCallback(this))
|
||||
, mPostDraw(new PostdrawCallback(this))
|
||||
, mFinalDraw(new FinaldrawCallback(this))
|
||||
, mUpdateViewCallback(new UpdateViewCallback(this))
|
||||
, mMsaaResolveTexture{}
|
||||
, mMirrorTexture{ nullptr }
|
||||
|
@ -126,13 +130,13 @@ namespace MWVR
|
|||
mSwapchainConfig[i].selectedWidth = parseResolution(xConfString[i], mSwapchainConfig[i].recommendedWidth, mSwapchainConfig[i].maxWidth);
|
||||
mSwapchainConfig[i].selectedHeight = parseResolution(yConfString[i], mSwapchainConfig[i].recommendedHeight, mSwapchainConfig[i].maxHeight);
|
||||
|
||||
mSwapchainConfig[i].selectedSamples =
|
||||
mSwapchainConfig[i].selectedSamples =
|
||||
std::max(1, // OpenXR requires a non-zero value
|
||||
std::min(mSwapchainConfig[i].maxSamples,
|
||||
std::min(mSwapchainConfig[i].maxSamples,
|
||||
Settings::Manager::getInt("antialiasing", "Video")
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
Log(Debug::Verbose) << name << " resolution: Recommended x=" << mSwapchainConfig[i].recommendedWidth << ", y=" << mSwapchainConfig[i].recommendedHeight;
|
||||
Log(Debug::Verbose) << name << " resolution: Max x=" << mSwapchainConfig[i].maxWidth << ", y=" << mSwapchainConfig[i].maxHeight;
|
||||
Log(Debug::Verbose) << name << " resolution: Selected x=" << mSwapchainConfig[i].selectedWidth << ", y=" << mSwapchainConfig[i].selectedHeight;
|
||||
|
@ -152,10 +156,10 @@ namespace MWVR
|
|||
int height = std::max(mSubImages[0].height, mSubImages[1].height);
|
||||
int samples = std::max(mSwapchainConfig[0].selectedSamples, mSwapchainConfig[1].selectedSamples);
|
||||
|
||||
mFramebuffer.reset(new VRFramebuffer(gc->getState(),width,height, samples));
|
||||
mFramebuffer.reset(new VRFramebuffer(gc->getState(), width, height, samples));
|
||||
mFramebuffer->createColorBuffer(gc);
|
||||
mFramebuffer->createDepthBuffer(gc);
|
||||
mMsaaResolveTexture.reset(new VRFramebuffer(gc->getState(),width,height,0));
|
||||
mMsaaResolveTexture.reset(new VRFramebuffer(gc->getState(), width, height, 0));
|
||||
mMsaaResolveTexture->createColorBuffer(gc);
|
||||
mGammaResolveTexture.reset(new VRFramebuffer(gc->getState(), width, height, 0));
|
||||
mGammaResolveTexture->createColorBuffer(gc);
|
||||
|
@ -179,6 +183,7 @@ namespace MWVR
|
|||
Misc::StereoView::instance().setInitialDrawCallback(new InitialDrawCallback(this));
|
||||
Misc::StereoView::instance().setPredrawCallback(mPreDraw);
|
||||
Misc::StereoView::instance().setPostdrawCallback(mPostDraw);
|
||||
Misc::StereoView::instance().setFinaldrawCallback(mFinalDraw);
|
||||
//auto cullMask = Misc::StereoView::instance().getCullMask();
|
||||
auto cullMask = ~(MWRender::VisMask::Mask_UpdateVisitor | MWRender::VisMask::Mask_SimpleWater);
|
||||
cullMask &= ~MWRender::VisMask::Mask_GUI;
|
||||
|
@ -257,108 +262,106 @@ namespace MWVR
|
|||
return shader;
|
||||
}
|
||||
|
||||
static bool applyGamma(osg::GraphicsContext* gc, VRFramebuffer& target, VRFramebuffer& source)
|
||||
static bool applyGamma(osg::RenderInfo& info, VRFramebuffer& target, VRFramebuffer& source)
|
||||
{
|
||||
// TODO: Temporary solution for applying gamma and contrast modifications
|
||||
// When OpenMW implements post processing, this will be performed there instead.
|
||||
// I'm just throwing things into static locals since this is temporary code that will be trashed later.
|
||||
static bool first = true;
|
||||
static GLuint vShader = 0;
|
||||
static GLuint fShader = 0;
|
||||
static GLuint program = 0;
|
||||
static GLuint vbo = 0;
|
||||
static GLuint gammaUniform = 0;
|
||||
static GLuint contrastUniform = 0;
|
||||
osg::State* state = info.getState();
|
||||
static const char* vSource = "#version 120\n varying vec2 uv; void main(){ gl_Position = vec4(gl_Vertex.xy*2.0 - 1, 0, 1); uv = gl_Vertex.xy;}";
|
||||
static const char* fSource = "#version 120\n varying vec2 uv; uniform sampler2D t; uniform float gamma; uniform float contrast;"
|
||||
"void main() {"
|
||||
"vec4 color1 = texture2D(t, uv);"
|
||||
"vec3 rgb = color1.rgb;"
|
||||
"rgb = (rgb - 0.5f) * contrast + 0.5f;"
|
||||
"rgb = pow(rgb, vec3(1.0/gamma));"
|
||||
"gl_FragColor = vec4(rgb, color1.a);"
|
||||
"}";
|
||||
|
||||
auto* state = gc->getState();
|
||||
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
||||
static bool first = true;
|
||||
static osg::ref_ptr<osg::Program> program = nullptr;
|
||||
static osg::ref_ptr<osg::Shader> vShader = nullptr;
|
||||
static osg::ref_ptr<osg::Shader> fShader = nullptr;
|
||||
static osg::ref_ptr<osg::Uniform> gammaUniform = nullptr;
|
||||
static GLint gammaUniformLocation = 0;
|
||||
static osg::ref_ptr<osg::Uniform> contrastUniform = nullptr;
|
||||
static GLint contrastUniformLocation = 0;
|
||||
osg::Viewport* viewport = nullptr;
|
||||
static osg::ref_ptr<osg::StateSet> stateset = nullptr;
|
||||
static osg::ref_ptr<osg::Geometry> geometry = nullptr;
|
||||
static osg::ref_ptr<osg::Texture2D> texture = nullptr;
|
||||
static osg::ref_ptr<osg::Texture::TextureObject> textureObject = nullptr;
|
||||
|
||||
static std::vector<osg::Vec4> vertices =
|
||||
{
|
||||
{0, 0, 0, 0},
|
||||
{1, 0, 0, 0},
|
||||
{1, 1, 0, 0},
|
||||
{0, 0, 0, 0},
|
||||
{1, 1, 0, 0},
|
||||
{0, 1, 0, 0}
|
||||
};
|
||||
static osg::ref_ptr<osg::Vec4Array> vertexArray = new osg::Vec4Array(vertices.begin(), vertices.end());
|
||||
|
||||
if (first)
|
||||
{
|
||||
geometry = new osg::Geometry();
|
||||
geometry->setVertexArray(vertexArray);
|
||||
geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLES, 0, 6));
|
||||
geometry->setUseDisplayList(false);
|
||||
stateset = geometry->getOrCreateStateSet();
|
||||
|
||||
vShader = new osg::Shader(osg::Shader::Type::VERTEX, vSource);
|
||||
fShader = new osg::Shader(osg::Shader::Type::FRAGMENT, fSource);
|
||||
program = new osg::Program();
|
||||
program->addShader(vShader);
|
||||
program->addShader(fShader);
|
||||
program->compileGLObjects(*state);
|
||||
stateset->setAttributeAndModes(program, osg::StateAttribute::ON);
|
||||
|
||||
texture = new osg::Texture2D();
|
||||
texture->setName("diffuseMap");
|
||||
textureObject = new osg::Texture::TextureObject(texture, source.colorBuffer(), GL_TEXTURE_2D);
|
||||
texture->setTextureObject(state->getContextID(), textureObject);
|
||||
stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::PROTECTED);
|
||||
stateset->setTextureMode(0, GL_TEXTURE_2D, osg::StateAttribute::PROTECTED);
|
||||
|
||||
gammaUniform = new osg::Uniform("gamma", Settings::Manager::getFloat("gamma", "Video"));
|
||||
contrastUniform = new osg::Uniform("contrast", Settings::Manager::getFloat("contrast", "Video"));
|
||||
stateset->addUniform(gammaUniform);
|
||||
stateset->addUniform(contrastUniform);
|
||||
|
||||
geometry->compileGLObjects(info);
|
||||
|
||||
first = false;
|
||||
|
||||
const char* vSource = "#version 120\n varying vec2 uv; void main(){ gl_Position = vec4(gl_Vertex.xy*2.0 - 1, 0, 1); uv = gl_Vertex.xy;}";
|
||||
const char* fSource = "#version 120\n varying vec2 uv; uniform sampler2D t; uniform float gamma; uniform float contrast;"
|
||||
"void main() {"
|
||||
"vec4 color1 = texture2D(t, uv);"
|
||||
"vec3 rgb = color1.rgb;"
|
||||
"rgb = (rgb - 0.5f) * contrast + 0.5f;"
|
||||
"rgb = pow(rgb, vec3(1.0/gamma));"
|
||||
"gl_FragColor = vec4(rgb, color1.a);"
|
||||
"}";
|
||||
|
||||
vShader = createShader(gl, vSource, GL_VERTEX_SHADER);
|
||||
fShader = createShader(gl, fSource, GL_FRAGMENT_SHADER);
|
||||
|
||||
program = gl->glCreateProgram();
|
||||
gl->glAttachShader(program, vShader);
|
||||
gl->glAttachShader(program, fShader);
|
||||
gl->glLinkProgram(program);
|
||||
|
||||
GLint isCompiled = 0;
|
||||
gl->glGetProgramiv(program, GL_LINK_STATUS, &isCompiled);
|
||||
if (isCompiled == GL_FALSE)
|
||||
{
|
||||
GLint maxLength = 0;
|
||||
gl->glGetProgramInfoLog(program, 0, &maxLength, nullptr);
|
||||
std::vector<GLchar> infoLog(maxLength);
|
||||
gl->glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);
|
||||
gl->glDeleteProgram(program);
|
||||
program = 0;
|
||||
Log(Debug::Error) << "Failed to link program: " << infoLog.data();
|
||||
}
|
||||
|
||||
if (program)
|
||||
{
|
||||
GLfloat vertices[] =
|
||||
{
|
||||
0, 0, 0, 0,
|
||||
1, 0, 0, 0,
|
||||
1, 1, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
1, 1, 0, 0,
|
||||
0, 1, 0, 0
|
||||
};
|
||||
|
||||
gl->glGenBuffers(1, &vbo);
|
||||
gl->glBindBuffer(GL_ARRAY_BUFFER_ARB, vbo);
|
||||
gl->glBufferData(GL_ARRAY_BUFFER_ARB, sizeof(vertices), vertices, GL_STATIC_DRAW);
|
||||
|
||||
gammaUniform = gl->glGetUniformLocation(program, "gamma");
|
||||
contrastUniform = gl->glGetUniformLocation(program, "contrast");
|
||||
}
|
||||
}
|
||||
|
||||
target.bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||
target.bindFramebuffer(state->getGraphicsContext(), GL_FRAMEBUFFER_EXT);
|
||||
|
||||
if (program > 0)
|
||||
{
|
||||
gl->glUseProgram(program);
|
||||
gl->glBindVertexArray(0);
|
||||
glViewport(0, 0, target.width(), target.height());
|
||||
// OSG does not pop statesets until after the final draw callback. Unrelated statesets may therefore still be on the stack at this point.
|
||||
// Pop these to avoid inheriting arbitrary state from these. They will not be used more in this frame.
|
||||
state->popAllStateSets();
|
||||
state->apply();
|
||||
|
||||
gl->glUniform1f(gammaUniform, Settings::Manager::getFloat("gamma", "Video"));
|
||||
gl->glUniform1f(contrastUniform, Settings::Manager::getFloat("contrast", "Video"));
|
||||
gammaUniform->set(Settings::Manager::getFloat("gamma", "Video"));
|
||||
contrastUniform->set(Settings::Manager::getFloat("contrast", "Video"));
|
||||
state->pushStateSet(stateset);
|
||||
state->apply();
|
||||
|
||||
if(!viewport)
|
||||
viewport = new osg::Viewport(0, 0, target.width(), target.height());
|
||||
viewport->setViewport(0, 0, target.width(), target.height());
|
||||
viewport->apply(*state);
|
||||
|
||||
gl->glBindBuffer(GL_ARRAY_BUFFER_ARB, vbo);
|
||||
glVertexPointer(4, GL_FLOAT, 0, 0);
|
||||
gl->glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, source.colorBuffer());
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
glDisable(GL_BLEND);
|
||||
geometry->draw(info);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||
|
||||
gl->glUseProgram(0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glEnable(GL_BLEND);
|
||||
gl->glBindBuffer(GL_ARRAY_BUFFER_ARB, 0);
|
||||
state->popStateSet();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void VRViewer::blit(osg::GraphicsContext* gc)
|
||||
void VRViewer::blit(osg::RenderInfo& info)
|
||||
{
|
||||
if (mMirrorTextureShouldBeCleanedUp)
|
||||
{
|
||||
|
@ -368,21 +371,23 @@ namespace MWVR
|
|||
if (!mMirrorTextureEnabled)
|
||||
return;
|
||||
|
||||
auto* state = info.getState();
|
||||
auto* gc = state->getGraphicsContext();
|
||||
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
||||
|
||||
auto* traits = SDLUtil::GraphicsWindowSDL2::findContext(*mViewer)->getTraits();
|
||||
int screenWidth = traits->width;
|
||||
int screenHeight = traits->height;
|
||||
if (!mMirrorTexture)
|
||||
{
|
||||
;
|
||||
mMirrorTexture.reset(new VRFramebuffer(gc->getState(),
|
||||
mMirrorTexture.reset(new VRFramebuffer(state,
|
||||
screenWidth,
|
||||
screenHeight,
|
||||
0));
|
||||
mMirrorTexture->createColorBuffer(gc);
|
||||
}
|
||||
|
||||
auto* state = gc->getState();
|
||||
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
||||
|
||||
int mirrorWidth = screenWidth / mMirrorTextureViews.size();
|
||||
|
||||
|
@ -393,7 +398,7 @@ namespace MWVR
|
|||
mFramebuffer->blit(gc, 0, 0, mFramebuffer->width(), mFramebuffer->height(), 0, 0, mMsaaResolveTexture->width(), mMsaaResolveTexture->height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
bool shouldDoGamma = Settings::Manager::getBool("gamma postprocessing", "VR Debug");
|
||||
if (!shouldDoGamma || !applyGamma(gc, *mGammaResolveTexture, *mMsaaResolveTexture))
|
||||
if (!shouldDoGamma || !applyGamma(info, *mGammaResolveTexture, *mMsaaResolveTexture))
|
||||
{
|
||||
mGammaResolveTexture->bindFramebuffer(gc, GL_FRAMEBUFFER_EXT);
|
||||
mMsaaResolveTexture->blit(gc, 0, 0, mMsaaResolveTexture->width(), mMsaaResolveTexture->height(), 0, 0, mGammaResolveTexture->width(), mGammaResolveTexture->height(), GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
@ -484,6 +489,20 @@ namespace MWVR
|
|||
}
|
||||
}
|
||||
|
||||
void VRViewer::finalDrawCallback(osg::RenderInfo& info)
|
||||
{
|
||||
auto* session = Environment::get().getSession();
|
||||
auto* frameMeta = session->getFrame(VRSession::FramePhase::Draw).get();
|
||||
|
||||
if (frameMeta->mShouldSyncFrameLoop)
|
||||
{
|
||||
if (frameMeta->mShouldRender)
|
||||
{
|
||||
blit(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VRViewer::swapBuffersCallback(osg::GraphicsContext* gc)
|
||||
{
|
||||
auto* session = Environment::get().getSession();
|
||||
|
@ -508,4 +527,10 @@ namespace MWVR
|
|||
{
|
||||
mViewer->updateView(left, right);
|
||||
}
|
||||
|
||||
void VRViewer::FinaldrawCallback::operator()(osg::RenderInfo& info, Misc::StereoView::StereoDrawCallback::View view) const
|
||||
{
|
||||
if (view != Misc::StereoView::StereoDrawCallback::View::Left)
|
||||
mViewer->finalDrawCallback(info);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -90,6 +90,20 @@ namespace MWVR
|
|||
VRViewer* mViewer;
|
||||
};
|
||||
|
||||
class FinaldrawCallback : public Misc::StereoView::StereoDrawCallback
|
||||
{
|
||||
public:
|
||||
FinaldrawCallback(VRViewer* viewer)
|
||||
: mViewer(viewer)
|
||||
{}
|
||||
|
||||
void operator()(osg::RenderInfo& info, Misc::StereoView::StereoDrawCallback::View view) const override;
|
||||
|
||||
private:
|
||||
|
||||
VRViewer* mViewer;
|
||||
};
|
||||
|
||||
static const std::array<const char*, 2> sViewNames;
|
||||
enum class MirrorTextureEye
|
||||
{
|
||||
|
@ -108,7 +122,8 @@ namespace MWVR
|
|||
void initialDrawCallback(osg::RenderInfo& info);
|
||||
void preDrawCallback(osg::RenderInfo& info);
|
||||
void postDrawCallback(osg::RenderInfo& info);
|
||||
void blit(osg::GraphicsContext* gc);
|
||||
void finalDrawCallback(osg::RenderInfo& info);
|
||||
void blit(osg::RenderInfo& gc);
|
||||
void configureXR(osg::GraphicsContext* gc);
|
||||
void configureCallbacks();
|
||||
void setupMirrorTexture();
|
||||
|
@ -128,6 +143,7 @@ namespace MWVR
|
|||
osg::ref_ptr<osgViewer::Viewer> mViewer = nullptr;
|
||||
osg::ref_ptr<PredrawCallback> mPreDraw{ nullptr };
|
||||
osg::ref_ptr<PostdrawCallback> mPostDraw{ nullptr };
|
||||
osg::ref_ptr<FinaldrawCallback> mFinalDraw{ nullptr };
|
||||
std::shared_ptr<UpdateViewCallback> mUpdateViewCallback{ nullptr };
|
||||
bool mRenderingReady{ false };
|
||||
|
||||
|
|
|
@ -461,11 +461,13 @@ namespace Misc
|
|||
auto initialDrawCB = mInitialDrawCallback;
|
||||
auto predrawCB = mPreDrawCallback;
|
||||
auto postDrawCB = mPostDrawCallback;
|
||||
auto finalDrawCB = mFinalDrawCallback;
|
||||
|
||||
setCullCallback(nullptr);
|
||||
setInitialDrawCallback(nullptr);
|
||||
setPostdrawCallback(nullptr);
|
||||
setPredrawCallback(nullptr);
|
||||
setFinaldrawCallback(nullptr);
|
||||
|
||||
disableStereo();
|
||||
mTechnique = technique;
|
||||
|
@ -475,6 +477,7 @@ namespace Misc
|
|||
setInitialDrawCallback(initialDrawCB);
|
||||
setPostdrawCallback(predrawCB);
|
||||
setPredrawCallback(postDrawCB);
|
||||
setFinaldrawCallback(finalDrawCB);
|
||||
}
|
||||
|
||||
void StereoView::update()
|
||||
|
@ -705,6 +708,12 @@ namespace Misc
|
|||
mMainCamera->setPostDrawCallback(cb);
|
||||
}
|
||||
|
||||
void StereoView::setFinaldrawCallback(osg::ref_ptr<osg::Camera::DrawCallback> cb)
|
||||
{
|
||||
mFinalDrawCallback = cb;
|
||||
mMainCamera->setFinalDrawCallback(cb);
|
||||
}
|
||||
|
||||
void StereoView::setCullCallback(osg::ref_ptr<osg::NodeCallback> cb)
|
||||
{
|
||||
mMainCamera->setCullCallback(cb);
|
||||
|
@ -746,4 +755,47 @@ namespace Misc
|
|||
{
|
||||
return mRightCamera->getViewMatrix();
|
||||
}
|
||||
void StereoView::StereoDrawCallback::operator()(osg::RenderInfo& info) const
|
||||
{
|
||||
// OSG does not give any information about stereo in these callbacks so i have to infer this myself.
|
||||
// And hopefully OSG won't change this behaviour.
|
||||
|
||||
View view = View::Both;
|
||||
|
||||
auto camera = info.getCurrentCamera();
|
||||
auto viewport = camera->getViewport();
|
||||
|
||||
// Find the current scene view.
|
||||
osg::GraphicsOperation* graphicsOperation = info.getCurrentCamera()->getRenderer();
|
||||
osgViewer::Renderer* renderer = dynamic_cast<osgViewer::Renderer*>(graphicsOperation);
|
||||
for (int i = 0; i < 2; i++) // OSG alternates between two sceneviews.
|
||||
{
|
||||
auto* sceneView = renderer->getSceneView(i);
|
||||
// The render info argument is a member of scene view, allowing me to identify it.
|
||||
if (&sceneView->getRenderInfo() == &info)
|
||||
{
|
||||
// Now i can simply examine the viewport.
|
||||
auto activeViewport = static_cast<osg::Viewport*>(sceneView->getLocalStateSet()->getAttribute(osg::StateAttribute::Type::VIEWPORT, 0));
|
||||
if (activeViewport)
|
||||
{
|
||||
if (activeViewport->width() == viewport->width() && activeViewport->height() == viewport->height())
|
||||
view = View::Both;
|
||||
else if (activeViewport->x() == viewport->x() && activeViewport->y() == viewport->y())
|
||||
view = View::Left;
|
||||
else
|
||||
view = View::Right;
|
||||
}
|
||||
else
|
||||
{
|
||||
// OSG always sets a viewport in the local stateset if osg's stereo is enabled.
|
||||
// If it isn't, assume both.
|
||||
view = View::Both;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
operator()(info, view);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,6 +89,29 @@ namespace Misc
|
|||
GeometryShader_IndexedViewports, //!< Frustum camera culls and draws stereo into indexed viewports using an automatically generated geometry shader.
|
||||
};
|
||||
|
||||
//! A draw callback that adds stereo information to the operator.
|
||||
//! The stereo information is an enum describing which of the views the callback concerns.
|
||||
//! With some stereo methods, there is only one callback, in which case the enum will be 'Both'.
|
||||
//!
|
||||
//! A typical use case of this callback is to prevent firing callbacks twice and correctly identifying the last/first callback.
|
||||
struct StereoDrawCallback : public osg::Camera::DrawCallback
|
||||
{
|
||||
public:
|
||||
enum class View
|
||||
{
|
||||
Both, Left, Right
|
||||
};
|
||||
public:
|
||||
StereoDrawCallback()
|
||||
{}
|
||||
|
||||
void operator()(osg::RenderInfo& info) const override;
|
||||
|
||||
virtual void operator()(osg::RenderInfo& info, View view) const = 0;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
static StereoView& instance();
|
||||
|
||||
//! Adds two cameras in stereo to the mainCamera.
|
||||
|
@ -121,6 +144,9 @@ namespace Misc
|
|||
//! Set the postdraw callback on the appropriate camera object
|
||||
void setPostdrawCallback(osg::ref_ptr<osg::Camera::DrawCallback> cb);
|
||||
|
||||
//! Set the final draw callback on the appropriate camera object
|
||||
void setFinaldrawCallback(osg::ref_ptr<osg::Camera::DrawCallback> cb);
|
||||
|
||||
//! Set the cull callback on the appropriate camera object
|
||||
void setCullCallback(osg::ref_ptr<osg::NodeCallback> cb);
|
||||
|
||||
|
@ -180,6 +206,7 @@ namespace Misc
|
|||
osg::ref_ptr<osg::Camera::DrawCallback> mInitialDrawCallback{ nullptr };
|
||||
osg::ref_ptr<osg::Camera::DrawCallback> mPreDrawCallback{ nullptr };
|
||||
osg::ref_ptr<osg::Camera::DrawCallback> mPostDrawCallback{ nullptr };
|
||||
osg::ref_ptr<osg::Camera::DrawCallback> mFinalDrawCallback{ nullptr };
|
||||
};
|
||||
|
||||
//! Overrides all stereo-related states/uniforms to disable stereo for the scene rendered by camera
|
||||
|
|
Loading…
Reference in a new issue