Basic water rendering

c++11
scrawl 9 years ago
parent de8e5f0db1
commit 01944c33f5

@ -22,8 +22,8 @@ source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
bulletdebugdraw globalmap characterpreview camera localmap
# occlusionquery water shadows ripplesimulation refraction terrainstorage
bulletdebugdraw globalmap characterpreview camera localmap water
# occlusionquery shadows ripplesimulation refraction terrainstorage
)
add_openmw_dir (mwinput

@ -157,7 +157,7 @@ osg::ref_ptr<osg::Camera> LocalMap::createOrthographicCamera(float x, float y, f
camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
camera->setRenderOrder(osg::Camera::PRE_RENDER);
camera->setCullMask(MWRender::Mask_Scene);
camera->setCullMask(MWRender::Mask_Scene|MWRender::Mask_Water);
camera->setNodeMask(Mask_RenderToTexture);
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;

@ -1,110 +0,0 @@
#include "refraction.hpp"
#include <OgreCamera.h>
#include <OgreTextureManager.h>
#include <OgreSceneManager.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreRenderTarget.h>
#include <OgreViewport.h>
#include <OgreRoot.h>
#include <OgreRenderTexture.h>
#include <OgreSceneNode.h>
#include <extern/shiny/Main/Factory.hpp>
#include "renderconst.hpp"
namespace MWRender
{
Refraction::Refraction(Ogre::Camera *parentCamera)
: mParentCamera(parentCamera)
, mRenderActive(false)
, mIsUnderwater(false)
{
mCamera = mParentCamera->getSceneManager()->createCamera("RefractionCamera");
mParentCamera->getSceneManager()->addRenderQueueListener(this);
Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual("WaterRefraction",
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 512, 512, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET);
mRenderTarget = texture->getBuffer()->getRenderTarget();
Ogre::Viewport* vp = mRenderTarget->addViewport(mCamera);
vp->setOverlaysEnabled(false);
vp->setShadowsEnabled(false);
vp->setVisibilityMask(RV_Refraction);
vp->setMaterialScheme("water_refraction");
vp->setBackgroundColour (Ogre::ColourValue(0.090195f, 0.115685f, 0.12745f));
mRenderTarget->setAutoUpdated(true);
mRenderTarget->addListener(this);
}
Refraction::~Refraction()
{
mRenderTarget->removeListener(this);
Ogre::TextureManager::getSingleton().remove("WaterRefraction");
mParentCamera->getSceneManager()->destroyCamera(mCamera);
mParentCamera->getSceneManager()->removeRenderQueueListener(this);
}
void Refraction::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)
{
if (mParentCamera->isAttached())
mParentCamera->getParentSceneNode ()->needUpdate ();
mCamera->setOrientation(mParentCamera->getDerivedOrientation());
mCamera->setPosition(mParentCamera->getDerivedPosition());
mCamera->setNearClipDistance(mParentCamera->getNearClipDistance());
mCamera->setFarClipDistance(mParentCamera->getFarClipDistance());
mCamera->setAspectRatio(mParentCamera->getAspectRatio());
mCamera->setFOVy(mParentCamera->getFOVy());
// for depth calculation, we want the original viewproj matrix _without_ the custom near clip plane.
// since all we are interested in is depth, we only need the third row of the matrix.
Ogre::Matrix4 projMatrix = mCamera->getProjectionMatrixWithRSDepth () * mCamera->getViewMatrix ();
sh::Vector4* row3 = new sh::Vector4(projMatrix[2][0], projMatrix[2][1], projMatrix[2][2], projMatrix[2][3]);
sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty<sh::Vector4> (row3));
// enable clip plane here to take advantage of CPU culling for overwater or underwater objects
mCamera->enableCustomNearClipPlane(mIsUnderwater ? mNearClipPlaneUnderwater : mNearClipPlane);
mRenderActive = true;
}
void Refraction::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)
{
mCamera->disableCustomNearClipPlane ();
mRenderActive = false;
}
void Refraction::setHeight(float height)
{
mNearClipPlane = Ogre::Plane( -Ogre::Vector3(0,0,1), -(height + 5));
mNearClipPlaneUnderwater = Ogre::Plane( Ogre::Vector3(0,0,1), height - 5);
}
void Refraction::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation)
{
// We don't want the sky to get clipped by custom near clip plane (the water plane)
if (queueGroupId < 20 && mRenderActive)
{
mCamera->disableCustomNearClipPlane();
Ogre::Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS());
}
}
void Refraction::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation)
{
if (queueGroupId < 20 && mRenderActive)
{
mCamera->enableCustomNearClipPlane(mIsUnderwater ? mNearClipPlaneUnderwater : mNearClipPlane);
Ogre::Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS());
}
}
void Refraction::setActive(bool active)
{
mRenderTarget->setActive(active);
}
}

@ -1,45 +0,0 @@
#ifndef MWRENDER_REFRACTION_H
#define MWRENDER_REFRACTION_H
#include <OgrePlane.h>
#include <OgreRenderTargetListener.h>
#include <OgreRenderQueueListener.h>
namespace Ogre
{
class Camera;
class RenderTarget;
}
namespace MWRender
{
class Refraction : public Ogre::RenderTargetListener, public Ogre::RenderQueueListener
{
public:
Refraction(Ogre::Camera* parentCamera);
~Refraction();
void setHeight (float height);
void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt);
void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt);
void setUnderwater(bool underwater) {mIsUnderwater = underwater;}
void setActive (bool active);
void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation);
void renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation);
private:
Ogre::Camera* mParentCamera;
Ogre::Camera* mCamera;
Ogre::RenderTarget* mRenderTarget;
Ogre::Plane mNearClipPlane;
Ogre::Plane mNearClipPlaneUnderwater;
bool mRenderActive;
bool mIsUnderwater;
};
}
#endif

@ -34,6 +34,7 @@
#include "vismask.hpp"
#include "pathgrid.hpp"
#include "camera.hpp"
#include "water.hpp"
namespace MWRender
{
@ -129,7 +130,9 @@ namespace MWRender
mResourceSystem->getSceneManager()->setIncrementalCompileOperation(mViewer->getIncrementalCompileOperation());
mEffectManager.reset(new EffectManager(mRootNode, mResourceSystem));
mEffectManager.reset(new EffectManager(lightRoot, mResourceSystem));
mWater.reset(new Water(lightRoot, mResourceSystem));
mCamera.reset(new Camera(mViewer->getCamera()));
@ -177,6 +180,7 @@ namespace MWRender
mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera");
mFieldOfView = Settings::Manager::getFloat("field of view", "General");
updateProjectionMatrix();
mStateUpdater->setFogEnd(mViewDistance);
}
RenderingManager::~RenderingManager()
@ -230,6 +234,8 @@ namespace MWRender
void RenderingManager::addCell(const MWWorld::CellStore *store)
{
mPathgrid->addCell(store);
mWater->changeCell(store);
}
void RenderingManager::removeCell(const MWWorld::CellStore *store)
@ -253,6 +259,22 @@ namespace MWRender
mStateUpdater->setWireframe(wireframe);
return wireframe;
}
else if (mode == Render_Water)
{
return mWater->toggle();
}
else if (mode == Render_Scene)
{
int mask = mViewer->getCamera()->getCullMask();
bool enabled = mask&Mask_Scene;
enabled = !enabled;
if (enabled)
mask |= Mask_Scene;
else
mask &= ~Mask_Scene;
mViewer->getCamera()->setCullMask(mask);
return enabled;
}
/*
else //if (mode == Render_BoundingBoxes)
{
@ -271,12 +293,9 @@ namespace MWRender
configureFog (cell->mAmbi.mFogDensity, color);
}
void RenderingManager::configureFog(float /* fogDepth */, const osg::Vec4f &colour)
void RenderingManager::configureFog(float /* fogDepth */, const osg::Vec4f &color)
{
mViewer->getCamera()->setClearColor(colour);
mStateUpdater->setFogColor(colour);
mStateUpdater->setFogEnd(mViewDistance);
mFogColor = color;
}
SkyManager* RenderingManager::getSkyManager()
@ -289,6 +308,19 @@ namespace MWRender
mEffectManager->update(dt);
mSky->update(dt);
mCamera->update(dt, paused);
osg::Vec3f focal, cameraPos;
mCamera->getPosition(focal, cameraPos);
if (mWater->isUnderwater(cameraPos))
{
setFogColor(osg::Vec4f(0.090195f, 0.115685f, 0.12745f, 1.f));
mStateUpdater->setFogEnd(1000);
}
else
{
setFogColor(mFogColor);
mStateUpdater->setFogEnd(mViewDistance);
}
}
void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr)
@ -325,6 +357,16 @@ namespace MWRender
mObjects->removeObject(ptr);
}
void RenderingManager::setWaterEnabled(bool enabled)
{
mWater->setEnabled(enabled);
}
void RenderingManager::setWaterHeight(float height)
{
mWater->setHeight(height);
}
void RenderingManager::getCameraToViewportRay(float nX, float nY, osg::Vec3f &origin, osg::Vec3f &dest)
{
osg::Matrix viewProj = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix();
@ -390,7 +432,7 @@ namespace MWRender
osgUtil::IntersectionVisitor intersectionVisitor(intersector);
int mask = intersectionVisitor.getTraversalMask();
mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect);
mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect|Mask_Water);
if (ignorePlayer)
mask &= ~(Mask_Player);
@ -521,6 +563,13 @@ namespace MWRender
mViewer->startThreading();
}
void RenderingManager::setFogColor(const osg::Vec4f &color)
{
mViewer->getCamera()->setClearColor(color);
mStateUpdater->setFogColor(color);
}
void RenderingManager::processChangedSettings(const Settings::CategorySettingVector &changed)
{
for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it)

@ -42,6 +42,7 @@ namespace MWRender
class NpcAnimation;
class Pathgrid;
class Camera;
class Water;
class RenderingManager : public MWRender::RenderingInterface
{
@ -73,6 +74,9 @@ namespace MWRender
void removeObject(const MWWorld::Ptr& ptr);
void setWaterEnabled(bool enabled);
void setWaterHeight(float level);
/// Return the object under the mouse cursor / crosshair position, given by nX and nY normalized screen coordinates,
/// where (0,0) is the top left corner.
MWWorld::Ptr getFacedObject(const float nX, const float nY, float maxDistance, bool ignorePlayer);
@ -131,6 +135,7 @@ namespace MWRender
private:
void updateProjectionMatrix();
void updateTextureFiltering();
void setFogColor(const osg::Vec4f& color);
osg::ref_ptr<osgViewer::Viewer> mViewer;
osg::ref_ptr<osg::Group> mRootNode;
@ -141,6 +146,7 @@ namespace MWRender
std::auto_ptr<Pathgrid> mPathgrid;
std::auto_ptr<Objects> mObjects;
std::auto_ptr<Water> mWater;
std::auto_ptr<SkyManager> mSky;
std::auto_ptr<EffectManager> mEffectManager;
std::auto_ptr<NpcAnimation> mPlayerAnimation;
@ -149,6 +155,8 @@ namespace MWRender
osg::ref_ptr<StateUpdater> mStateUpdater;
osg::Vec4f mFogColor;
float mNearClip;
float mViewDistance;
float mFieldOfView;

@ -9,7 +9,9 @@ namespace MWRender
Render_CollisionDebug,
Render_Wireframe,
Render_Pathgrid,
Render_BoundingBoxes
Render_BoundingBoxes,
Render_Water,
Render_Scene
};
}

@ -15,13 +15,14 @@ namespace MWRender
Mask_Actor = (1<<3),
Mask_Player = (1<<4),
Mask_Sky = (1<<5),
Mask_Water = (1<<6),
// top level masks
Mask_Scene = (1<<6),
Mask_GUI = (1<<7),
Mask_Scene = (1<<7),
Mask_GUI = (1<<8),
// Set on cameras within the main scene graph
Mask_RenderToTexture = (1<<8)
Mask_RenderToTexture = (1<<9)
// reserved: (1<<16) for SceneUtil::Mask_Lit
};

@ -1,491 +1,184 @@
#include "water.hpp"
#include <OgreRenderTexture.h>
#include <OgreEntity.h>
#include <OgreMeshManager.h>
#include <OgreMaterialManager.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreRoot.h>
#include <OgreCamera.h>
#include <OgreTextureManager.h>
#include <OgreViewport.h>
#include <OgreSceneNode.h>
#include <OgreTechnique.h>
#include "sky.hpp"
#include "renderingmanager.hpp"
#include "ripplesimulation.hpp"
#include "refraction.hpp"
#include <extern/shiny/Main/Factory.hpp>
#include <extern/shiny/Platforms/Ogre/OgreMaterial.hpp>
using namespace Ogre;
#include <iomanip>
namespace MWRender
{
CubeReflection::CubeReflection(Ogre::SceneManager* sceneManager)
: Reflection(sceneManager)
{
Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton ().createManual("CubeReflection",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_CUBE_MAP,
512,512, 0, PF_R8G8B8, TU_RENDERTARGET);
mCamera = mSceneMgr->createCamera ("CubeCamera");
mCamera->setNearClipDistance (5);
mCamera->setFarClipDistance (1000);
for (int face = 0; face < 6; ++face)
{
mRenderTargets[face] = texture->getBuffer (face)->getRenderTarget();
mRenderTargets[face]->removeAllViewports ();
Viewport* vp = mRenderTargets[face]->addViewport (mCamera);
vp->setOverlaysEnabled(false);
vp->setShadowsEnabled(false);
vp->setMaterialScheme ("water_reflection");
mRenderTargets[face]->setAutoUpdated(false);
/*
Vector3 lookAt(0,0,0), up(0,0,0), right(0,0,0);
switch(face)
{
case 0: lookAt.x =-1; up.y = 1; right.z = 1; break; // +X
case 1: lookAt.x = 1; up.y = 1; right.z =-1; break; // -X
case 2: lookAt.y =-1; up.z = 1; right.x = 1; break; // +Y
case 3: lookAt.y = 1; up.z =-1; right.x = 1; break; // -Y
case 4: lookAt.z = 1; up.y = 1; right.x =-1; break; // +Z
case 5: lookAt.z =-1; up.y = 1; right.x =-1; break; // -Z
}
Quaternion orient(right, up, lookAt);
mCamera->setOrientation(orient);
*/
}
}
#include <osg/Group>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Material>
#include <osg/PositionAttitudeTransform>
#include <osg/Depth>
CubeReflection::~CubeReflection ()
{
Ogre::TextureManager::getSingleton ().remove("CubeReflection");
mSceneMgr->destroyCamera (mCamera);
}
#include <components/resource/resourcesystem.hpp>
#include <components/resource/texturemanager.hpp>
void CubeReflection::update ()
{
if (mParentCamera->isAttached())
mParentCamera->getParentSceneNode ()->needUpdate ();
mCamera->setPosition(mParentCamera->getDerivedPosition());
}
#include <components/nifosg/controller.hpp>
#include <components/sceneutil/controller.hpp>
// --------------------------------------------------------------------------------------------------------------------------------
#include "vismask.hpp"
PlaneReflection::PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky)
: Reflection(sceneManager)
, mSky(sky)
, mRenderActive(false)
namespace
{
mCamera = mSceneMgr->createCamera ("PlaneReflectionCamera");
mSceneMgr->addRenderQueueListener(this);
mTexture = TextureManager::getSingleton().createManual("WaterReflection",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, 512, 512, 0, PF_R8G8B8, TU_RENDERTARGET);
mRenderTarget = mTexture->getBuffer()->getRenderTarget();
Viewport* vp = mRenderTarget->addViewport(mCamera);
vp->setOverlaysEnabled(false);
vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f));
vp->setShadowsEnabled(false);
vp->setMaterialScheme("water_reflection");
mRenderTarget->addListener(this);
mRenderTarget->setActive(true);
mRenderTarget->setAutoUpdated(true);
sh::Factory::getInstance ().setTextureAlias ("WaterReflection", mTexture->getName());
}
PlaneReflection::~PlaneReflection ()
{
mRenderTarget->removeListener (this);
mSceneMgr->destroyCamera (mCamera);
mSceneMgr->removeRenderQueueListener(this);
TextureManager::getSingleton ().remove("WaterReflection");
}
void PlaneReflection::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation)
{
// We don't want the sky to get clipped by custom near clip plane (the water plane)
if (queueGroupId < 20 && mRenderActive)
osg::ref_ptr<osg::Geometry> createWaterGeometry(float size, int segments, float textureRepeats)
{
mCamera->disableCustomNearClipPlane();
Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS());
}
}
void PlaneReflection::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation)
{
if (queueGroupId < 20 && mRenderActive)
{
mCamera->enableCustomNearClipPlane(mIsUnderwater ? mErrorPlaneUnderwater : mErrorPlane);
Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS());
}
}
void PlaneReflection::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)
{
if (mParentCamera->isAttached())
mParentCamera->getParentSceneNode ()->needUpdate ();
mCamera->setOrientation(mParentCamera->getDerivedOrientation());
mCamera->setPosition(mParentCamera->getDerivedPosition());
mCamera->setNearClipDistance(mParentCamera->getNearClipDistance());
mCamera->setFarClipDistance(mParentCamera->getFarClipDistance());
mCamera->setAspectRatio(mParentCamera->getAspectRatio());
mCamera->setFOVy(mParentCamera->getFOVy());
mRenderActive = true;
mCamera->enableReflection(mWaterPlane);
// for depth calculation, we want the original viewproj matrix _without_ the custom near clip plane.
// since all we are interested in is depth, we only need the third row of the matrix.
Ogre::Matrix4 projMatrix = mCamera->getProjectionMatrixWithRSDepth () * mCamera->getViewMatrix ();
sh::Vector4* row3 = new sh::Vector4(projMatrix[2][0], projMatrix[2][1], projMatrix[2][2], projMatrix[2][3]);
sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty<sh::Vector4> (row3));
// enable clip plane here to take advantage of CPU culling for overwater or underwater objects
mCamera->enableCustomNearClipPlane(mIsUnderwater ? mErrorPlaneUnderwater : mErrorPlane);
}
void PlaneReflection::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt)
{
mCamera->disableReflection();
mCamera->disableCustomNearClipPlane();
mRenderActive = false;
}
void PlaneReflection::setHeight (float height)
{
mWaterPlane = Plane(Ogre::Vector3(0,0,1), height);
mErrorPlane = Plane(Ogre::Vector3(0,0,1), height - 5);
mErrorPlaneUnderwater = Plane(Ogre::Vector3(0,0,-1), -height - 5);
}
void PlaneReflection::setActive (bool active)
{
mRenderTarget->setActive(active);
}
void PlaneReflection::setViewportBackground(Ogre::ColourValue colour)
{
mRenderTarget->getViewport (0)->setBackgroundColour (colour);
}
void PlaneReflection::setVisibilityMask (int flags)
{
mRenderTarget->getViewport (0)->setVisibilityMask (flags);
}
// --------------------------------------------------------------------------------------------------------------------------------
Water::Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallback* fallback) :
mCamera (camera), mSceneMgr (camera->getSceneManager()),
mIsUnderwater(false), mActive(1),
mToggled(1), mWaterTimer(0.f),
mRendering(rend),
mVisibilityFlags(0),
mReflection(NULL),
mRefraction(NULL),
mSimulation(NULL),
mPlayer(0,0)
{
mSimulation = new RippleSimulation(mSceneMgr, fallback);
mSky = rend->getSkyManager();
mMaterial = MaterialManager::getSingleton().getByName("Water");
mTop = 0;
mIsUnderwater = false;
mWaterPlane = Plane(Vector3::UNIT_Z, 0);
int waterScale = 30;
MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane,
static_cast<Ogre::Real>(CELL_SIZE*5*waterScale), static_cast<Ogre::Real>(CELL_SIZE*5*waterScale),
40, 40, true, 1, static_cast<Ogre::Real>(3 * waterScale), static_cast<Ogre::Real>(3 * waterScale), Vector3::UNIT_Y);
mWater = mSceneMgr->createEntity("water");
mWater->setVisibilityFlags(RV_Water);
mWater->setCastShadows(false);
mWater->setRenderQueueGroup(RQG_Alpha);
mWaterNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
mWaterNode->attachObject(mWater);
applyRTT();
applyVisibilityMask();
mWater->setMaterial(mMaterial);
osg::ref_ptr<osg::Vec3Array> verts (new osg::Vec3Array);
osg::ref_ptr<osg::Vec2Array> texcoords (new osg::Vec2Array);
// some drivers don't like huge triangles, so we do some subdivisons
// a paged solution would be even better
const float step = size/segments;
const float texCoordStep = textureRepeats / segments;
for (int x=0; x<segments; ++x)
{
for (int y=0; y<segments; ++y)
{
float x1 = -size/2.f + x*step;
float y1 = -size/2.f + y*step;
float x2 = x1 + step;
float y2 = y1 + step;
verts->push_back(osg::Vec3f(x1, y2, 0.f));
verts->push_back(osg::Vec3f(x1, y1, 0.f));
verts->push_back(osg::Vec3f(x2, y1, 0.f));
verts->push_back(osg::Vec3f(x2, y2, 0.f));
float u1 = x*texCoordStep;
float v1 = y*texCoordStep;
float u2 = u1 + texCoordStep;
float v2 = v1 + texCoordStep;
texcoords->push_back(osg::Vec2f(u1, v2));
texcoords->push_back(osg::Vec2f(u1, v1));
texcoords->push_back(osg::Vec2f(u2, v1));
texcoords->push_back(osg::Vec2f(u2, v2));
}
}
setHeight(mTop);
osg::ref_ptr<osg::Geometry> waterGeom (new osg::Geometry);
waterGeom->setVertexArray(verts);
waterGeom->setTexCoordArray(0, texcoords);
sh::MaterialInstance* m = sh::Factory::getInstance ().getMaterialInstance ("Water");
m->setListener (this);
waterGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,verts->size()));
return waterGeom;
}
// ----------------------------------------------------------------------------------------------
// ---------------------------------- reflection debug overlay ----------------------------------
// ----------------------------------------------------------------------------------------------
/*
if (Settings::Manager::getBool("shader", "Water"))
void createWaterStateSet(Resource::ResourceSystem* resourceSystem, osg::ref_ptr<osg::Node> node)
{
OverlayManager& mgr = OverlayManager::getSingleton();
Overlay* overlay;
// destroy if already exists
if ((overlay = mgr.getByName("ReflectionDebugOverlay")))
mgr.destroy(overlay);
osg::ref_ptr<osg::StateSet> stateset (new osg::StateSet);
overlay = mgr.create("ReflectionDebugOverlay");
osg::ref_ptr<osg::Material> material (new osg::Material);
material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f));
material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f));
material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f));
material->setColorMode(osg::Material::OFF);
stateset->setAttributeAndModes(material, osg::StateAttribute::ON);
if (MaterialManager::getSingleton().resourceExists("Ogre/ReflectionDebugTexture"))
MaterialManager::getSingleton().remove("Ogre/ReflectionDebugTexture");
MaterialPtr debugMat = MaterialManager::getSingleton().create(
"Ogre/ReflectionDebugTexture",
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false);
debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(mReflectionTexture->getName());
osg::ref_ptr<osg::Depth> depth (new osg::Depth);
depth->setWriteMask(false);
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);
OverlayContainer* debugPanel;
stateset->setRenderBinDetails(9, "RenderBin");
// destroy container if exists
try
std::vector<osg::ref_ptr<osg::Texture2D> > textures;
for (int i=0; i<32; ++i)
{
if ((debugPanel =
static_cast<OverlayContainer*>(
mgr.getOverlayElement("Ogre/ReflectionDebugTexPanel"
))))
mgr.destroyOverlayElement(debugPanel);
std::ostringstream texname;
texname << "textures/water/water" << std::setw(2) << std::setfill('0') << i << ".dds";
textures.push_back(resourceSystem->getTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT));
}
catch (Ogre::Exception&) {}
debugPanel = (OverlayContainer*)
(OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/ReflectionDebugTexPanel"));
debugPanel->_setPosition(0, 0.55);
debugPanel->_setDimensions(0.3, 0.3);
debugPanel->setMaterialName(debugMat->getName());
debugPanel->show();
overlay->add2D(debugPanel);
overlay->show();
}
*/
}
void Water::setActive(bool active)
{
mActive = active;
updateVisible();
osg::ref_ptr<NifOsg::FlipController> controller (new NifOsg::FlipController(0, 2/32.f, textures));
controller->setSource(boost::shared_ptr<SceneUtil::ControllerSource>(new SceneUtil::FrameTimeSource));
node->addUpdateCallback(controller);
node->setStateSet(stateset);
stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON);
}
sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty<sh::FloatValue> (new sh::FloatValue(active ? 1.0f : 0.0f)));
}
Water::~Water()
namespace MWRender
{
MeshManager::getSingleton().remove("water");
mWaterNode->detachObject(mWater);
mSceneMgr->destroyEntity(mWater);
mSceneMgr->destroySceneNode(mWaterNode);
delete mReflection;
delete mRefraction;
delete mSimulation;
}
// --------------------------------------------------------------------------------------------------------------------------------
void Water::changeCell(const ESM::Cell* cell)
Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem)
: mParent(parent)
, mResourceSystem(resourceSystem)
, mEnabled(true)
, mToggled(true)
, mTop(0)
{
if(cell->isExterior())
mWaterNode->setPosition(getSceneNodeCoordinates(cell->mData.mX, cell->mData.mY));
}
osg::ref_ptr<osg::Geometry> waterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900);
void Water::setHeight(const float height)
{
mTop = height;
osg::ref_ptr<osg::Geode> geode (new osg::Geode);
geode->addDrawable(waterGeom);
geode->setNodeMask(Mask_Water);
mSimulation->setWaterHeight(height);
createWaterStateSet(mResourceSystem, geode);
mWaterPlane = Plane(Vector3::UNIT_Z, -height);
mWaterNode = new osg::PositionAttitudeTransform;
mWaterNode->addChild(geode);
if (mReflection)
mReflection->setHeight(height);
if (mRefraction)
mRefraction->setHeight(height);
mParent->addChild(mWaterNode);
mWaterNode->setPosition(0, 0, height);
sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty<sh::FloatValue>(new sh::FloatValue(height)));
setHeight(mTop);
}
bool Water::toggle()
Water::~Water()
{
mToggled = !mToggled;
updateVisible();
return mToggled;
mParent->removeChild(mWaterNode);
}
void
Water::updateUnderwater(bool underwater)
void Water::setEnabled(bool enabled)
{
if (!mActive) {
return;
}
mIsUnderwater =
underwater &&
mWater->isVisible() &&
mCamera->getPolygonMode() == Ogre::PM_SOLID;
if (mReflection)
mReflection->setUnderwater (mIsUnderwater);
if (mRefraction)
mRefraction->setUnderwater (mIsUnderwater);
mEnabled = enabled;
updateVisible();
}
Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY)
void Water::changeCell(const MWWorld::CellStore* store)
{
return Vector3(static_cast<Ogre::Real>(gridX * CELL_SIZE + (CELL_SIZE / 2)), static_cast<Ogre::Real>(gridY * CELL_SIZE + (CELL_SIZE / 2)), mTop);
if (store->getCell()->isExterior())
mWaterNode->setPosition(getSceneNodeCoordinates(store->getCell()->mData.mX, store->getCell()->mData.mY));
else
mWaterNode->setPosition(osg::Vec3f(0,0,mTop));
}
void Water::setViewportBackground(const ColourValue& bg)
void Water::setHeight(const float height)
{
if (mReflection)
mReflection->setViewportBackground(bg);
}
mTop = height;
void Water::updateVisible()
{
mWater->setVisible(mToggled && mActive);
if (mReflection)
mReflection->setActive(mToggled && mActive);
if (mRefraction)
mRefraction->setActive(mToggled && mActive);
osg::Vec3f pos = mWaterNode->getPosition();
pos.z() = height;
mWaterNode->setPosition(pos);
}
void Water::update(float dt, Ogre::Vector3 player)
void Water::updateVisible()
{
mWaterTimer += dt;
sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty<sh::FloatValue>(new sh::FloatValue(mWaterTimer)));
mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater);
mPlayer = Ogre::Vector2(player.x, player.y);
mWaterNode->setNodeMask(mEnabled && mToggled ? ~0 : 0);
}
void Water::frameStarted(float dt)
{
if (!mActive)
return;
mSimulation->update(dt, mPlayer);
if (mReflection)
{
mReflection->update();
}
}
void Water::applyRTT()
bool Water::toggle()
{
delete mReflection;
mReflection = NULL;
delete mRefraction;
mRefraction = NULL;
// Create rendertarget for reflection
//int rttsize = Settings::Manager::getInt("rtt size", "Water");
if (Settings::Manager::getBool("shader", "Water"))
{
mReflection = new PlaneReflection(mSceneMgr, mSky);
mReflection->setParentCamera (mCamera);
mReflection->setHeight(mTop);
if (Settings::Manager::getBool("refraction", "Water"))
{
mRefraction = new Refraction(mCamera);
mRefraction->setHeight(mTop);
}
}
mToggled = !mToggled;
updateVisible();
return mToggled;
}
void Water::applyVisibilityMask()
{
mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water")
+ (RV_Statics + RV_StaticsSmall + RV_Misc) * Settings::Manager::getBool("reflect statics", "Water")
+ RV_Actors * Settings::Manager::getBool("reflect actors", "Water")
+ RV_Effects
+ RV_Sky;
if (mReflection)
mReflection->setVisibilityMask(mVisibilityFlags);
}
void Water::processChangedSettings(const Settings::CategorySettingVector& settings)
{
bool applyRT = false;
bool applyVisMask = false;
for (Settings::CategorySettingVector::const_iterator it=settings.begin();
it != settings.end(); ++it)
{
if ( it->first == "Water" && (
it->second == "shader"
|| it->second == "refraction"
|| it->second == "rtt size"))
applyRT = true;
if ( it->first == "Water" && (
it->second == "reflect actors"
|| it->second == "reflect terrain"
|| it->second == "reflect statics"))
applyVisMask = true;
}
if(applyRT)
{
applyRTT();
applyVisibilityMask();
mWater->setMaterial(mMaterial);
}
if (applyVisMask)
applyVisibilityMask();
}
void Water::requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration)
bool Water::isUnderwater(const osg::Vec3f &pos) const
{
return pos.z() < mTop && mToggled && mEnabled;
}
void Water::createdConfiguration (sh::MaterialInstance* m, const std::string& configuration)
osg::Vec3f Water::getSceneNodeCoordinates(int gridX, int gridY)
{
if (configuration == "local_map" || !Settings::Manager::getBool("shader", "Water"))
{
// for simple water, set animated texture names
// these have to be set in code
std::string textureNames[32];
for (int i=0; i<32; ++i)
{
textureNames[i] = "textures\\water\\water" + StringConverter::toString(i, 2, '0') + ".dds";
}
Ogre::Technique* t = static_cast<sh::OgreMaterial*>(m->getMaterial())->getOgreTechniqueForConfiguration(configuration);
if (t->getPass(0)->getNumTextureUnitStates () == 0)
return;
t->getPass(0)->getTextureUnitState(0)->setAnimatedTextureName(textureNames, 32, 2);
t->getPass(0)->setDepthWriteEnabled (false);
t->getPass(0)->setSceneBlending (Ogre::SBT_TRANSPARENT_ALPHA);
}
return osg::Vec3f(static_cast<float>(gridX * CELL_SIZE + (CELL_SIZE / 2)), static_cast<float>(gridY * CELL_SIZE + (CELL_SIZE / 2)), mTop);
}
/*
void Water::addEmitter (const MWWorld::Ptr& ptr, float scale, float force)
{
mSimulation->addEmitter (ptr, scale, force);
@ -500,10 +193,6 @@ void Water::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr)
{
mSimulation->updateEmitterPtr(old, ptr);
}
*/
void Water::clearRipples()
{
mSimulation->clear();
}
} // namespace

@ -1,183 +1,60 @@
#ifndef GAME_MWRENDER_WATER_H
#define GAME_MWRENDER_WATER_H
#ifndef OPENMW_MWRENDER_WATER_H
#define OPENMW_MWRENDER_WATER_H
#include <OgrePlane.h>
#include <OgreRenderQueue.h>
#include <OgreRenderQueueListener.h>
#include <OgreRenderTargetListener.h>
#include <OgreMaterial.h>
#include <OgreTexture.h>
#include <OgreVector2.h>
#include <osg/ref_ptr>
#include <components/esm/loadcell.hpp>
#include <components/settings/settings.hpp>
#include "../mwworld/cellstore.hpp"
#include <extern/shiny/Main/MaterialInstance.hpp>
#include "renderconst.hpp"
#include "../mwworld/ptr.hpp"
namespace Ogre
namespace osg
{
class Camera;
class SceneManager;
class SceneNode;
class Entity;
class Vector3;
class Rectangle2D;
struct RenderTargetEvent;
class Group;
class PositionAttitudeTransform;
}
namespace MWWorld
namespace Resource
{
class Fallback;
class ResourceSystem;
}
namespace MWRender {
class SkyManager;
class RenderingManager;
class RippleSimulation;
class Refraction;
class Reflection
{
public:
Reflection(Ogre::SceneManager* sceneManager)
: mCamera(NULL)
, mParentCamera(NULL)
, mSceneMgr(sceneManager)
, mIsUnderwater(false)
{}
virtual ~Reflection() {}
virtual void setHeight (float height) {}
virtual void setParentCamera (Ogre::Camera* parent) { mParentCamera = parent; }
void setUnderwater(bool underwater) { mIsUnderwater = underwater; }
virtual void setActive (bool active) {}
virtual void setViewportBackground(Ogre::ColourValue colour) {}
virtual void update() {}
virtual void setVisibilityMask (int flags) {}
protected:
Ogre::Camera* mCamera;
Ogre::Camera* mParentCamera;
Ogre::TexturePtr mTexture;
Ogre::SceneManager* mSceneMgr;
bool mIsUnderwater;
};
class CubeReflection : public Reflection
{
public:
CubeReflection(Ogre::SceneManager* sceneManager);
virtual ~CubeReflection();
virtual void update();
protected:
Ogre::RenderTarget* mRenderTargets[6];
};
class PlaneReflection : public Reflection, public Ogre::RenderQueueListener, public Ogre::RenderTargetListener
{
public:
PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky);
virtual ~PlaneReflection();
virtual void setHeight (float height);
virtual void setActive (bool active);
virtual void setVisibilityMask (int flags);
void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt);
void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt);
void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation);
void renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation);
virtual void setViewportBackground(Ogre::ColourValue colour);
protected:
Ogre::RenderTarget* mRenderTarget;
SkyManager* mSky;
Ogre::Plane mWaterPlane;
Ogre::Plane mErrorPlane;
Ogre::Plane mErrorPlaneUnderwater;
bool mRenderActive;
};
namespace MWRender
{
/// Water rendering
class Water : public sh::MaterialInstanceListener
class Water
{
static const int CELL_SIZE = 8192;
Ogre::Camera *mCamera;
Ogre::SceneManager *mSceneMgr;
Ogre::Plane mWaterPlane;
Ogre::SceneNode *mWaterNode;
Ogre::Entity *mWater;
osg::ref_ptr<osg::Group> mParent;
osg::ref_ptr<osg::PositionAttitudeTransform> mWaterNode;
Resource::ResourceSystem* mResourceSystem;
bool mIsUnderwater;
bool mActive;
bool mEnabled;
bool mToggled;
float mTop;
float mWaterTimer;
Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY);
protected:
void applyRTT();
void applyVisibilityMask();
osg::Vec3f getSceneNodeCoordinates(int gridX, int gridY);
void updateVisible();
RenderingManager* mRendering;
SkyManager* mSky;
Ogre::MaterialPtr mMaterial;
bool mUnderwaterEffect;
int mVisibilityFlags;
Reflection* mReflection;
Refraction* mRefraction;
RippleSimulation* mSimulation;
Ogre::Vector2 mPlayer;
public:
Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallback* fallback);
Water(osg::Group* parent, Resource::ResourceSystem* resourceSystem);
~Water();
void clearRipples();
void setActive(bool active);
void setEnabled(bool enabled);
bool toggle();
void update(float dt, Ogre::Vector3 player);
void frameStarted(float dt);
bool isUnderwater(const osg::Vec3f& pos) const;
/*
/// adds an emitter, position will be tracked automatically using its scene node
void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f);
void removeEmitter (const MWWorld::Ptr& ptr);
void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr);
*/
void setViewportBackground(const Ogre::ColourValue& bg);
void processChangedSettings(const Settings::CategorySettingVector& settings);
/// Updates underwater state accordingly
void updateUnderwater(bool underwater);
void changeCell(const ESM::Cell* cell);
void changeCell(const MWWorld::CellStore* store);
void setHeight(const float height);
virtual void requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration);
virtual void createdConfiguration (sh::MaterialInstance* m, const std::string& configuration);
};
}

@ -265,11 +265,11 @@ namespace MWWorld
mRendering.addCell(cell);
bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior();
float waterLevel = cell->isExterior() ? -1.f : cell->getWaterLevel();
//mRendering.setWaterEnabled(waterEnabled);
mRendering.setWaterEnabled(waterEnabled);
if (waterEnabled)
{
mPhysics->enableWater(waterLevel);
//mRendering.setWaterHeight(waterLevel);
mRendering.setWaterHeight(waterLevel);
}
else
mPhysics->disableWater();

@ -1763,17 +1763,17 @@ namespace MWWorld
void World::setWaterHeight(const float height)
{
mPhysics->setWaterHeight(height);
//mRendering->setWaterHeight(height);
mRendering->setWaterHeight(height);
}
bool World::toggleWater()
{
return 0;//mRendering->toggleWater();
return mRendering->toggleRenderMode(MWRender::Render_Water);
}
bool World::toggleWorld()
{
return 0;//mRendering->toggleWorld();
return mRendering->toggleRenderMode(MWRender::Render_Scene);
}
void World::PCDropped (const Ptr& item)

@ -399,6 +399,13 @@ FlipController::FlipController(const Nif::NiFlipController *ctrl, std::vector<os
{
}
FlipController::FlipController(int texSlot, float delta, std::vector<osg::ref_ptr<osg::Texture2D> > textures)
: mTexSlot(texSlot)
, mDelta(delta)
, mTextures(textures)
{
}
FlipController::FlipController()
{
}

@ -218,6 +218,7 @@ namespace NifOsg
public:
FlipController(const Nif::NiFlipController* ctrl, std::vector<osg::ref_ptr<osg::Texture2D> > textures);
FlipController(int texSlot, float delta, std::vector<osg::ref_ptr<osg::Texture2D> > textures);
FlipController();
FlipController(const FlipController& copy, const osg::CopyOp& copyop);

@ -20,7 +20,10 @@ namespace SceneUtil
float Controller::getInputValue(osg::NodeVisitor* nv)
{
return mFunction->calculate(mSource->getValue(nv));
if (mFunction)
return mFunction->calculate(mSource->getValue(nv));
else
return mSource->getValue(nv);
}
void Controller::setSource(boost::shared_ptr<ControllerSource> source)

Loading…
Cancel
Save