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:
parent
da917fc9e7
commit
5c4e6c3f57
6 changed files with 297 additions and 150 deletions
|
@ -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));
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
103
components/sceneutil/rtt.cpp
Normal file
103
components/sceneutil/rtt.cpp
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
62
components/sceneutil/rtt.hpp
Normal file
62
components/sceneutil/rtt.hpp
Normal 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
|
Loading…
Reference in a new issue