Something went wrong. Try again.
OpenMW is an open implementation of the Morrowind engine
Something went wrong. Try again.
12 kB · 269 lines
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270#include "rtt.hpp"#include "util.hpp"
#include <osg/Texture2D>#include <osg/Texture2DArray>#include <osgUtil/CullVisitor>
#include <components/sceneutil/color.hpp>#include <components/sceneutil/depth.hpp>#include <components/sceneutil/nodecallback.hpp>#include <components/stereo/multiview.hpp>#include <components/stereo/stereomanager.hpp>
namespace SceneUtil{ class CullCallback : public SceneUtil::NodeCallback<CullCallback, RTTNode*, osgUtil::CullVisitor*> { public: void operator()(RTTNode* node, osgUtil::CullVisitor* cv) { node->cull(cv); } };
RTTNode::RTTNode(uint32_t textureWidth, uint32_t textureHeight, uint32_t samples, bool generateMipmaps, int renderOrderNum, StereoAwareness stereoAwareness, bool addMSAAIntermediateTarget) : mTextureWidth(textureWidth) , mTextureHeight(textureHeight) , mSamples(samples) , mGenerateMipmaps(generateMipmaps) , mColorBufferInternalFormat(Color::colorInternalFormat()) , mDepthBufferInternalFormat(SceneUtil::AutoDepth::depthInternalFormat()) , mRenderOrderNum(renderOrderNum) , mStereoAwareness(stereoAwareness) , mAddMSAAIntermediateTarget(addMSAAIntermediateTarget) { addCullCallback(new CullCallback); setCullingActive(false); }
RTTNode::~RTTNode() { for (auto& vdd : mViewDependentDataMap) { auto* camera = vdd.second->mCamera.get(); if (camera) { camera->removeChildren(0, camera->getNumChildren()); } } mViewDependentDataMap.clear(); }
void RTTNode::cull(osgUtil::CullVisitor* cv) { auto frameNumber = cv->getFrameStamp()->getFrameNumber(); auto* vdd = getViewDependentData(cv); if (frameNumber > vdd->mFrameNumber) { apply(vdd->mCamera); if (Stereo::getStereo()) { auto& sm = Stereo::Manager::instance(); if (sm.getEye(cv) == Stereo::Eye::Left) applyLeft(vdd->mCamera); if (sm.getEye(cv) == Stereo::Eye::Right) applyRight(vdd->mCamera); } vdd->mCamera->accept(*cv); } vdd->mFrameNumber = frameNumber; }
void RTTNode::setColorBufferInternalFormat(GLint internalFormat) { mColorBufferInternalFormat = internalFormat; }
void RTTNode::setDepthBufferInternalFormat(GLint internalFormat) { mDepthBufferInternalFormat = internalFormat; }
bool RTTNode::shouldDoPerViewMapping() { if (mStereoAwareness != StereoAwareness::Aware) return false; if (!Stereo::getMultiview()) return true; return false; }
bool RTTNode::shouldDoTextureArray() { if (mStereoAwareness == StereoAwareness::Unaware) return false; if (Stereo::getMultiview()) return true; return false; }
bool RTTNode::shouldDoTextureView() { if (mStereoAwareness != StereoAwareness::Unaware_MultiViewShaders) return false; if (Stereo::getMultiview()) return true; return false; }
osg::Texture2DArray* RTTNode::createTextureArray(GLint internalFormat) { osg::Texture2DArray* textureArray = new osg::Texture2DArray; textureArray->setTextureSize(mTextureWidth, mTextureHeight, 2); textureArray->setInternalFormat(internalFormat); GLenum sourceFormat = 0; GLenum sourceType = 0; if (SceneUtil::isDepthFormat(internalFormat)) { SceneUtil::getDepthFormatSourceFormatAndType(internalFormat, sourceFormat, sourceType); } else { SceneUtil::getColorFormatSourceFormatAndType(internalFormat, sourceFormat, sourceType); } textureArray->setSourceFormat(sourceFormat); textureArray->setSourceType(sourceType); textureArray->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); textureArray->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); textureArray->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); textureArray->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); textureArray->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE); return textureArray; }
osg::Texture2D* RTTNode::createTexture(GLint internalFormat) { osg::Texture2D* texture = new osg::Texture2D; texture->setTextureSize(mTextureWidth, mTextureHeight); texture->setInternalFormat(internalFormat); GLenum sourceFormat = 0; GLenum sourceType = 0; if (SceneUtil::isDepthFormat(internalFormat)) { SceneUtil::getDepthFormatSourceFormatAndType(internalFormat, sourceFormat, sourceType); } else { SceneUtil::getColorFormatSourceFormatAndType(internalFormat, sourceFormat, sourceType); } texture->setSourceFormat(sourceFormat); texture->setSourceType(sourceType); texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); texture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); texture->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE); return texture; }
osg::Texture* RTTNode::getColorTexture(osgUtil::CullVisitor* cv) { return getViewDependentData(cv)->mColorTexture; }
osg::Texture* RTTNode::getDepthTexture(osgUtil::CullVisitor* cv) { return getViewDependentData(cv)->mDepthTexture; }
osg::Camera* RTTNode::getCamera(osgUtil::CullVisitor* cv) { return getViewDependentData(cv)->mCamera; }
RTTNode::ViewDependentData* RTTNode::getViewDependentData(osgUtil::CullVisitor* cv) { if (!shouldDoPerViewMapping()) // Always setting it to null is an easy way to disable per-view mapping when mDoPerViewMapping is false. // This is safe since the visitor is never dereferenced. cv = nullptr;
if (mViewDependentDataMap.count(cv) == 0) { auto camera = new osg::Camera(); auto vdd = std::make_shared<ViewDependentData>(); mViewDependentDataMap[cv] = vdd; mViewDependentDataMap[cv]->mCamera = camera;
camera->setRenderOrder(osg::Camera::PRE_RENDER, mRenderOrderNum); camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); camera->setViewport(0, 0, mTextureWidth, mTextureHeight); SceneUtil::setCameraClearDepth(camera);
camera->getOrCreateStateSet()->addUniform(new osg::Uniform( "screenRes", osg::Vec2f(static_cast<float>(mTextureWidth), static_cast<float>(mTextureHeight))));
setDefaults(camera);
if (camera->getBufferAttachmentMap().count(osg::Camera::COLOR_BUFFER)) vdd->mColorTexture = camera->getBufferAttachmentMap()[osg::Camera::COLOR_BUFFER]._texture; if (camera->getBufferAttachmentMap().count(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER)) vdd->mDepthTexture = camera->getBufferAttachmentMap()[osg::Camera::PACKED_DEPTH_STENCIL_BUFFER]._texture;
if (shouldDoTextureArray()) { // Create any buffer attachments not added in setDefaults if (camera->getBufferAttachmentMap().count(osg::Camera::COLOR_BUFFER) == 0) { vdd->mColorTexture = createTextureArray(mColorBufferInternalFormat); camera->attach(osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, Stereo::osgFaceControlledByMultiviewShader(), mGenerateMipmaps, mSamples); SceneUtil::attachAlphaToCoverageFriendlyFramebufferToCamera(camera, osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, Stereo::osgFaceControlledByMultiviewShader(), mGenerateMipmaps, mAddMSAAIntermediateTarget); }
if (camera->getBufferAttachmentMap().count(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER) == 0) { vdd->mDepthTexture = createTextureArray(mDepthBufferInternalFormat); camera->attach(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, vdd->mDepthTexture, 0, Stereo::osgFaceControlledByMultiviewShader(), false, mSamples); }
if (shouldDoTextureView()) { // In this case, shaders being set to multiview forces us to render to a multiview framebuffer even // though we don't need that. This forces us to make Texture2DArray. To make this possible to sample // as a Texture2D, make a Texture2D view into the texture array. vdd->mColorTexture = Stereo::createTextureView_Texture2DFromTexture2DArray( static_cast<osg::Texture2DArray*>(vdd->mColorTexture.get()), 0); vdd->mDepthTexture = Stereo::createTextureView_Texture2DFromTexture2DArray( static_cast<osg::Texture2DArray*>(vdd->mDepthTexture.get()), 0); } } else { // Create any buffer attachments not added in setDefaults if (camera->getBufferAttachmentMap().count(osg::Camera::COLOR_BUFFER) == 0) { vdd->mColorTexture = createTexture(mColorBufferInternalFormat); camera->attach(osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, 0, mGenerateMipmaps, mSamples); SceneUtil::attachAlphaToCoverageFriendlyFramebufferToCamera(camera, osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, 0, mGenerateMipmaps, mAddMSAAIntermediateTarget); }
if (camera->getBufferAttachmentMap().count(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER) == 0) { vdd->mDepthTexture = createTexture(mDepthBufferInternalFormat); camera->attach(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER, vdd->mDepthTexture, 0, 0, false, mSamples); } }
// OSG appears not to properly initialize this metadata. So when multisampling is enabled, OSG will use // incorrect formats for the resolve buffers. if (mSamples > 1 || mAddMSAAIntermediateTarget) { camera->getBufferAttachmentMap()[osg::Camera::COLOR_BUFFER]._internalFormat = mColorBufferInternalFormat; camera->getBufferAttachmentMap()[osg::Camera::COLOR_BUFFER]._mipMapGeneration = mGenerateMipmaps; camera->getBufferAttachmentMap()[osg::Camera::PACKED_DEPTH_STENCIL_BUFFER]._internalFormat = mDepthBufferInternalFormat; camera->getBufferAttachmentMap()[osg::Camera::PACKED_DEPTH_STENCIL_BUFFER]._mipMapGeneration = mGenerateMipmaps; } }
return mViewDependentDataMap[cv].get(); }}