mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-03-17 19:20:49 +00:00
Merge branch 'multiview-refactor' into 'master'
[Multiview] refactoring See merge request OpenMW/openmw!2122
This commit is contained in:
commit
54db3a97bb
@ -25,6 +25,7 @@
|
|||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
#include <components/sceneutil/nodecallback.hpp>
|
#include <components/sceneutil/nodecallback.hpp>
|
||||||
#include <components/sceneutil/depth.hpp>
|
#include <components/sceneutil/depth.hpp>
|
||||||
|
#include <components/stereo/multiview.hpp>
|
||||||
|
|
||||||
#include "../mwbase/world.hpp"
|
#include "../mwbase/world.hpp"
|
||||||
#include "../mwworld/class.hpp"
|
#include "../mwworld/class.hpp"
|
||||||
@ -179,20 +180,6 @@ namespace MWRender
|
|||||||
camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
|
camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
|
||||||
SceneUtil::setCameraClearDepth(camera);
|
SceneUtil::setCameraClearDepth(camera);
|
||||||
|
|
||||||
#ifdef OSG_HAS_MULTIVIEW
|
|
||||||
if (shouldDoTextureArray())
|
|
||||||
{
|
|
||||||
auto* viewUniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "viewMatrixMultiView", 2);
|
|
||||||
auto* projUniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "projectionMatrixMultiView", 2);
|
|
||||||
viewUniform->setElement(0, osg::Matrix::identity());
|
|
||||||
viewUniform->setElement(1, osg::Matrix::identity());
|
|
||||||
projUniform->setElement(0, mPerspectiveMatrix);
|
|
||||||
projUniform->setElement(1, mPerspectiveMatrix);
|
|
||||||
mGroup->getOrCreateStateSet()->addUniform(viewUniform, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
|
||||||
mGroup->getOrCreateStateSet()->addUniform(projUniform, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
camera->setNodeMask(Mask_RenderToTexture);
|
camera->setNodeMask(Mask_RenderToTexture);
|
||||||
camera->addChild(mGroup);
|
camera->addChild(mGroup);
|
||||||
};
|
};
|
||||||
@ -202,6 +189,9 @@ namespace MWRender
|
|||||||
if(mCameraStateset)
|
if(mCameraStateset)
|
||||||
camera->setStateSet(mCameraStateset);
|
camera->setStateSet(mCameraStateset);
|
||||||
camera->setViewMatrix(mViewMatrix);
|
camera->setViewMatrix(mViewMatrix);
|
||||||
|
|
||||||
|
if (shouldDoTextureArray())
|
||||||
|
Stereo::setMultiviewMatrices(mGroup->getOrCreateStateSet(), { mPerspectiveMatrix, mPerspectiveMatrix });
|
||||||
};
|
};
|
||||||
|
|
||||||
void addChild(osg::Node* node)
|
void addChild(osg::Node* node)
|
||||||
|
@ -702,16 +702,7 @@ void LocalMapRenderToTexture::setDefaults(osg::Camera* camera)
|
|||||||
stateset->addUniform(new osg::Uniform("projectionMatrix", static_cast<osg::Matrixf>(mProjectionMatrix)), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
stateset->addUniform(new osg::Uniform("projectionMatrix", static_cast<osg::Matrixf>(mProjectionMatrix)), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||||
|
|
||||||
if (Stereo::getMultiview())
|
if (Stereo::getMultiview())
|
||||||
{
|
Stereo::setMultiviewMatrices(stateset, { mProjectionMatrix, mProjectionMatrix });
|
||||||
auto* viewUniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "viewMatrixMultiView", 2);
|
|
||||||
auto* projUniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "projectionMatrixMultiView", 2);
|
|
||||||
viewUniform->setElement(0, osg::Matrix::identity());
|
|
||||||
viewUniform->setElement(1, osg::Matrix::identity());
|
|
||||||
projUniform->setElement(0, mProjectionMatrix);
|
|
||||||
projUniform->setElement(1, mProjectionMatrix);
|
|
||||||
stateset->addUniform(viewUniform, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
|
||||||
stateset->addUniform(projUniform, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// assign large value to effectively turn off fog
|
// assign large value to effectively turn off fog
|
||||||
// shaders don't respect glDisable(GL_FOG)
|
// shaders don't respect glDisable(GL_FOG)
|
||||||
|
@ -67,25 +67,8 @@ namespace MWRender
|
|||||||
|
|
||||||
static void attachCloneOfTemplate(osg::FrameBufferObject* fbo, osg::Camera::BufferComponent component, osg::Texture* tex)
|
static void attachCloneOfTemplate(osg::FrameBufferObject* fbo, osg::Camera::BufferComponent component, osg::Texture* tex)
|
||||||
{
|
{
|
||||||
switch (tex->getTextureTarget())
|
osg::ref_ptr<osg::Texture> clone = static_cast<osg::Texture*>(tex->clone(osg::CopyOp::SHALLOW_COPY));
|
||||||
{
|
fbo->setAttachment(component, Stereo::createMultiviewCompatibleAttachment(clone));
|
||||||
case GL_TEXTURE_2D:
|
|
||||||
{
|
|
||||||
auto* tex2d = new osg::Texture2D(*static_cast<osg::Texture2D*>(tex));
|
|
||||||
fbo->setAttachment(component, osg::FrameBufferAttachment(tex2d));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_2D_ARRAY:
|
|
||||||
{
|
|
||||||
#ifdef OSG_HAS_MULTIVIEW
|
|
||||||
auto* tex2dArray = new osg::Texture2DArray(*static_cast<osg::Texture2DArray*>(tex));
|
|
||||||
fbo->setAttachment(component, osg::FrameBufferAttachment(tex2dArray, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, 0));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw std::logic_error("Invalid texture type received");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PingPongCanvas::drawImplementation(osg::RenderInfo& renderInfo) const
|
void PingPongCanvas::drawImplementation(osg::RenderInfo& renderInfo) const
|
||||||
|
@ -9,10 +9,6 @@
|
|||||||
#include <osg/Texture3D>
|
#include <osg/Texture3D>
|
||||||
#include <osg/Texture2DArray>
|
#include <osg/Texture2DArray>
|
||||||
|
|
||||||
#ifdef OSG_HAS_MULTIVIEW
|
|
||||||
#include <osg/Texture2DMultisampleArray>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
#include <components/sceneutil/depth.hpp>
|
#include <components/sceneutil/depth.hpp>
|
||||||
#include <components/sceneutil/color.hpp>
|
#include <components/sceneutil/color.hpp>
|
||||||
@ -75,53 +71,6 @@ namespace
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void setTextureSize(osg::Texture* tex, int w, int h)
|
|
||||||
{
|
|
||||||
switch (tex->getTextureTarget())
|
|
||||||
{
|
|
||||||
case GL_TEXTURE_2D:
|
|
||||||
static_cast<osg::Texture2D*>(tex)->setTextureSize(w, h);
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_2D_ARRAY:
|
|
||||||
static_cast<osg::Texture2DArray*>(tex)->setTextureSize(w, h, 2);
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_2D_MULTISAMPLE:
|
|
||||||
static_cast<osg::Texture2DMultisample*>(tex)->setTextureSize(w, h);
|
|
||||||
break;
|
|
||||||
#ifdef OSG_HAS_MULTIVIEW
|
|
||||||
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
|
|
||||||
static_cast<osg::Texture2DMultisampleArray*>(tex)->setTextureSize(w, h, 2);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
default:
|
|
||||||
throw std::logic_error("Invalid texture type received");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void setAttachment(osg::FrameBufferObject* fbo, osg::Camera::BufferComponent component, osg::Texture* tex)
|
|
||||||
{
|
|
||||||
switch (tex->getTextureTarget())
|
|
||||||
{
|
|
||||||
case GL_TEXTURE_2D:
|
|
||||||
{
|
|
||||||
auto* tex2d = static_cast<osg::Texture2D*>(tex);
|
|
||||||
fbo->setAttachment(component, osg::FrameBufferAttachment(tex2d));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GL_TEXTURE_2D_ARRAY:
|
|
||||||
{
|
|
||||||
#ifdef OSG_HAS_MULTIVIEW
|
|
||||||
auto* tex2dArray = static_cast<osg::Texture2DArray*>(tex);
|
|
||||||
fbo->setAttachment(component, osg::FrameBufferAttachment(tex2dArray, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, 0));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw std::logic_error("Invalid texture type received");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class Usage
|
enum class Usage
|
||||||
{
|
{
|
||||||
RENDER_BUFFER,
|
RENDER_BUFFER,
|
||||||
@ -136,35 +85,7 @@ namespace
|
|||||||
return osg::FrameBufferAttachment(attachment);
|
return osg::FrameBufferAttachment(attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
osg::FrameBufferAttachment attachment;
|
auto texture = Stereo::createMultiviewCompatibleTexture(width, height, samples);
|
||||||
|
|
||||||
#ifdef OSG_HAS_MULTIVIEW
|
|
||||||
if (Stereo::getMultiview())
|
|
||||||
{
|
|
||||||
if (samples > 1)
|
|
||||||
{
|
|
||||||
attachment = osg::FrameBufferAttachment(new osg::Texture2DMultisampleArray(), osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
attachment = osg::FrameBufferAttachment(new osg::Texture2DArray(), osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if (samples > 1)
|
|
||||||
{
|
|
||||||
attachment = osg::FrameBufferAttachment(new osg::Texture2DMultisample());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
attachment = osg::FrameBufferAttachment(new osg::Texture2D());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
osg::Texture* texture = attachment.getTexture();
|
|
||||||
setTextureSize(texture, width, height);
|
|
||||||
texture->setSourceFormat(template_->getSourceFormat());
|
texture->setSourceFormat(template_->getSourceFormat());
|
||||||
texture->setSourceType(template_->getSourceType());
|
texture->setSourceType(template_->getSourceType());
|
||||||
texture->setInternalFormat(template_->getInternalFormat());
|
texture->setInternalFormat(template_->getInternalFormat());
|
||||||
@ -173,7 +94,7 @@ namespace
|
|||||||
texture->setWrap(osg::Texture::WRAP_S, template_->getWrap(osg::Texture2D::WRAP_S));
|
texture->setWrap(osg::Texture::WRAP_S, template_->getWrap(osg::Texture2D::WRAP_S));
|
||||||
texture->setWrap(osg::Texture::WRAP_T, template_->getWrap(osg::Texture2D::WRAP_T));
|
texture->setWrap(osg::Texture::WRAP_T, template_->getWrap(osg::Texture2D::WRAP_T));
|
||||||
|
|
||||||
return attachment;
|
return Stereo::createMultiviewCompatibleAttachment(texture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -547,15 +468,15 @@ namespace MWRender
|
|||||||
if (!tex)
|
if (!tex)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
setTextureSize(tex, width, height);
|
Stereo::setMultiviewCompatibleTextureSize(tex, width, height);
|
||||||
tex->dirtyTextureObject();
|
tex->dirtyTextureObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
fbos[FBO_Primary] = new osg::FrameBufferObject;
|
fbos[FBO_Primary] = new osg::FrameBufferObject;
|
||||||
setAttachment(fbos[FBO_Primary], osg::Camera::COLOR_BUFFER0, textures[Tex_Scene]);
|
fbos[FBO_Primary]->setAttachment(osg::Camera::COLOR_BUFFER0, Stereo::createMultiviewCompatibleAttachment(textures[Tex_Scene]));
|
||||||
if (mNormals && mNormalsSupported)
|
if (mNormals && mNormalsSupported)
|
||||||
setAttachment(fbos[FBO_Primary], osg::Camera::COLOR_BUFFER1, textures[Tex_Normal]);
|
fbos[FBO_Primary]->setAttachment(osg::Camera::COLOR_BUFFER1, Stereo::createMultiviewCompatibleAttachment(textures[Tex_Normal]));
|
||||||
setAttachment(fbos[FBO_Primary], osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, textures[Tex_Depth]);
|
fbos[FBO_Primary]->setAttachment(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, Stereo::createMultiviewCompatibleAttachment(textures[Tex_Depth]));
|
||||||
|
|
||||||
fbos[FBO_FirstPerson] = new osg::FrameBufferObject;
|
fbos[FBO_FirstPerson] = new osg::FrameBufferObject;
|
||||||
|
|
||||||
@ -581,20 +502,20 @@ namespace MWRender
|
|||||||
fbos[FBO_FirstPerson]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, colorRB);
|
fbos[FBO_FirstPerson]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, colorRB);
|
||||||
|
|
||||||
fbos[FBO_Intercept] = new osg::FrameBufferObject;
|
fbos[FBO_Intercept] = new osg::FrameBufferObject;
|
||||||
setAttachment(fbos[FBO_Intercept], osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, textures[Tex_Scene]);
|
fbos[FBO_Intercept]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, Stereo::createMultiviewCompatibleAttachment(textures[Tex_Scene]));
|
||||||
setAttachment(fbos[FBO_Intercept], osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, textures[Tex_Normal]);
|
fbos[FBO_Intercept]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, Stereo::createMultiviewCompatibleAttachment(textures[Tex_Normal]));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
setAttachment(fbos[FBO_FirstPerson], osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, textures[Tex_Scene]);
|
fbos[FBO_FirstPerson]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, Stereo::createMultiviewCompatibleAttachment(textures[Tex_Scene]));
|
||||||
if (mNormals && mNormalsSupported)
|
if (mNormals && mNormalsSupported)
|
||||||
setAttachment(fbos[FBO_FirstPerson], osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, textures[Tex_Normal]);
|
fbos[FBO_FirstPerson]->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER1, Stereo::createMultiviewCompatibleAttachment(textures[Tex_Normal]));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (textures[Tex_OpaqueDepth])
|
if (textures[Tex_OpaqueDepth])
|
||||||
{
|
{
|
||||||
fbos[FBO_OpaqueDepth] = new osg::FrameBufferObject;
|
fbos[FBO_OpaqueDepth] = new osg::FrameBufferObject;
|
||||||
setAttachment(fbos[FBO_OpaqueDepth], osg::FrameBufferObject::BufferComponent::PACKED_DEPTH_STENCIL_BUFFER, textures[Tex_OpaqueDepth]);
|
fbos[FBO_OpaqueDepth]->setAttachment(osg::FrameBufferObject::BufferComponent::PACKED_DEPTH_STENCIL_BUFFER, Stereo::createMultiviewCompatibleAttachment(textures[Tex_OpaqueDepth]));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
@ -799,7 +720,7 @@ namespace MWRender
|
|||||||
else
|
else
|
||||||
texture = new osg::Texture2D;
|
texture = new osg::Texture2D;
|
||||||
}
|
}
|
||||||
setTextureSize(texture, width, height);
|
Stereo::setMultiviewCompatibleTextureSize(texture, width, height);
|
||||||
texture->setSourceFormat(GL_RGBA);
|
texture->setSourceFormat(GL_RGBA);
|
||||||
texture->setSourceType(GL_UNSIGNED_BYTE);
|
texture->setSourceType(GL_UNSIGNED_BYTE);
|
||||||
texture->setInternalFormat(GL_RGBA);
|
texture->setInternalFormat(GL_RGBA);
|
||||||
|
@ -615,9 +615,7 @@ namespace MWRender
|
|||||||
protected:
|
protected:
|
||||||
void setDefaults(osg::StateSet* stateset) override
|
void setDefaults(osg::StateSet* stateset) override
|
||||||
{
|
{
|
||||||
if (Stereo::getMultiview())
|
if (!Stereo::getMultiview())
|
||||||
stateset->addUniform(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "projectionMatrixMultiView", 2), osg::StateAttribute::OVERRIDE);
|
|
||||||
else
|
|
||||||
stateset->addUniform(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "projectionMatrix"), osg::StateAttribute::OVERRIDE);
|
stateset->addUniform(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "projectionMatrix"), osg::StateAttribute::OVERRIDE);
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -626,7 +624,7 @@ namespace MWRender
|
|||||||
{
|
{
|
||||||
if (Stereo::getMultiview())
|
if (Stereo::getMultiview())
|
||||||
{
|
{
|
||||||
auto* projectionMatrixMultiViewUniform = stateset->getUniform("projectionMatrixMultiView");
|
std::array<osg::Matrix, 2> projectionMatrices;
|
||||||
auto& sm = Stereo::Manager::instance();
|
auto& sm = Stereo::Manager::instance();
|
||||||
|
|
||||||
for (int view : {0, 1})
|
for (int view : {0, 1})
|
||||||
@ -636,8 +634,10 @@ namespace MWRender
|
|||||||
for (int col : {0, 1, 2})
|
for (int col : {0, 1, 2})
|
||||||
viewOffsetMatrix(3, col) = 0;
|
viewOffsetMatrix(3, col) = 0;
|
||||||
|
|
||||||
projectionMatrixMultiViewUniform->setElement(view, viewOffsetMatrix * projectionMatrix);
|
projectionMatrices[view] = viewOffsetMatrix * projectionMatrix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Stereo::setMultiviewMatrices(stateset, projectionMatrices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void applyLeft(osg::StateSet* stateset, osgUtil::CullVisitor* /*cv*/) override
|
void applyLeft(osg::StateSet* stateset, osgUtil::CullVisitor* /*cv*/) override
|
||||||
|
@ -4,10 +4,6 @@
|
|||||||
#include <osg/Texture2D>
|
#include <osg/Texture2D>
|
||||||
#include <osg/Texture2DArray>
|
#include <osg/Texture2DArray>
|
||||||
|
|
||||||
#ifdef OSG_HAS_MULTIVIEW
|
|
||||||
#include <osg/Texture2DMultisampleArray>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <osgUtil/RenderStage>
|
#include <osgUtil/RenderStage>
|
||||||
|
|
||||||
#include <components/shader/shadermanager.hpp>
|
#include <components/shader/shadermanager.hpp>
|
||||||
@ -70,14 +66,11 @@ namespace MWRender
|
|||||||
|
|
||||||
if (Stereo::getMultiview())
|
if (Stereo::getMultiview())
|
||||||
{
|
{
|
||||||
if (!mMultiviewDepthResolveLeftSource[frameId])
|
if (!mMultiviewResolve[frameId])
|
||||||
setupMultiviewDepthResolveBuffers(frameId);
|
{
|
||||||
mMultiviewDepthResolveLeftTarget[frameId]->apply(state, osg::FrameBufferObject::BindTarget::DRAW_FRAMEBUFFER);
|
mMultiviewResolve[frameId] = std::make_unique<Stereo::MultiviewFramebufferResolve>(msaaFbo ? msaaFbo : fbo, opaqueFbo, GL_DEPTH_BUFFER_BIT);
|
||||||
mMultiviewDepthResolveLeftSource[frameId]->apply(state, osg::FrameBufferObject::BindTarget::READ_FRAMEBUFFER);
|
}
|
||||||
ext->glBlitFramebuffer(0, 0, tex->getTextureWidth(), tex->getTextureHeight(), 0, 0, tex->getTextureWidth(), tex->getTextureHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
mMultiviewResolve[frameId]->resolveImplementation(state);
|
||||||
mMultiviewDepthResolveRightTarget[frameId]->apply(state, osg::FrameBufferObject::BindTarget::DRAW_FRAMEBUFFER);
|
|
||||||
mMultiviewDepthResolveRightSource[frameId]->apply(state, osg::FrameBufferObject::BindTarget::READ_FRAMEBUFFER);
|
|
||||||
ext->glBlitFramebuffer(0, 0, tex->getTextureWidth(), tex->getTextureHeight(), 0, 0, tex->getTextureWidth(), tex->getTextureHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -107,42 +100,8 @@ namespace MWRender
|
|||||||
|
|
||||||
void TransparentDepthBinCallback::dirtyFrame(int frameId)
|
void TransparentDepthBinCallback::dirtyFrame(int frameId)
|
||||||
{
|
{
|
||||||
mMultiviewDepthResolveLeftSource[frameId] = mMultiviewDepthResolveRightSource[frameId] = nullptr;
|
if (mMultiviewResolve[frameId])
|
||||||
mMultiviewDepthResolveLeftTarget[frameId] = mMultiviewDepthResolveRightTarget[frameId] = nullptr;
|
mMultiviewResolve[frameId]->dirty();
|
||||||
}
|
|
||||||
|
|
||||||
osg::FrameBufferAttachment makeSingleLayerAttachmentFromMultilayerAttachment(osg::FrameBufferAttachment attachment, int layer)
|
|
||||||
{
|
|
||||||
osg::Texture* tex = attachment.getTexture();
|
|
||||||
|
|
||||||
if (tex->getTextureTarget() == GL_TEXTURE_2D_ARRAY)
|
|
||||||
return osg::FrameBufferAttachment(static_cast<osg::Texture2DArray*>(tex), layer, 0);
|
|
||||||
|
|
||||||
#ifdef OSG_HAS_MULTIVIEW
|
|
||||||
if (tex->getTextureTarget() == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
|
|
||||||
return osg::FrameBufferAttachment(static_cast<osg::Texture2DMultisampleArray*>(tex), layer, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Log(Debug::Error) << "Attempted to extract a layer from an unlayered texture";
|
|
||||||
|
|
||||||
return osg::FrameBufferAttachment();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TransparentDepthBinCallback::setupMultiviewDepthResolveBuffers(int frameId)
|
|
||||||
{
|
|
||||||
const osg::FrameBufferObject::BufferComponent component = osg::FrameBufferObject::BufferComponent::PACKED_DEPTH_STENCIL_BUFFER;
|
|
||||||
const auto& sourceFbo = mMsaaFbo[frameId] ? mMsaaFbo[frameId] : mFbo[frameId];
|
|
||||||
const auto& sourceAttachment = sourceFbo->getAttachment(component);
|
|
||||||
mMultiviewDepthResolveLeftSource[frameId] = new osg::FrameBufferObject;
|
|
||||||
mMultiviewDepthResolveLeftSource[frameId]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(sourceAttachment, 0));
|
|
||||||
mMultiviewDepthResolveRightSource[frameId] = new osg::FrameBufferObject;
|
|
||||||
mMultiviewDepthResolveRightSource[frameId]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(sourceAttachment, 1));
|
|
||||||
const auto& targetFbo = mOpaqueFbo[frameId];
|
|
||||||
const auto& targetAttachment = targetFbo->getAttachment(component);
|
|
||||||
mMultiviewDepthResolveLeftTarget[frameId] = new osg::FrameBufferObject;
|
|
||||||
mMultiviewDepthResolveLeftTarget[frameId]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(targetAttachment, 0));
|
|
||||||
mMultiviewDepthResolveRightTarget[frameId] = new osg::FrameBufferObject;
|
|
||||||
mMultiviewDepthResolveRightTarget[frameId]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(targetAttachment, 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,11 @@ namespace Shader
|
|||||||
class ShaderManager;
|
class ShaderManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Stereo
|
||||||
|
{
|
||||||
|
class MultiviewFramebufferResolve;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MWRender
|
namespace MWRender
|
||||||
{
|
{
|
||||||
class TransparentDepthBinCallback : public osgUtil::RenderBin::DrawCallback
|
class TransparentDepthBinCallback : public osgUtil::RenderBin::DrawCallback
|
||||||
@ -24,16 +29,12 @@ namespace MWRender
|
|||||||
|
|
||||||
void drawImplementation(osgUtil::RenderBin* bin, osg::RenderInfo& renderInfo, osgUtil::RenderLeaf*& previous) override;
|
void drawImplementation(osgUtil::RenderBin* bin, osg::RenderInfo& renderInfo, osgUtil::RenderLeaf*& previous) override;
|
||||||
void dirtyFrame(int frameId);
|
void dirtyFrame(int frameId);
|
||||||
void setupMultiviewDepthResolveBuffers(int frameId);
|
|
||||||
|
|
||||||
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mFbo;
|
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mFbo;
|
||||||
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mMsaaFbo;
|
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mMsaaFbo;
|
||||||
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mOpaqueFbo;
|
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mOpaqueFbo;
|
||||||
|
|
||||||
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mMultiviewDepthResolveLeftSource;
|
std::array<std::unique_ptr<Stereo::MultiviewFramebufferResolve>, 2> mMultiviewResolve;
|
||||||
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mMultiviewDepthResolveRightSource;
|
|
||||||
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mMultiviewDepthResolveLeftTarget;
|
|
||||||
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mMultiviewDepthResolveRightTarget;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
osg::ref_ptr<osg::StateSet> mStateSet;
|
osg::ref_ptr<osg::StateSet> mStateSet;
|
||||||
|
@ -200,21 +200,20 @@ namespace SceneUtil
|
|||||||
if (camera->getBufferAttachmentMap().count(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER))
|
if (camera->getBufferAttachmentMap().count(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER))
|
||||||
vdd->mDepthTexture = camera->getBufferAttachmentMap()[osg::Camera::PACKED_DEPTH_STENCIL_BUFFER]._texture;
|
vdd->mDepthTexture = camera->getBufferAttachmentMap()[osg::Camera::PACKED_DEPTH_STENCIL_BUFFER]._texture;
|
||||||
|
|
||||||
#ifdef OSG_HAS_MULTIVIEW
|
|
||||||
if (shouldDoTextureArray())
|
if (shouldDoTextureArray())
|
||||||
{
|
{
|
||||||
// Create any buffer attachments not added in setDefaults
|
// Create any buffer attachments not added in setDefaults
|
||||||
if (camera->getBufferAttachmentMap().count(osg::Camera::COLOR_BUFFER) == 0)
|
if (camera->getBufferAttachmentMap().count(osg::Camera::COLOR_BUFFER) == 0)
|
||||||
{
|
{
|
||||||
vdd->mColorTexture = createTextureArray(mColorBufferInternalFormat);
|
vdd->mColorTexture = createTextureArray(mColorBufferInternalFormat);
|
||||||
camera->attach(osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, mGenerateMipmaps, mSamples);
|
camera->attach(osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, Stereo::osgFaceControlledByMultiviewShader(), mGenerateMipmaps, mSamples);
|
||||||
SceneUtil::attachAlphaToCoverageFriendlyFramebufferToCamera(camera, osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, mGenerateMipmaps);
|
SceneUtil::attachAlphaToCoverageFriendlyFramebufferToCamera(camera, osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, Stereo::osgFaceControlledByMultiviewShader(), mGenerateMipmaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (camera->getBufferAttachmentMap().count(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER) == 0)
|
if (camera->getBufferAttachmentMap().count(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER) == 0)
|
||||||
{
|
{
|
||||||
vdd->mDepthTexture = createTextureArray(mDepthBufferInternalFormat);
|
vdd->mDepthTexture = createTextureArray(mDepthBufferInternalFormat);
|
||||||
camera->attach(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, vdd->mDepthTexture, 0, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, false, mSamples);
|
camera->attach(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, vdd->mDepthTexture, 0, Stereo::osgFaceControlledByMultiviewShader(), false, mSamples);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldDoTextureView())
|
if (shouldDoTextureView())
|
||||||
@ -226,7 +225,6 @@ namespace SceneUtil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
// Create any buffer attachments not added in setDefaults
|
// Create any buffer attachments not added in setDefaults
|
||||||
if (camera->getBufferAttachmentMap().count(osg::Camera::COLOR_BUFFER) == 0)
|
if (camera->getBufferAttachmentMap().count(osg::Camera::COLOR_BUFFER) == 0)
|
||||||
|
@ -27,31 +27,32 @@
|
|||||||
|
|
||||||
#include <components/settings/settings.hpp>
|
#include <components/settings/settings.hpp>
|
||||||
|
|
||||||
|
#include <components/stereo/multiview.hpp>
|
||||||
|
|
||||||
#include <components/misc/stringops.hpp>
|
#include <components/misc/stringops.hpp>
|
||||||
#include "frustum.hpp"
|
#include "frustum.hpp"
|
||||||
|
|
||||||
namespace Stereo
|
namespace Stereo
|
||||||
{
|
{
|
||||||
#ifdef OSG_HAS_MULTIVIEW
|
struct MultiviewFrustumCallback final : public Stereo::InitialFrustumCallback
|
||||||
struct MultiviewFrustumCallback final : public osg::CullSettings::InitialFrustumCallback
|
|
||||||
{
|
{
|
||||||
MultiviewFrustumCallback(StereoFrustumManager* sfm)
|
MultiviewFrustumCallback(StereoFrustumManager* sfm, osg::Camera* camera)
|
||||||
: mSfm(sfm)
|
: Stereo::InitialFrustumCallback(camera)
|
||||||
|
, mSfm(sfm)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setInitialFrustum(osg::CullStack& cullStack, osg::Polytope& frustum) const override
|
void setInitialFrustum(osg::CullStack& cullStack, osg::BoundingBoxd& bb, bool& nearCulling, bool& farCulling) const override
|
||||||
{
|
{
|
||||||
auto cm = cullStack.getCullingMode();
|
auto cm = cullStack.getCullingMode();
|
||||||
bool nearCulling = !!(cm & osg::CullSettings::NEAR_PLANE_CULLING);
|
nearCulling = !!(cm & osg::CullSettings::NEAR_PLANE_CULLING);
|
||||||
bool farCulling = !!(cm & osg::CullSettings::FAR_PLANE_CULLING);
|
farCulling = !!(cm & osg::CullSettings::FAR_PLANE_CULLING);
|
||||||
frustum.setToBoundingBox(mSfm->boundingBox(), nearCulling, farCulling);
|
bb = mSfm->boundingBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
StereoFrustumManager* mSfm;
|
StereoFrustumManager* mSfm;
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|
||||||
struct ShadowFrustumCallback final : public SceneUtil::MWShadowTechnique::CustomFrustumCallback
|
struct ShadowFrustumCallback final : public SceneUtil::MWShadowTechnique::CustomFrustumCallback
|
||||||
{
|
{
|
||||||
@ -95,14 +96,10 @@ namespace Stereo
|
|||||||
: mCamera(camera)
|
: mCamera(camera)
|
||||||
, mShadowTechnique(nullptr)
|
, mShadowTechnique(nullptr)
|
||||||
, mShadowFrustumCallback(nullptr)
|
, mShadowFrustumCallback(nullptr)
|
||||||
, mMultiview(Stereo::getMultiview())
|
|
||||||
{
|
{
|
||||||
if (mMultiview)
|
if (Stereo::getMultiview())
|
||||||
{
|
{
|
||||||
#ifdef OSG_HAS_MULTIVIEW
|
mMultiviewFrustumCallback = std::make_unique<MultiviewFrustumCallback>(this, camera);
|
||||||
mMultiviewFrustumCallback = new MultiviewFrustumCallback(this);
|
|
||||||
mCamera->setInitialFrustumCallback(mMultiviewFrustumCallback);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings::Manager::getBool("shared shadow maps", "Stereo"))
|
if (Settings::Manager::getBool("shared shadow maps", "Stereo"))
|
||||||
@ -118,13 +115,6 @@ namespace Stereo
|
|||||||
|
|
||||||
StereoFrustumManager::~StereoFrustumManager()
|
StereoFrustumManager::~StereoFrustumManager()
|
||||||
{
|
{
|
||||||
if (mMultiview)
|
|
||||||
{
|
|
||||||
#ifdef OSG_HAS_MULTIVIEW
|
|
||||||
mCamera->setInitialFrustumCallback(nullptr);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mShadowTechnique)
|
if (mShadowTechnique)
|
||||||
mShadowTechnique->setCustomFrustumCallback(nullptr);
|
mShadowTechnique->setCustomFrustumCallback(nullptr);
|
||||||
}
|
}
|
||||||
|
@ -38,10 +38,7 @@ namespace SceneUtil
|
|||||||
|
|
||||||
namespace Stereo
|
namespace Stereo
|
||||||
{
|
{
|
||||||
#ifdef OSG_HAS_MULTIVIEW
|
|
||||||
struct MultiviewFrustumCallback;
|
struct MultiviewFrustumCallback;
|
||||||
#endif
|
|
||||||
|
|
||||||
struct ShadowFrustumCallback;
|
struct ShadowFrustumCallback;
|
||||||
|
|
||||||
void joinBoundingBoxes(const osg::Matrix& masterProjection, const osg::Matrix& slaveProjection, osg::BoundingBoxd& bb);
|
void joinBoundingBoxes(const osg::Matrix& masterProjection, const osg::Matrix& slaveProjection, osg::BoundingBoxd& bb);
|
||||||
@ -64,13 +61,10 @@ namespace Stereo
|
|||||||
osg::ref_ptr<osg::Camera> mCamera;
|
osg::ref_ptr<osg::Camera> mCamera;
|
||||||
osg::ref_ptr<SceneUtil::MWShadowTechnique> mShadowTechnique;
|
osg::ref_ptr<SceneUtil::MWShadowTechnique> mShadowTechnique;
|
||||||
osg::ref_ptr<ShadowFrustumCallback> mShadowFrustumCallback;
|
osg::ref_ptr<ShadowFrustumCallback> mShadowFrustumCallback;
|
||||||
bool mMultiview;
|
|
||||||
std::map< osgUtil::CullVisitor*, osgUtil::CullVisitor*> mSharedFrustums;
|
std::map< osgUtil::CullVisitor*, osgUtil::CullVisitor*> mSharedFrustums;
|
||||||
osg::BoundingBoxd mBoundingBox;
|
osg::BoundingBoxd mBoundingBox;
|
||||||
|
|
||||||
#ifdef OSG_HAS_MULTIVIEW
|
std::unique_ptr<MultiviewFrustumCallback> mMultiviewFrustumCallback;
|
||||||
osg::ref_ptr<MultiviewFrustumCallback> mMultiviewFrustumCallback;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <osg/FrameBufferObject>
|
#include <osg/FrameBufferObject>
|
||||||
#include <osg/GLExtensions>
|
#include <osg/GLExtensions>
|
||||||
#include <osg/Texture2D>
|
#include <osg/Texture2D>
|
||||||
|
#include <osg/Texture2DMultisample>
|
||||||
#include <osg/Texture2DArray>
|
#include <osg/Texture2DArray>
|
||||||
#include <osgUtil/RenderStage>
|
#include <osgUtil/RenderStage>
|
||||||
#include <osgUtil/CullVisitor>
|
#include <osgUtil/CullVisitor>
|
||||||
@ -337,6 +338,133 @@ namespace Stereo
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setMultiviewMatrices(osg::StateSet* stateset, const std::array<osg::Matrix, 2>& projection, bool createInverseMatrices)
|
||||||
|
{
|
||||||
|
auto* projUniform = stateset->getUniform("projectionMatrixMultiView");
|
||||||
|
if (!projUniform)
|
||||||
|
{
|
||||||
|
projUniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "projectionMatrixMultiView", 2);
|
||||||
|
stateset->addUniform(projUniform, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
projUniform->setElement(0, projection[0]);
|
||||||
|
projUniform->setElement(1, projection[1]);
|
||||||
|
|
||||||
|
if (createInverseMatrices)
|
||||||
|
{
|
||||||
|
auto* invUniform = stateset->getUniform("invProjectionMatrixMultiView");
|
||||||
|
if (!invUniform)
|
||||||
|
{
|
||||||
|
invUniform = new osg::Uniform(osg::Uniform::FLOAT_MAT4, "invProjectionMatrixMultiView", 2);
|
||||||
|
stateset->addUniform(invUniform, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
|
||||||
|
}
|
||||||
|
|
||||||
|
invUniform->setElement(0, osg::Matrix::inverse(projection[0]));
|
||||||
|
invUniform->setElement(1, osg::Matrix::inverse(projection[1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMultiviewCompatibleTextureSize(osg::Texture* tex, int w, int h)
|
||||||
|
{
|
||||||
|
switch (tex->getTextureTarget())
|
||||||
|
{
|
||||||
|
case GL_TEXTURE_2D:
|
||||||
|
static_cast<osg::Texture2D*>(tex)->setTextureSize(w, h);
|
||||||
|
break;
|
||||||
|
case GL_TEXTURE_2D_ARRAY:
|
||||||
|
static_cast<osg::Texture2DArray*>(tex)->setTextureSize(w, h, 2);
|
||||||
|
break;
|
||||||
|
case GL_TEXTURE_2D_MULTISAMPLE:
|
||||||
|
static_cast<osg::Texture2DMultisample*>(tex)->setTextureSize(w, h);
|
||||||
|
break;
|
||||||
|
#ifdef OSG_HAS_MULTIVIEW
|
||||||
|
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
|
||||||
|
static_cast<osg::Texture2DMultisampleArray*>(tex)->setTextureSize(w, h, 2);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
throw std::logic_error("Invalid texture type received");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::Texture> createMultiviewCompatibleTexture(int width, int height, int samples)
|
||||||
|
{
|
||||||
|
#ifdef OSG_HAS_MULTIVIEW
|
||||||
|
if (Stereo::getMultiview())
|
||||||
|
{
|
||||||
|
if (samples > 1)
|
||||||
|
{
|
||||||
|
auto tex = new osg::Texture2DMultisampleArray();
|
||||||
|
tex->setTextureSize(width, height, 2);
|
||||||
|
tex->setNumSamples(samples);
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto tex = new osg::Texture2DArray();
|
||||||
|
tex->setTextureSize(width, height, 2);
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (samples > 1)
|
||||||
|
{
|
||||||
|
auto tex = new osg::Texture2DMultisample();
|
||||||
|
tex->setTextureSize(width, height);
|
||||||
|
tex->setNumSamples(samples);
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto tex = new osg::Texture2D();
|
||||||
|
tex->setTextureSize(width, height);
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::FrameBufferAttachment createMultiviewCompatibleAttachment(osg::Texture* tex)
|
||||||
|
{
|
||||||
|
switch (tex->getTextureTarget())
|
||||||
|
{
|
||||||
|
case GL_TEXTURE_2D:
|
||||||
|
{
|
||||||
|
auto* tex2d = static_cast<osg::Texture2D*>(tex);
|
||||||
|
return osg::FrameBufferAttachment(tex2d);
|
||||||
|
}
|
||||||
|
case GL_TEXTURE_2D_MULTISAMPLE:
|
||||||
|
{
|
||||||
|
auto* tex2dMsaa = static_cast<osg::Texture2DMultisample*>(tex);
|
||||||
|
return osg::FrameBufferAttachment(tex2dMsaa);
|
||||||
|
}
|
||||||
|
#ifdef OSG_HAS_MULTIVIEW
|
||||||
|
case GL_TEXTURE_2D_ARRAY:
|
||||||
|
{
|
||||||
|
auto* tex2dArray = static_cast<osg::Texture2DArray*>(tex);
|
||||||
|
return osg::FrameBufferAttachment(tex2dArray, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, 0);
|
||||||
|
}
|
||||||
|
case GL_TEXTURE_2D_MULTISAMPLE_ARRAY:
|
||||||
|
{
|
||||||
|
auto* tex2dMsaaArray = static_cast<osg::Texture2DMultisampleArray*>(tex);
|
||||||
|
return osg::FrameBufferAttachment(tex2dMsaaArray, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
throw std::logic_error("Invalid texture type received");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int osgFaceControlledByMultiviewShader()
|
||||||
|
{
|
||||||
|
#ifdef OSG_HAS_MULTIVIEW
|
||||||
|
return osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
class UpdateRenderStagesCallback : public SceneUtil::NodeCallback<UpdateRenderStagesCallback, osg::Node*, osgUtil::CullVisitor*>
|
class UpdateRenderStagesCallback : public SceneUtil::NodeCallback<UpdateRenderStagesCallback, osg::Node*, osgUtil::CullVisitor*>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -558,4 +686,111 @@ namespace Stereo
|
|||||||
textureArray->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
|
textureArray->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
|
||||||
return textureArray;
|
return textureArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
osg::FrameBufferAttachment makeSingleLayerAttachmentFromMultilayerAttachment(osg::FrameBufferAttachment attachment, int layer)
|
||||||
|
{
|
||||||
|
osg::Texture* tex = attachment.getTexture();
|
||||||
|
|
||||||
|
if (tex->getTextureTarget() == GL_TEXTURE_2D_ARRAY)
|
||||||
|
return osg::FrameBufferAttachment(static_cast<osg::Texture2DArray*>(tex), layer, 0);
|
||||||
|
|
||||||
|
#ifdef OSG_HAS_MULTIVIEW
|
||||||
|
if (tex->getTextureTarget() == GL_TEXTURE_2D_MULTISAMPLE_ARRAY)
|
||||||
|
return osg::FrameBufferAttachment(static_cast<osg::Texture2DMultisampleArray*>(tex), layer, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Log(Debug::Error) << "Attempted to extract a layer from an unlayered texture";
|
||||||
|
|
||||||
|
return osg::FrameBufferAttachment();
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiviewFramebufferResolve::MultiviewFramebufferResolve(osg::FrameBufferObject* msaaFbo, osg::FrameBufferObject* resolveFbo, GLbitfield blitMask)
|
||||||
|
: mResolveFbo(resolveFbo)
|
||||||
|
, mMsaaFbo(msaaFbo)
|
||||||
|
, mBlitMask(blitMask)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void MultiviewFramebufferResolve::resolveImplementation(osg::State& state)
|
||||||
|
{
|
||||||
|
if (mDirtyLayers)
|
||||||
|
setupLayers();
|
||||||
|
|
||||||
|
osg::GLExtensions* ext = state.get<osg::GLExtensions>();
|
||||||
|
|
||||||
|
for (int view : {0, 1})
|
||||||
|
{
|
||||||
|
mResolveLayers[view]->apply(state, osg::FrameBufferObject::BindTarget::DRAW_FRAMEBUFFER);
|
||||||
|
mMsaaLayers[view]->apply(state, osg::FrameBufferObject::BindTarget::READ_FRAMEBUFFER);
|
||||||
|
ext->glBlitFramebuffer(0, 0, mWidth, mHeight, 0, 0, mWidth, mHeight, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void MultiviewFramebufferResolve::setupLayers()
|
||||||
|
{
|
||||||
|
mDirtyLayers = false;
|
||||||
|
std::vector<osg::FrameBufferObject::BufferComponent> components;
|
||||||
|
if (mBlitMask & GL_DEPTH_BUFFER_BIT)
|
||||||
|
components.push_back(osg::FrameBufferObject::BufferComponent::PACKED_DEPTH_STENCIL_BUFFER);
|
||||||
|
if (mBlitMask & GL_COLOR_BUFFER_BIT)
|
||||||
|
components.push_back(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER);
|
||||||
|
|
||||||
|
mMsaaLayers = { new osg::FrameBufferObject, new osg::FrameBufferObject };
|
||||||
|
mResolveLayers = { new osg::FrameBufferObject, new osg::FrameBufferObject };
|
||||||
|
for (auto component : components)
|
||||||
|
{
|
||||||
|
const auto& msaaAttachment = mMsaaFbo->getAttachment(component);
|
||||||
|
mMsaaLayers[0]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(msaaAttachment, 0));
|
||||||
|
mMsaaLayers[1]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(msaaAttachment, 1));
|
||||||
|
|
||||||
|
const auto& resolveAttachment = mResolveFbo->getAttachment(component);
|
||||||
|
mResolveLayers[0]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(resolveAttachment, 0));
|
||||||
|
mResolveLayers[1]->setAttachment(component, makeSingleLayerAttachmentFromMultilayerAttachment(resolveAttachment, 1));
|
||||||
|
|
||||||
|
mWidth = msaaAttachment.getTexture()->getTextureWidth();
|
||||||
|
mHeight = msaaAttachment.getTexture()->getTextureHeight();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef OSG_HAS_MULTIVIEW
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct MultiviewFrustumCallback final : public osg::CullSettings::InitialFrustumCallback
|
||||||
|
{
|
||||||
|
MultiviewFrustumCallback(Stereo::InitialFrustumCallback* ifc)
|
||||||
|
: mIfc(ifc)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void setInitialFrustum(osg::CullStack& cullStack, osg::Polytope& frustum) const override
|
||||||
|
{
|
||||||
|
bool nearCulling = false;
|
||||||
|
bool farCulling = false;
|
||||||
|
osg::BoundingBoxd bb;
|
||||||
|
mIfc->setInitialFrustum(cullStack, bb, nearCulling, farCulling);
|
||||||
|
frustum.setToBoundingBox(bb, nearCulling, farCulling);
|
||||||
|
}
|
||||||
|
|
||||||
|
Stereo::InitialFrustumCallback* mIfc;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
InitialFrustumCallback::InitialFrustumCallback(osg::Camera* camera)
|
||||||
|
: mCamera(camera)
|
||||||
|
{
|
||||||
|
#ifdef OSG_HAS_MULTIVIEW
|
||||||
|
camera->setInitialFrustumCallback(new MultiviewFrustumCallback(this));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
InitialFrustumCallback::~InitialFrustumCallback()
|
||||||
|
{
|
||||||
|
#ifdef OSG_HAS_MULTIVIEW
|
||||||
|
osg::ref_ptr<osg::Camera> camera;
|
||||||
|
if(mCamera.lock(camera))
|
||||||
|
camera->setInitialFrustumCallback(nullptr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include <osg/ref_ptr>
|
#include <osg/ref_ptr>
|
||||||
#include <osg/GL>
|
#include <osg/GL>
|
||||||
#include <osg/Camera>
|
#include <osg/Camera>
|
||||||
|
#include <osg/FrameBufferObject>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -40,9 +41,6 @@ namespace Stereo
|
|||||||
//! Creates a Texture2D as a texture view into a Texture2DArray
|
//! Creates a Texture2D as a texture view into a Texture2DArray
|
||||||
osg::ref_ptr<osg::Texture2D> createTextureView_Texture2DFromTexture2DArray(osg::Texture2DArray* textureArray, int layer);
|
osg::ref_ptr<osg::Texture2D> createTextureView_Texture2DFromTexture2DArray(osg::Texture2DArray* textureArray, int layer);
|
||||||
|
|
||||||
//! Sets up a draw callback on the render stage that performs the MSAA resolve operation
|
|
||||||
void setMultiviewMSAAResolveCallback(osgUtil::RenderStage* renderStage);
|
|
||||||
|
|
||||||
//! Class that manages the specifics of GL_OVR_Multiview aware framebuffers, separating the layers into separate framebuffers, and disabling
|
//! Class that manages the specifics of GL_OVR_Multiview aware framebuffers, separating the layers into separate framebuffers, and disabling
|
||||||
class MultiviewFramebuffer
|
class MultiviewFramebuffer
|
||||||
{
|
{
|
||||||
@ -86,6 +84,61 @@ namespace Stereo
|
|||||||
std::array<osg::ref_ptr<osg::Texture2D>, 2> mDepthTexture;
|
std::array<osg::ref_ptr<osg::Texture2D>, 2> mDepthTexture;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! Sets up a draw callback on the render stage that performs the MSAA resolve operation
|
||||||
|
void setMultiviewMSAAResolveCallback(osgUtil::RenderStage* renderStage);
|
||||||
|
|
||||||
|
//! Sets up or updates multiview matrices for the given stateset
|
||||||
|
void setMultiviewMatrices(osg::StateSet* stateset, const std::array<osg::Matrix, 2>& projection, bool createInverseMatrices = false);
|
||||||
|
|
||||||
|
//! Sets the width/height of a texture by first down-casting it to the appropriate type. Sets depth to 2 always for Texture2DArray and Texture2DMultisampleArray.
|
||||||
|
void setMultiviewCompatibleTextureSize(osg::Texture* tex, int w, int h);
|
||||||
|
|
||||||
|
//! Creates a texture (Texture2D, Texture2DMultisample, Texture2DArray, or Texture2DMultisampleArray) based on multiview settings and sample count.
|
||||||
|
osg::ref_ptr<osg::Texture> createMultiviewCompatibleTexture(int width, int height, int samples);
|
||||||
|
|
||||||
|
//! Returns a framebuffer attachment from the texture, returning a multiview attachment if the texture is one of Texture2DArray or Texture2DMultisampleArray
|
||||||
|
osg::FrameBufferAttachment createMultiviewCompatibleAttachment(osg::Texture* tex);
|
||||||
|
|
||||||
|
//! If OSG has multiview, returns the magic number used to tell OSG to create a multiview attachment. Otherwise returns 0.
|
||||||
|
unsigned int osgFaceControlledByMultiviewShader();
|
||||||
|
|
||||||
|
//! Implements resolving a multisamples multiview framebuffer. Does not automatically reflect changes to the fbo attachments, must call dirty() when the fbo attachments change.
|
||||||
|
class MultiviewFramebufferResolve
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MultiviewFramebufferResolve(osg::FrameBufferObject* msaaFbo, osg::FrameBufferObject* resolveFbo, GLbitfield blitMask);
|
||||||
|
|
||||||
|
void resolveImplementation(osg::State& state);
|
||||||
|
|
||||||
|
void dirty() { mDirtyLayers = true; }
|
||||||
|
|
||||||
|
const osg::FrameBufferObject* resolveFbo() const { return mResolveFbo; };
|
||||||
|
const osg::FrameBufferObject* msaaFbo() const { return mMsaaFbo; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupLayers();
|
||||||
|
|
||||||
|
osg::ref_ptr<osg::FrameBufferObject> mResolveFbo;
|
||||||
|
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mResolveLayers{};
|
||||||
|
osg::ref_ptr<osg::FrameBufferObject> mMsaaFbo;
|
||||||
|
std::array<osg::ref_ptr<osg::FrameBufferObject>, 2> mMsaaLayers{};
|
||||||
|
|
||||||
|
GLbitfield mBlitMask;
|
||||||
|
bool mDirtyLayers = true;
|
||||||
|
int mWidth = -1;
|
||||||
|
int mHeight = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Wrapper for osg::CullSettings::InitialFrustumCallback, to avoid exposing osg multiview interfaces outside of multiview.cpp
|
||||||
|
struct InitialFrustumCallback
|
||||||
|
{
|
||||||
|
InitialFrustumCallback(osg::Camera* camera);
|
||||||
|
virtual ~InitialFrustumCallback();
|
||||||
|
|
||||||
|
virtual void setInitialFrustum(osg::CullStack& cullStack, osg::BoundingBoxd& bb, bool& nearCulling, bool& farCulling) const = 0;
|
||||||
|
|
||||||
|
osg::observer_ptr<osg::Camera> mCamera;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -97,7 +97,6 @@ namespace Stereo
|
|||||||
protected:
|
protected:
|
||||||
virtual void setDefaults(osg::StateSet* stateset)
|
virtual void setDefaults(osg::StateSet* stateset)
|
||||||
{
|
{
|
||||||
stateset->addUniform(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "projectionMatrixMultiView", 2));
|
|
||||||
stateset->addUniform(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "invProjectionMatrixMultiView", 2));
|
stateset->addUniform(new osg::Uniform(osg::Uniform::FLOAT_MAT4, "invProjectionMatrixMultiView", 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,8 +194,8 @@ namespace Stereo
|
|||||||
mEyeResolutionOverride = eyeResolution;
|
mEyeResolutionOverride = eyeResolution;
|
||||||
mEyeResolutionOverriden = true;
|
mEyeResolutionOverriden = true;
|
||||||
|
|
||||||
if (mMultiviewFramebuffer)
|
//if (mMultiviewFramebuffer)
|
||||||
updateStereoFramebuffer();
|
// updateStereoFramebuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::screenResolutionChanged()
|
void Manager::screenResolutionChanged()
|
||||||
@ -302,14 +301,14 @@ namespace Stereo
|
|||||||
void Manager::updateStereoFramebuffer()
|
void Manager::updateStereoFramebuffer()
|
||||||
{
|
{
|
||||||
//VR-TODO: in VR, still need to have this framebuffer attached before the postprocessor is created
|
//VR-TODO: in VR, still need to have this framebuffer attached before the postprocessor is created
|
||||||
auto samples = Settings::Manager::getInt("antialiasing", "Video");
|
//auto samples = Settings::Manager::getInt("antialiasing", "Video");
|
||||||
auto eyeRes = eyeResolution();
|
//auto eyeRes = eyeResolution();
|
||||||
|
|
||||||
//if (mMultiviewFramebuffer)
|
//if (mMultiviewFramebuffer)
|
||||||
// mMultiviewFramebuffer->detachFrom(mMainCamera);
|
// mMultiviewFramebuffer->detachFrom(mMainCamera);
|
||||||
mMultiviewFramebuffer = std::make_shared<MultiviewFramebuffer>(static_cast<int>(eyeRes.x()), static_cast<int>(eyeRes.y()), samples);
|
//mMultiviewFramebuffer = std::make_shared<MultiviewFramebuffer>(static_cast<int>(eyeRes.x()), static_cast<int>(eyeRes.y()), samples);
|
||||||
mMultiviewFramebuffer->attachColorComponent(SceneUtil::Color::colorSourceFormat(), SceneUtil::Color::colorSourceType(), SceneUtil::Color::colorInternalFormat());
|
//mMultiviewFramebuffer->attachColorComponent(SceneUtil::Color::colorSourceFormat(), SceneUtil::Color::colorSourceType(), SceneUtil::Color::colorInternalFormat());
|
||||||
mMultiviewFramebuffer->attachDepthComponent(SceneUtil::AutoDepth::depthSourceFormat(), SceneUtil::AutoDepth::depthSourceType(), SceneUtil::AutoDepth::depthInternalFormat());
|
//mMultiviewFramebuffer->attachDepthComponent(SceneUtil::AutoDepth::depthSourceFormat(), SceneUtil::AutoDepth::depthSourceType(), SceneUtil::AutoDepth::depthInternalFormat());
|
||||||
//mMultiviewFramebuffer->attachTo(mMainCamera);
|
//mMultiviewFramebuffer->attachTo(mMainCamera);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,17 +375,12 @@ namespace Stereo
|
|||||||
|
|
||||||
void Manager::updateMultiviewStateset(osg::StateSet* stateset)
|
void Manager::updateMultiviewStateset(osg::StateSet* stateset)
|
||||||
{
|
{
|
||||||
// Update stereo uniforms
|
std::array<osg::Matrix, 2> projectionMatrices;
|
||||||
auto * projectionMatrixMultiViewUniform = stateset->getUniform("projectionMatrixMultiView");
|
|
||||||
auto * invProjectionMatrixMultiViewUniform = stateset->getUniform("invProjectionMatrixMultiView");
|
|
||||||
|
|
||||||
for (int view : {0, 1})
|
for (int view : {0, 1})
|
||||||
{
|
projectionMatrices[view] = computeEyeViewOffset(view) * computeEyeProjection(view, SceneUtil::AutoDepth::isReversed());
|
||||||
auto projectionMatrix = computeEyeViewOffset(view) * computeEyeProjection(view, SceneUtil::AutoDepth::isReversed());
|
|
||||||
auto invProjectionMatrix = osg::Matrix::inverse(projectionMatrix);
|
Stereo::setMultiviewMatrices(stateset, projectionMatrices, true);
|
||||||
projectionMatrixMultiViewUniform->setElement(view, projectionMatrix);
|
|
||||||
invProjectionMatrixMultiViewUniform->setElement(view, invProjectionMatrix);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Manager::setUpdateViewCallback(std::shared_ptr<UpdateViewCallback> cb)
|
void Manager::setUpdateViewCallback(std::shared_ptr<UpdateViewCallback> cb)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user