1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-01-07 12:54:00 +00:00
OpenMW/components/sceneutil/rtt.cpp
madsbuvi dd5901d351 Initial commit
Multiview shaders.

Refactor Frustum management

Rewrite shared shadow map

cull mask should respect stereo

Stereo savegame screencap

LocalMap refactoring

use the vertex buffer hint instead of the display list patch to enable/disable display lists

Character preview fixes
2022-04-28 21:05:34 +02:00

259 lines
11 KiB
C++

#include "rtt.hpp"
#include "util.hpp"
#include <osg/Node>
#include <osg/NodeVisitor>
#include <osg/Texture2D>
#include <osg/Texture2DArray>
#include <osgUtil/CullVisitor>
#include <components/sceneutil/nodecallback.hpp>
#include <components/settings/settings.hpp>
#include <components/sceneutil/depth.hpp>
#include <components/sceneutil/color.hpp>
#include <components/stereo/multiview.hpp>
#include <components/debug/debuglog.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)
: mTextureWidth(textureWidth)
, mTextureHeight(textureHeight)
, mSamples(samples)
, mGenerateMipmaps(generateMipmaps)
, mColorBufferInternalFormat(Color::colorInternalFormat())
, mDepthBufferInternalFormat(AutoDepth::depthInternalFormat())
, mRenderOrderNum(renderOrderNum)
, mStereoAwareness(stereoAwareness)
{
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);
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);
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;
#ifdef OSG_HAS_MULTIVIEW
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, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, mGenerateMipmaps, mSamples);
SceneUtil::attachAlphaToCoverageFriendlyFramebufferToCamera(camera, osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, mGenerateMipmaps);
}
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, osg::Camera::FACE_CONTROLLED_BY_MULTIVIEW_SHADER, 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
#endif
{
// 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);
}
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)
{
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();
}
}