1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-20 07:23:51 +00:00

Stereo friendly water

(cherry picked from commit 0e22c55e48a7f965367d3d430c1bef5357b22748)
This commit is contained in:
madsbuvi 2021-01-24 10:42:21 +01:00
parent da917fc9e7
commit 5c4e6c3f57
6 changed files with 297 additions and 150 deletions

View file

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

View file

@ -25,6 +25,7 @@
#include <components/resource/imagemanager.hpp> #include <components/resource/imagemanager.hpp>
#include <components/resource/scenemanager.hpp> #include <components/resource/scenemanager.hpp>
#include <components/sceneutil/rtt.hpp>
#include <components/sceneutil/shadow.hpp> #include <components/sceneutil/shadow.hpp>
#include <components/sceneutil/waterutil.hpp> #include <components/sceneutil/waterutil.hpp>
@ -228,65 +229,42 @@ osg::ref_ptr<osg::Image> readPngImage (const std::string& file)
return result.getImage(); return result.getImage();
} }
class Refraction : public SceneUtil::RTTNode
class Refraction : public osg::Camera
{ {
public: public:
Refraction() Refraction()
{ {
unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); mClipCullNode = new ClipCullNode;
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);
setCullMask(Mask_Effect|Mask_Scene|Mask_Object|Mask_Static|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|Mask_Lighting); void setDefaults(osg::Camera* camera) override
setNodeMask(Mask_RenderToTexture); {
setViewport(0, 0, rttSize, rttSize); 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 camera->setCullMask(Mask_Effect | Mask_Scene | Mask_Object | Mask_Static | Mask_Terrain | Mask_Actor | Mask_ParticleSystem | Mask_Sky | Mask_Sun | Mask_Player | Mask_Lighting);
// A double update would mess with the light collection (in addition to being plain redundant)
setUpdateCallback(new NoTraverseCallback);
// No need for fog here, we are already applying fog on the water surface itself as well as underwater fog // 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 // assign large value to effectively turn off fog
// shaders don't respect glDisable(GL_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->setStart(10000000);
fog->setEnd(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; camera->addChild(mClipCullNode);
osg::Camera::addChild(mClipCullNode); camera->setNodeMask(Mask_RenderToTexture);
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);
if (Settings::Manager::getFloat("refraction scale", "Water") != 1) // TODO: to be removed with issue #5709 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) void setScene(osg::Node* scene)
@ -302,71 +280,49 @@ public:
const float refractionScale = std::min(1.0f,std::max(0.0f, const float refractionScale = std::min(1.0f,std::max(0.0f,
Settings::Manager::getFloat("refraction scale", "Water"))); Settings::Manager::getFloat("refraction scale", "Water")));
setViewMatrix(osg::Matrix::scale(1,1,refractionScale) * mViewMatrix = osg::Matrix::scale(1,1,refractionScale) *
osg::Matrix::translate(0,0,(1.0 - refractionScale) * waterLevel)); osg::Matrix::translate(0,0,(1.0 - refractionScale) * waterLevel);
mClipCullNode->setPlane(osg::Plane(osg::Vec3d(0,0,-1), osg::Vec3d(0,0, 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: private:
osg::ref_ptr<ClipCullNode> mClipCullNode; osg::ref_ptr<ClipCullNode> mClipCullNode;
osg::ref_ptr<osg::Texture2D> mRefractionTexture;
osg::ref_ptr<osg::Texture2D> mRefractionDepthTexture;
osg::ref_ptr<osg::Node> mScene; osg::ref_ptr<osg::Node> mScene;
osg::Matrix mViewMatrix{ osg::Matrix::identity() };
}; };
class Reflection : public osg::Camera class Reflection : public SceneUtil::RTTNode
{ {
public: public:
Reflection(bool isInterior) 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); setInterior(isInterior);
setNodeMask(Mask_RenderToTexture); mClipCullNode = new ClipCullNode;
}
unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); void setDefaults(osg::Camera* camera) override
setViewport(0, 0, rttSize, rttSize); {
camera->setReferenceFrame(osg::Camera::RELATIVE_RF);
// No need for Update traversal since the mSceneRoot is already updated as part of the main scene graph camera->setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water"));
// A double update would mess with the light collection (in addition to being plain redundant) camera->setName("ReflectionCamera");
setUpdateCallback(new NoTraverseCallback); camera->addCullCallback(new InheritViewPointCallback);
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);
attach(osg::Camera::COLOR_BUFFER, mReflectionTexture);
// XXX: should really flip the FrontFace on each renderable instead of forcing clockwise. // 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); frontFace->setMode(osg::FrontFace::CLOCKWISE);
getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON); camera->getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON);
mClipCullNode = new ClipCullNode; camera->addChild(mClipCullNode);
osg::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) void setInterior(bool isInterior)
@ -378,12 +334,12 @@ public:
if(reflectionDetail >= 2) extraMask |= Mask_Static; if(reflectionDetail >= 2) extraMask |= Mask_Static;
if(reflectionDetail >= 3) extraMask |= Mask_Effect|Mask_ParticleSystem|Mask_Object; if(reflectionDetail >= 3) extraMask |= Mask_Effect|Mask_ParticleSystem|Mask_Object;
if(reflectionDetail >= 4) extraMask |= Mask_Player|Mask_Actor; 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) 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))); mClipCullNode->setPlane(osg::Plane(osg::Vec3d(0,0,1), osg::Vec3d(0,0,waterLevel)));
} }
@ -395,15 +351,11 @@ public:
mClipCullNode->addChild(scene); mClipCullNode->addChild(scene);
} }
osg::Texture2D* getReflectionTexture() const
{
return mReflectionTexture.get();
}
private: private:
osg::ref_ptr<osg::Texture2D> mReflectionTexture;
osg::ref_ptr<ClipCullNode> mClipCullNode; osg::ref_ptr<ClipCullNode> mClipCullNode;
osg::ref_ptr<osg::Node> mScene; 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. /// 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) , mTop(0)
, mInterior(false) , mInterior(false)
, mCullCallback(nullptr) , mCullCallback(nullptr)
, mShaderWaterStateSetUpdater(nullptr)
{ {
mSimulation.reset(new RippleSimulation(mSceneRoot, resourceSystem)); mSimulation.reset(new RippleSimulation(mSceneRoot, resourceSystem));
@ -500,19 +453,26 @@ osg::Uniform *Water::getRainIntensityUniform()
void Water::updateWaterMaterial() void Water::updateWaterMaterial()
{ {
if (mShaderWaterStateSetUpdater)
{
mWaterNode->removeCullCallback(mShaderWaterStateSetUpdater);
mShaderWaterStateSetUpdater = nullptr;
}
if (mReflection) if (mReflection)
{ {
mReflection->removeChildren(0, mReflection->getNumChildren());
mParent->removeChild(mReflection); mParent->removeChild(mReflection);
mReflection = nullptr; mReflection = nullptr;
} }
if (mRefraction) if (mRefraction)
{ {
mRefraction->removeChildren(0, mRefraction->getNumChildren());
mParent->removeChild(mRefraction); mParent->removeChild(mRefraction);
mRefraction = nullptr; mRefraction = nullptr;
} }
mWaterNode->setStateSet(nullptr);
mWaterGeom->setStateSet(nullptr);
mWaterGeom->setUpdateCallback(nullptr);
if (Settings::Manager::getBool("shader", "Water")) if (Settings::Manager::getBool("shader", "Water"))
{ {
mReflection = new Reflection(mInterior); mReflection = new Reflection(mInterior);
@ -532,7 +492,7 @@ void Water::updateWaterMaterial()
mParent->addChild(mRefraction); mParent->addChild(mRefraction);
} }
createShaderWaterStateSet(mWaterGeom, mReflection, mRefraction); createShaderWaterStateSet(mWaterNode, mReflection, mRefraction);
} }
else else
createSimpleWaterStateSet(mWaterGeom, Fallback::Map::getFloat("Water_World_Alpha")); createSimpleWaterStateSet(mWaterGeom, Fallback::Map::getFloat("Water_World_Alpha"));
@ -540,12 +500,12 @@ void Water::updateWaterMaterial()
updateVisible(); updateVisible();
} }
osg::Camera *Water::getReflectionCamera() osg::Node *Water::getReflectionNode()
{ {
return mReflection; return mReflection;
} }
osg::Camera *Water::getRefractionCamera() osg::Node* Water::getRefractionNode()
{ {
return mRefraction; return mRefraction;
} }
@ -590,17 +550,75 @@ void Water::createSimpleWaterStateSet(osg::Node* node, float alpha)
sceneManager->setForceShaders(oldValue); 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) void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, Refraction* refraction)
{ {
// use a define map to conditionally compile the shader // use a define map to conditionally compile the shader
std::map<std::string, std::string> defineMap; 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(); 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> 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> 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()) if (normalMap->getImage())
normalMap->getImage()->flipVertical(); 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::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
normalMap->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR); normalMap->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
osg::ref_ptr<osg::StateSet> shaderStateset = new osg::StateSet; mShaderWaterStateSetUpdater = new ShaderWaterStateSetUpdater(this, mReflection, mRefraction, program, normalMap);
shaderStateset->addUniform(new osg::Uniform("normalMap", 0)); node->addCullCallback(mShaderWaterStateSetUpdater);
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);
} }
void Water::processChangedSettings(const Settings::CategorySettingVector& settings) void Water::processChangedSettings(const Settings::CategorySettingVector& settings)
@ -660,13 +643,11 @@ Water::~Water()
if (mReflection) if (mReflection)
{ {
mReflection->removeChildren(0, mReflection->getNumChildren());
mParent->removeChild(mReflection); mParent->removeChild(mReflection);
mReflection = nullptr; mReflection = nullptr;
} }
if (mRefraction) if (mRefraction)
{ {
mRefraction->removeChildren(0, mRefraction->getNumChildren());
mParent->removeChild(mRefraction); mParent->removeChild(mRefraction);
mRefraction = nullptr; mRefraction = nullptr;
} }

View file

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

View file

@ -52,7 +52,7 @@ add_component_dir (shader
add_component_dir (sceneutil add_component_dir (sceneutil
clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller
lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer 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 add_component_dir (nif

View file

@ -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();
}
}

View file

@ -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