Stereo friendly water

(cherry picked from commit 0e22c55e48a7f965367d3d430c1bef5357b22748)
pull/615/head
madsbuvi 4 years ago
parent da917fc9e7
commit 5c4e6c3f57

@ -312,8 +312,8 @@ namespace MWRender
rttCamera->setUpdateCallback(new NoTraverseCallback);
rttCamera->addChild(mSceneRoot);
rttCamera->addChild(mWater->getReflectionCamera());
rttCamera->addChild(mWater->getRefractionCamera());
rttCamera->addChild(mWater->getReflectionNode());
rttCamera->addChild(mWater->getRefractionNode());
rttCamera->setCullMask(mViewer->getCamera()->getCullMask() & (~Mask_GUI));

@ -25,6 +25,7 @@
#include <components/resource/imagemanager.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/sceneutil/rtt.hpp>
#include <components/sceneutil/shadow.hpp>
#include <components/sceneutil/waterutil.hpp>
@ -228,65 +229,42 @@ osg::ref_ptr<osg::Image> readPngImage (const std::string& file)
return result.getImage();
}
class Refraction : public osg::Camera
class Refraction : public SceneUtil::RTTNode
{
public:
Refraction()
{
unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water");
setRenderOrder(osg::Camera::PRE_RENDER, 1);
setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
setReferenceFrame(osg::Camera::RELATIVE_RF);
setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water"));
osg::Camera::setName("RefractionCamera");
setCullCallback(new InheritViewPointCallback);
setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
mClipCullNode = new ClipCullNode;
}
setCullMask(Mask_Effect|Mask_Scene|Mask_Object|Mask_Static|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|Mask_Lighting);
setNodeMask(Mask_RenderToTexture);
setViewport(0, 0, rttSize, rttSize);
void setDefaults(osg::Camera* camera) override
{
camera->setReferenceFrame(osg::Camera::RELATIVE_RF);
camera->setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water"));
camera->setName("RefractionCamera");
camera->addCullCallback(new InheritViewPointCallback);
camera->setComputeNearFarMode(osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR);
// No need for Update traversal since the scene 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 NoTraverseCallback);
camera->setCullMask(Mask_Effect | Mask_Scene | Mask_Object | Mask_Static | Mask_Terrain | Mask_Actor | Mask_ParticleSystem | Mask_Sky | Mask_Sun | Mask_Player | Mask_Lighting);
// No need for fog here, we are already applying fog on the water surface itself as well as underwater fog
// assign large value to effectively turn off fog
// shaders don't respect glDisable(GL_FOG)
osg::ref_ptr<osg::Fog> fog (new osg::Fog);
osg::ref_ptr<osg::Fog> fog(new osg::Fog);
fog->setStart(10000000);
fog->setEnd(10000000);
getOrCreateStateSet()->setAttributeAndModes(fog, osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE);
camera->getOrCreateStateSet()->setAttributeAndModes(fog, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
mClipCullNode = new ClipCullNode;
osg::Camera::addChild(mClipCullNode);
mRefractionTexture = new osg::Texture2D;
mRefractionTexture->setTextureSize(rttSize, rttSize);
mRefractionTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
mRefractionTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
mRefractionTexture->setInternalFormat(GL_RGB);
mRefractionTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
mRefractionTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
attach(osg::Camera::COLOR_BUFFER, mRefractionTexture);
mRefractionDepthTexture = new osg::Texture2D;
mRefractionDepthTexture->setTextureSize(rttSize, rttSize);
mRefractionDepthTexture->setSourceFormat(GL_DEPTH_COMPONENT);
mRefractionDepthTexture->setInternalFormat(GL_DEPTH_COMPONENT24);
mRefractionDepthTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
mRefractionDepthTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
mRefractionDepthTexture->setSourceType(GL_UNSIGNED_INT);
mRefractionDepthTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
mRefractionDepthTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
attach(osg::Camera::DEPTH_BUFFER, mRefractionDepthTexture);
camera->addChild(mClipCullNode);
camera->setNodeMask(Mask_RenderToTexture);
if (Settings::Manager::getFloat("refraction scale", "Water") != 1) // TODO: to be removed with issue #5709
SceneUtil::ShadowManager::disableShadowsForStateSet(getOrCreateStateSet());
SceneUtil::ShadowManager::disableShadowsForStateSet(camera->getOrCreateStateSet());
}
void apply(osg::Camera* camera) override
{
camera->setViewMatrix(mViewMatrix);
}
void setScene(osg::Node* scene)
@ -302,71 +280,49 @@ public:
const float refractionScale = std::min(1.0f,std::max(0.0f,
Settings::Manager::getFloat("refraction scale", "Water")));
setViewMatrix(osg::Matrix::scale(1,1,refractionScale) *
osg::Matrix::translate(0,0,(1.0 - refractionScale) * waterLevel));
mViewMatrix = osg::Matrix::scale(1,1,refractionScale) *
osg::Matrix::translate(0,0,(1.0 - refractionScale) * waterLevel);
mClipCullNode->setPlane(osg::Plane(osg::Vec3d(0,0,-1), osg::Vec3d(0,0, waterLevel)));
}
osg::Texture2D* getRefractionTexture() const
{
return mRefractionTexture.get();
}
osg::Texture2D* getRefractionDepthTexture() const
{
return mRefractionDepthTexture.get();
}
private:
osg::ref_ptr<ClipCullNode> mClipCullNode;
osg::ref_ptr<osg::Texture2D> mRefractionTexture;
osg::ref_ptr<osg::Texture2D> mRefractionDepthTexture;
osg::ref_ptr<osg::Node> mScene;
osg::Matrix mViewMatrix{ osg::Matrix::identity() };
};
class Reflection : public osg::Camera
class Reflection : public SceneUtil::RTTNode
{
public:
Reflection(bool isInterior)
{
setRenderOrder(osg::Camera::PRE_RENDER);
setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
setReferenceFrame(osg::Camera::RELATIVE_RF);
setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water"));
osg::Camera::setName("ReflectionCamera");
setCullCallback(new InheritViewPointCallback);
setInterior(isInterior);
setNodeMask(Mask_RenderToTexture);
unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water");
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 NoTraverseCallback);
mReflectionTexture = new osg::Texture2D;
mReflectionTexture->setTextureSize(rttSize, rttSize);
mReflectionTexture->setInternalFormat(GL_RGB);
mReflectionTexture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
mReflectionTexture->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
mReflectionTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
mReflectionTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
mClipCullNode = new ClipCullNode;
}
attach(osg::Camera::COLOR_BUFFER, mReflectionTexture);
void setDefaults(osg::Camera* camera) override
{
camera->setReferenceFrame(osg::Camera::RELATIVE_RF);
camera->setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water"));
camera->setName("ReflectionCamera");
camera->addCullCallback(new InheritViewPointCallback);
// XXX: should really flip the FrontFace on each renderable instead of forcing clockwise.
osg::ref_ptr<osg::FrontFace> frontFace (new osg::FrontFace);
osg::ref_ptr<osg::FrontFace> frontFace(new osg::FrontFace);
frontFace->setMode(osg::FrontFace::CLOCKWISE);
getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON);
camera->getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON);
mClipCullNode = new ClipCullNode;
osg::Camera::addChild(mClipCullNode);
camera->addChild(mClipCullNode);
camera->setNodeMask(Mask_RenderToTexture);
SceneUtil::ShadowManager::disableShadowsForStateSet(getOrCreateStateSet());
SceneUtil::ShadowManager::disableShadowsForStateSet(camera->getOrCreateStateSet());
}
void apply(osg::Camera* camera) override
{
camera->setViewMatrix(mViewMatrix);
camera->setCullMask(mNodeMask);
}
void setInterior(bool isInterior)
@ -378,12 +334,12 @@ public:
if(reflectionDetail >= 2) extraMask |= Mask_Static;
if(reflectionDetail >= 3) extraMask |= Mask_Effect|Mask_ParticleSystem|Mask_Object;
if(reflectionDetail >= 4) extraMask |= Mask_Player|Mask_Actor;
setCullMask(Mask_Scene|Mask_Sky|Mask_Lighting|extraMask);
mNodeMask = Mask_Scene | Mask_Sky | Mask_Lighting | extraMask;
}
void setWaterLevel(float waterLevel)
{
setViewMatrix(osg::Matrix::scale(1,1,-1) * osg::Matrix::translate(0,0,2 * waterLevel));
mViewMatrix = osg::Matrix::scale(1,1,-1) * osg::Matrix::translate(0,0,2 * waterLevel);
mClipCullNode->setPlane(osg::Plane(osg::Vec3d(0,0,1), osg::Vec3d(0,0,waterLevel)));
}
@ -395,15 +351,11 @@ public:
mClipCullNode->addChild(scene);
}
osg::Texture2D* getReflectionTexture() const
{
return mReflectionTexture.get();
}
private:
osg::ref_ptr<osg::Texture2D> mReflectionTexture;
osg::ref_ptr<ClipCullNode> mClipCullNode;
osg::ref_ptr<osg::Node> mScene;
osg::Node::NodeMask mNodeMask;
osg::Matrix mViewMatrix{ osg::Matrix::identity() };
};
/// DepthClampCallback enables GL_DEPTH_CLAMP for the current draw, if supported.
@ -439,6 +391,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem
, mTop(0)
, mInterior(false)
, mCullCallback(nullptr)
, mShaderWaterStateSetUpdater(nullptr)
{
mSimulation.reset(new RippleSimulation(mSceneRoot, resourceSystem));
@ -500,19 +453,26 @@ osg::Uniform *Water::getRainIntensityUniform()
void Water::updateWaterMaterial()
{
if (mShaderWaterStateSetUpdater)
{
mWaterNode->removeCullCallback(mShaderWaterStateSetUpdater);
mShaderWaterStateSetUpdater = nullptr;
}
if (mReflection)
{
mReflection->removeChildren(0, mReflection->getNumChildren());
mParent->removeChild(mReflection);
mReflection = nullptr;
}
if (mRefraction)
{
mRefraction->removeChildren(0, mRefraction->getNumChildren());
mParent->removeChild(mRefraction);
mRefraction = nullptr;
}
mWaterNode->setStateSet(nullptr);
mWaterGeom->setStateSet(nullptr);
mWaterGeom->setUpdateCallback(nullptr);
if (Settings::Manager::getBool("shader", "Water"))
{
mReflection = new Reflection(mInterior);
@ -532,7 +492,7 @@ void Water::updateWaterMaterial()
mParent->addChild(mRefraction);
}
createShaderWaterStateSet(mWaterGeom, mReflection, mRefraction);
createShaderWaterStateSet(mWaterNode, mReflection, mRefraction);
}
else
createSimpleWaterStateSet(mWaterGeom, Fallback::Map::getFloat("Water_World_Alpha"));
@ -540,12 +500,12 @@ void Water::updateWaterMaterial()
updateVisible();
}
osg::Camera *Water::getReflectionCamera()
osg::Node *Water::getReflectionNode()
{
return mReflection;
}
osg::Camera *Water::getRefractionCamera()
osg::Node* Water::getRefractionNode()
{
return mRefraction;
}
@ -590,17 +550,75 @@ void Water::createSimpleWaterStateSet(osg::Node* node, float alpha)
sceneManager->setForceShaders(oldValue);
}
class ShaderWaterStateSetUpdater : public SceneUtil::StateSetUpdater
{
public:
ShaderWaterStateSetUpdater(Water* water, Reflection* reflection, Refraction* refraction, osg::ref_ptr<osg::Program> program, osg::ref_ptr<osg::Texture2D> normalMap)
: mWater(water)
, mReflection(reflection)
, mRefraction(refraction)
, mProgram(program)
, mNormalMap(normalMap)
{
}
void setDefaults(osg::StateSet* stateset) override
{
stateset->addUniform(new osg::Uniform("normalMap", 0));
stateset->setTextureAttributeAndModes(0, mNormalMap, osg::StateAttribute::ON);
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
stateset->addUniform(mWater->getRainIntensityUniform());
stateset->setAttributeAndModes(mProgram, osg::StateAttribute::ON);
stateset->addUniform(new osg::Uniform("reflectionMap", 1));
if (mRefraction)
{
stateset->addUniform(new osg::Uniform("refractionMap", 2));
stateset->addUniform(new osg::Uniform("refractionDepthMap", 3));
stateset->setRenderBinDetails(MWRender::RenderBin_Default, "RenderBin");
}
else
{
stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin");
osg::ref_ptr<osg::Depth> depth(new osg::Depth);
depth->setWriteMask(false);
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);
}
}
void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) override
{
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(nv);
stateset->setTextureAttributeAndModes(1, mReflection->getColorTexture(cv), osg::StateAttribute::ON);
if (mRefraction)
{
stateset->setTextureAttributeAndModes(2, mRefraction->getColorTexture(cv), osg::StateAttribute::ON);
stateset->setTextureAttributeAndModes(3, mRefraction->getDepthTexture(cv), osg::StateAttribute::ON);
}
}
private:
Water* mWater;
Reflection* mReflection;
Refraction* mRefraction;
osg::ref_ptr<osg::Program> mProgram;
osg::ref_ptr<osg::Texture2D> mNormalMap;
};
void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, Refraction* refraction)
{
// use a define map to conditionally compile the shader
std::map<std::string, std::string> defineMap;
defineMap.insert(std::make_pair(std::string("refraction_enabled"), std::string(refraction ? "1" : "0")));
defineMap.insert(std::make_pair(std::string("refraction_enabled"), std::string(mRefraction ? "1" : "0")));
Shader::ShaderManager& shaderMgr = mResourceSystem->getSceneManager()->getShaderManager();
osg::ref_ptr<osg::Shader> vertexShader (shaderMgr.getShader("water_vertex.glsl", defineMap, osg::Shader::VERTEX));
osg::ref_ptr<osg::Shader> fragmentShader (shaderMgr.getShader("water_fragment.glsl", defineMap, osg::Shader::FRAGMENT));
osg::ref_ptr<osg::Shader> vertexShader(shaderMgr.getShader("water_vertex.glsl", defineMap, osg::Shader::VERTEX));
osg::ref_ptr<osg::Shader> fragmentShader(shaderMgr.getShader("water_fragment.glsl", defineMap, osg::Shader::FRAGMENT));
osg::ref_ptr<osg::Program> program = shaderMgr.getProgram(vertexShader, fragmentShader);
osg::ref_ptr<osg::Texture2D> normalMap (new osg::Texture2D(readPngImage(mResourcePath + "/shaders/water_nm.png")));
osg::ref_ptr<osg::Texture2D> normalMap(new osg::Texture2D(readPngImage(mResourcePath + "/shaders/water_nm.png")));
if (normalMap->getImage())
normalMap->getImage()->flipVertical();
@ -610,43 +628,8 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R
normalMap->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
normalMap->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
osg::ref_ptr<osg::StateSet> shaderStateset = new osg::StateSet;
shaderStateset->addUniform(new osg::Uniform("normalMap", 0));
shaderStateset->addUniform(new osg::Uniform("reflectionMap", 1));
shaderStateset->setTextureAttributeAndModes(0, normalMap, osg::StateAttribute::ON);
shaderStateset->setTextureAttributeAndModes(1, reflection->getReflectionTexture(), osg::StateAttribute::ON);
if (refraction)
{
shaderStateset->setTextureAttributeAndModes(2, refraction->getRefractionTexture(), osg::StateAttribute::ON);
shaderStateset->setTextureAttributeAndModes(3, refraction->getRefractionDepthTexture(), osg::StateAttribute::ON);
shaderStateset->addUniform(new osg::Uniform("refractionMap", 2));
shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 3));
shaderStateset->setRenderBinDetails(MWRender::RenderBin_Default, "RenderBin");
}
else
{
shaderStateset->setMode(GL_BLEND, osg::StateAttribute::ON);
shaderStateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin");
osg::ref_ptr<osg::Depth> depth (new osg::Depth);
depth->setWriteMask(false);
shaderStateset->setAttributeAndModes(depth, osg::StateAttribute::ON);
}
shaderStateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
shaderStateset->addUniform(mRainIntensityUniform.get());
osg::ref_ptr<osg::Program> program (new osg::Program);
program->addShader(vertexShader);
program->addShader(fragmentShader);
shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON);
node->setStateSet(shaderStateset);
node->setUpdateCallback(nullptr);
mShaderWaterStateSetUpdater = new ShaderWaterStateSetUpdater(this, mReflection, mRefraction, program, normalMap);
node->addCullCallback(mShaderWaterStateSetUpdater);
}
void Water::processChangedSettings(const Settings::CategorySettingVector& settings)
@ -660,13 +643,11 @@ Water::~Water()
if (mReflection)
{
mReflection->removeChildren(0, mReflection->getNumChildren());
mParent->removeChild(mReflection);
mReflection = nullptr;
}
if (mRefraction)
{
mRefraction->removeChildren(0, mRefraction->getNumChildren());
mParent->removeChild(mRefraction);
mRefraction = nullptr;
}

@ -72,6 +72,7 @@ namespace MWRender
bool mInterior;
osg::Callback* mCullCallback;
osg::ref_ptr<osg::NodeCallback> mShaderWaterStateSetUpdater;
osg::Vec3f getSceneNodeCoordinates(int gridX, int gridY);
void updateVisible();
@ -115,8 +116,8 @@ namespace MWRender
void update(float dt);
osg::Camera *getReflectionCamera();
osg::Camera *getRefractionCamera();
osg::Node* getReflectionNode();
osg::Node* getRefractionNode();
void processChangedSettings(const Settings::CategorySettingVector& settings);

@ -52,7 +52,7 @@ add_component_dir (shader
add_component_dir (sceneutil
clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller
lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer
actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique recastmesh shadowsbin osgacontroller
actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique recastmesh shadowsbin osgacontroller rtt
)
add_component_dir (nif

@ -0,0 +1,103 @@
#include "rtt.hpp"
#include <osg/Node>
#include <osg/NodeVisitor>
#include <osg/Texture2D>
#include <osgUtil/CullVisitor>
#include <components/settings/settings.hpp>
namespace SceneUtil
{
// RTTNode's cull callback
class CullCallback : public osg::NodeCallback
{
public:
CullCallback(RTTNode* group)
: mGroup(group) {}
void operator()(osg::Node* node, osg::NodeVisitor* nv) override
{
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(nv);
mGroup->cull(cv);
}
RTTNode* mGroup;
};
// RTT camera
class RTTCamera : public osg::Camera
{
public:
RTTCamera()
{
setRenderOrder(osg::Camera::PRE_RENDER, 1);
setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water");
setViewport(0, 0, rttSize, rttSize);
mColorBuffer = new osg::Texture2D;
mColorBuffer->setTextureSize(rttSize, rttSize);
mColorBuffer->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
mColorBuffer->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
mColorBuffer->setInternalFormat(GL_RGB);
mColorBuffer->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
mColorBuffer->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
attach(osg::Camera::COLOR_BUFFER, mColorBuffer);
mDepthBuffer = new osg::Texture2D;
mDepthBuffer->setTextureSize(rttSize, rttSize);
mDepthBuffer->setSourceFormat(GL_DEPTH_COMPONENT);
mDepthBuffer->setInternalFormat(GL_DEPTH_COMPONENT24);
mDepthBuffer->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
mDepthBuffer->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
mDepthBuffer->setSourceType(GL_UNSIGNED_INT);
mDepthBuffer->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
mDepthBuffer->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
attach(osg::Camera::DEPTH_BUFFER, mDepthBuffer);
}
osg::ref_ptr<osg::Texture2D> mColorBuffer;
osg::ref_ptr<osg::Texture2D> mDepthBuffer;
};
RTTNode::RTTNode()
{
addCullCallback(new CullCallback(this));
}
RTTNode::~RTTNode()
{
}
void RTTNode::cull(osgUtil::CullVisitor* cv)
{
auto* vdd = getViewDependentData(cv);
apply(vdd->mCamera);
vdd->mCamera->accept(*cv);
}
osg::Texture2D* RTTNode::getColorTexture(osgUtil::CullVisitor* cv)
{
return getViewDependentData(cv)->mCamera->mColorBuffer.get();
}
osg::Texture2D* RTTNode::getDepthTexture(osgUtil::CullVisitor* cv)
{
return getViewDependentData(cv)->mCamera->mDepthBuffer.get();
}
RTTNode::ViewDependentData* RTTNode::getViewDependentData(osgUtil::CullVisitor* cv)
{
if (mViewDependentDataMap.count(cv) == 0)
{
mViewDependentDataMap[cv].reset(new ViewDependentData);
mViewDependentDataMap[cv]->mCamera = new RTTCamera();
setDefaults(mViewDependentDataMap[cv]->mCamera.get());
}
return mViewDependentDataMap[cv].get();
}
}

@ -0,0 +1,62 @@
#ifndef OPENMW_RTT_H
#define OPENMW_RTT_H
#include <osg/Node>
#include <map>
namespace osg
{
class Texture2D;
}
namespace osgUtil
{
class CullVisitor;
}
namespace SceneUtil
{
class RTTCamera;
/// @brief Implements per-view RTT operations.
/// @par With a naive RTT implementation, subsequent views of multiple views will overwrite the results of the previous views, leading to
/// the results of the last view being broadcast to all views. An error in all cases where the RTT result depends on the view.
/// @par If using an RTTNode this is solved by mapping RTT operations to CullVisitors, which will be unique per view. This requires
/// instancing one camera per view, and traversing only the camera mapped to that CV during cull traversals.
/// @par Camera settings should be effectuated by overriding the setDefaults() and apply() methods, following a pattern similar to SceneUtil::StateSetUpdater
/// @par When using the RTT texture in your statesets, it is recommended to use SceneUtil::StateSetUpdater as a cull callback to handle this as the appropriate
/// textures can be retrieved during SceneUtil::StateSetUpdater::Apply()
class RTTNode : public osg::Node
{
public:
RTTNode();
~RTTNode();
osg::Texture2D* getColorTexture(osgUtil::CullVisitor* cv);
osg::Texture2D* getDepthTexture(osgUtil::CullVisitor* cv);
/// Apply state - to override in derived classes
/// @note Due to the view mapping approach you *have* to apply all camera settings, even if they have not changed since the last frame.
virtual void setDefaults(osg::Camera* camera) {};
/// Set default settings - optionally override in derived classes
virtual void apply(osg::Camera* camera) {};
void cull(osgUtil::CullVisitor* cv);
private:
struct ViewDependentData
{
osg::ref_ptr<RTTCamera> mCamera;
};
ViewDependentData* getViewDependentData(osgUtil::CullVisitor* cv);
typedef std::map< osgUtil::CullVisitor*, std::unique_ptr<ViewDependentData> > ViewDependentDataMap;
ViewDependentDataMap mViewDependentDataMap;
};
}
#endif
Loading…
Cancel
Save