mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-01-25 06:35:30 +00:00
Reworked MWRender::Water to be more OOP-ish and possibly allow other reflection types.
This commit is contained in:
parent
6c6ce4a05c
commit
df602553d1
@ -24,12 +24,163 @@ using namespace Ogre;
|
||||
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);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
CubeReflection::~CubeReflection ()
|
||||
{
|
||||
Ogre::TextureManager::getSingleton ().remove("CubeReflection");
|
||||
mSceneMgr->destroyCamera (mCamera);
|
||||
}
|
||||
|
||||
void CubeReflection::update ()
|
||||
{
|
||||
mParentCamera->getParentSceneNode ()->needUpdate ();
|
||||
mCamera->setPosition(mParentCamera->getDerivedPosition());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
PlaneReflection::PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky)
|
||||
: Reflection(sceneManager)
|
||||
, mSky(sky)
|
||||
{
|
||||
mCamera = mSceneMgr->createCamera ("PlaneReflectionCamera");
|
||||
mSceneMgr->addRenderQueueListener(this);
|
||||
|
||||
mTexture = TextureManager::getSingleton().createManual("WaterReflection",
|
||||
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, 512, 512, 0, PF_A8R8G8B8, 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);
|
||||
// use fallback techniques without shadows and without mrt
|
||||
vp->setMaterialScheme("water_reflection");
|
||||
mRenderTarget->addListener(this);
|
||||
mRenderTarget->setActive(true);
|
||||
|
||||
sh::Factory::getInstance ().setTextureAlias ("WaterReflection", mTexture->getName());
|
||||
}
|
||||
|
||||
PlaneReflection::~PlaneReflection ()
|
||||
{
|
||||
mRenderTarget->removeListener (this);
|
||||
mSceneMgr->destroyCamera (mCamera);
|
||||
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)
|
||||
{
|
||||
mCamera->disableCustomNearClipPlane();
|
||||
Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS());
|
||||
}
|
||||
}
|
||||
|
||||
void PlaneReflection::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation)
|
||||
{
|
||||
if (queueGroupId < 20 && mRenderActive)
|
||||
{
|
||||
if (!mIsUnderwater)
|
||||
mCamera->enableCustomNearClipPlane(mErrorPlane);
|
||||
Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS());
|
||||
}
|
||||
}
|
||||
|
||||
void PlaneReflection::preRenderTargetUpdate(const RenderTargetEvent& evt)
|
||||
{
|
||||
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;
|
||||
|
||||
Vector3 pos = mParentCamera->getRealPosition();
|
||||
pos.y = (mWaterPlane).d*2 - pos.y;
|
||||
mSky->setSkyPosition(pos);
|
||||
mCamera->enableReflection(mWaterPlane);
|
||||
}
|
||||
|
||||
void PlaneReflection::postRenderTargetUpdate(const RenderTargetEvent& evt)
|
||||
{
|
||||
mSky->resetSkyPosition();
|
||||
mCamera->disableReflection();
|
||||
mCamera->disableCustomNearClipPlane();
|
||||
mRenderActive = false;
|
||||
}
|
||||
|
||||
void PlaneReflection::setWaterPlane (Plane plane)
|
||||
{
|
||||
mWaterPlane = plane;
|
||||
mErrorPlane = Plane(plane.normal, mWaterPlane.d - 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 ESM::Cell* cell) :
|
||||
mCamera (camera), mSceneManager (camera->getSceneManager()),
|
||||
mCamera (camera), mSceneMgr (camera->getSceneManager()),
|
||||
mIsUnderwater(false), mVisibilityFlags(0),
|
||||
mReflectionTarget(0), mActive(1), mToggled(1),
|
||||
mReflectionRenderActive(false), mRendering(rend),
|
||||
mWaterTimer(0.f)
|
||||
mActive(1), mToggled(1),
|
||||
mRendering(rend),
|
||||
mWaterTimer(0.f),
|
||||
mReflection(NULL)
|
||||
{
|
||||
mSky = rend->getSkyManager();
|
||||
|
||||
@ -43,13 +194,11 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel
|
||||
|
||||
MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, CELL_SIZE*5, CELL_SIZE * 5, 10, 10, true, 1, 3,3, Vector3::UNIT_Z);
|
||||
|
||||
mWater = mSceneManager->createEntity("water");
|
||||
mWater = mSceneMgr->createEntity("water");
|
||||
mWater->setVisibilityFlags(RV_Water);
|
||||
mWater->setCastShadows(false);
|
||||
|
||||
mWaterNode = mSceneManager->getRootSceneNode()->createChildSceneNode();
|
||||
|
||||
mReflectionCamera = mSceneManager->createCamera("ReflectionCamera");
|
||||
mWaterNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
|
||||
|
||||
if(!(cell->mData.mFlags & cell->Interior))
|
||||
{
|
||||
@ -72,8 +221,6 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel
|
||||
underwaterDome->setMaterialName("Underwater_Dome");
|
||||
*/
|
||||
|
||||
mSceneManager->addRenderQueueListener(this);
|
||||
|
||||
assignTextures();
|
||||
|
||||
setHeight(mTop);
|
||||
@ -142,12 +289,9 @@ Water::~Water()
|
||||
{
|
||||
MeshManager::getSingleton().remove("water");
|
||||
|
||||
if (mReflectionTarget)
|
||||
mReflectionTexture->getBuffer()->getRenderTarget()->removeListener(this);
|
||||
|
||||
mWaterNode->detachObject(mWater);
|
||||
mSceneManager->destroyEntity(mWater);
|
||||
mSceneManager->destroySceneNode(mWaterNode);
|
||||
mSceneMgr->destroyEntity(mWater);
|
||||
mSceneMgr->destroySceneNode(mWaterNode);
|
||||
}
|
||||
|
||||
void Water::changeCell(const ESM::Cell* cell)
|
||||
@ -166,8 +310,8 @@ void Water::setHeight(const float height)
|
||||
|
||||
mWaterPlane = Plane(Vector3::UNIT_Y, height);
|
||||
|
||||
// small error due to reflection texture size & reflection distortion
|
||||
mErrorPlane = Plane(Vector3::UNIT_Y, height - 5);
|
||||
if (mReflection)
|
||||
mReflection->setWaterPlane(mWaterPlane);
|
||||
|
||||
mWaterNode->setPosition(0, height, 0);
|
||||
sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty<sh::FloatValue>(new sh::FloatValue(height)));
|
||||
@ -190,6 +334,9 @@ Water::updateUnderwater(bool underwater)
|
||||
mWater->isVisible() &&
|
||||
mCamera->getPolygonMode() == Ogre::PM_SOLID;
|
||||
|
||||
if (mReflection)
|
||||
mReflection->setUnderwater (mIsUnderwater);
|
||||
|
||||
updateVisible();
|
||||
}
|
||||
|
||||
@ -198,37 +345,6 @@ Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY)
|
||||
return Vector3(gridX * CELL_SIZE + (CELL_SIZE / 2), mTop, -gridY * CELL_SIZE - (CELL_SIZE / 2));
|
||||
}
|
||||
|
||||
void Water::preRenderTargetUpdate(const RenderTargetEvent& evt)
|
||||
{
|
||||
if (evt.source == mReflectionTarget)
|
||||
{
|
||||
mCamera->getParentSceneNode ()->needUpdate ();
|
||||
mReflectionCamera->setOrientation(mCamera->getDerivedOrientation());
|
||||
mReflectionCamera->setPosition(mCamera->getDerivedPosition());
|
||||
mReflectionCamera->setNearClipDistance(mCamera->getNearClipDistance());
|
||||
mReflectionCamera->setFarClipDistance(mCamera->getFarClipDistance());
|
||||
mReflectionCamera->setAspectRatio(mCamera->getAspectRatio());
|
||||
mReflectionCamera->setFOVy(mCamera->getFOVy());
|
||||
mReflectionRenderActive = true;
|
||||
|
||||
Vector3 pos = mCamera->getRealPosition();
|
||||
pos.y = mTop*2 - pos.y;
|
||||
mSky->setSkyPosition(pos);
|
||||
mReflectionCamera->enableReflection(mWaterPlane);
|
||||
}
|
||||
}
|
||||
|
||||
void Water::postRenderTargetUpdate(const RenderTargetEvent& evt)
|
||||
{
|
||||
if (evt.source == mReflectionTarget)
|
||||
{
|
||||
mSky->resetSkyPosition();
|
||||
mReflectionCamera->disableReflection();
|
||||
mReflectionCamera->disableCustomNearClipPlane();
|
||||
mReflectionRenderActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Water::assignTextures()
|
||||
{
|
||||
if (Settings::Manager::getBool("shader", "Water"))
|
||||
@ -246,34 +362,16 @@ void Water::assignTextures()
|
||||
|
||||
void Water::setViewportBackground(const ColourValue& bg)
|
||||
{
|
||||
if (mReflectionTarget)
|
||||
mReflectionTarget->getViewport(0)->setBackgroundColour(bg);
|
||||
if (mReflection)
|
||||
mReflection->setViewportBackground(bg);
|
||||
}
|
||||
|
||||
void Water::updateVisible()
|
||||
{
|
||||
mWater->setVisible(mToggled && mActive);
|
||||
if (mReflectionTarget)
|
||||
mReflectionTarget->setActive(mToggled && mActive);
|
||||
}
|
||||
|
||||
void Water::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 && mReflectionRenderActive)
|
||||
if (mReflection)
|
||||
{
|
||||
mReflectionCamera->disableCustomNearClipPlane();
|
||||
Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mReflectionCamera->getProjectionMatrixRS());
|
||||
}
|
||||
}
|
||||
|
||||
void Water::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation)
|
||||
{
|
||||
if (queueGroupId < 20 && mReflectionRenderActive)
|
||||
{
|
||||
if (!mIsUnderwater)
|
||||
mReflectionCamera->enableCustomNearClipPlane(mErrorPlane);
|
||||
Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mReflectionCamera->getProjectionMatrixRS());
|
||||
mReflection->setActive(mToggled && mActive);
|
||||
}
|
||||
}
|
||||
|
||||
@ -293,10 +391,10 @@ void Water::update(float dt)
|
||||
|
||||
void Water::applyRTT()
|
||||
{
|
||||
if (mReflectionTarget)
|
||||
if (mReflection)
|
||||
{
|
||||
TextureManager::getSingleton().remove("WaterReflection");
|
||||
mReflectionTarget = 0;
|
||||
delete mReflection;
|
||||
mReflection = NULL;
|
||||
}
|
||||
|
||||
// Create rendertarget for reflection
|
||||
@ -304,23 +402,9 @@ void Water::applyRTT()
|
||||
|
||||
if (Settings::Manager::getBool("shader", "Water"))
|
||||
{
|
||||
mReflectionTexture = TextureManager::getSingleton().createManual("WaterReflection",
|
||||
ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, rttsize, rttsize, 0, PF_A8R8G8B8, TU_RENDERTARGET);
|
||||
|
||||
RenderTarget* rtt = mReflectionTexture->getBuffer()->getRenderTarget();
|
||||
Viewport* vp = rtt->addViewport(mReflectionCamera);
|
||||
vp->setOverlaysEnabled(false);
|
||||
vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f));
|
||||
vp->setShadowsEnabled(false);
|
||||
// use fallback techniques without shadows and without mrt
|
||||
vp->setMaterialScheme("water_reflection");
|
||||
rtt->addListener(this);
|
||||
rtt->setActive(true);
|
||||
|
||||
mReflectionTarget = rtt;
|
||||
|
||||
sh::Factory::getInstance ().setTextureAlias ("WaterReflection", mReflectionTexture->getName());
|
||||
|
||||
mReflection = new PlaneReflection(mSceneMgr, mSky);
|
||||
mReflection->setParentCamera (mCamera);
|
||||
mReflection->setWaterPlane(mWaterPlane);
|
||||
mWater->setRenderQueueGroup(RQG_Water);
|
||||
}
|
||||
else
|
||||
@ -336,10 +420,8 @@ void Water::applyVisibilityMask()
|
||||
+ RV_Misc * Settings::Manager::getBool("reflect misc", "Water")
|
||||
+ RV_Sky;
|
||||
|
||||
if (mReflectionTarget)
|
||||
{
|
||||
mReflectionTexture->getBuffer()->getRenderTarget()->getViewport(0)->setVisibilityMask(mVisibilityFlags);
|
||||
}
|
||||
if (mReflection)
|
||||
mReflection->setVisibilityMask(mVisibilityFlags);
|
||||
}
|
||||
|
||||
void Water::processChangedSettings(const Settings::CategorySettingVector& settings)
|
||||
|
@ -30,15 +30,73 @@ namespace MWRender {
|
||||
class SkyManager;
|
||||
class RenderingManager;
|
||||
|
||||
class Reflection
|
||||
{
|
||||
public:
|
||||
Reflection(Ogre::SceneManager* sceneManager)
|
||||
: mSceneMgr(sceneManager) {}
|
||||
|
||||
virtual void setWaterPlane (Ogre::Plane plane) {}
|
||||
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 setWaterPlane (Ogre::Plane plane);
|
||||
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;
|
||||
bool mRenderActive;
|
||||
};
|
||||
|
||||
/// Water rendering
|
||||
class Water : public Ogre::RenderTargetListener, public Ogre::RenderQueueListener, public sh::MaterialInstanceListener
|
||||
{
|
||||
static const int CELL_SIZE = 8192;
|
||||
Ogre::Camera *mCamera;
|
||||
Ogre::SceneManager *mSceneManager;
|
||||
Ogre::SceneManager *mSceneMgr;
|
||||
|
||||
Ogre::Plane mWaterPlane;
|
||||
Ogre::Plane mErrorPlane;
|
||||
|
||||
Ogre::SceneNode *mWaterNode;
|
||||
Ogre::Entity *mWater;
|
||||
@ -52,17 +110,9 @@ namespace MWRender {
|
||||
|
||||
float mWaterTimer;
|
||||
|
||||
bool mReflectionRenderActive;
|
||||
|
||||
Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY);
|
||||
|
||||
protected:
|
||||
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);
|
||||
|
||||
void applyRTT();
|
||||
void applyVisibilityMask();
|
||||
|
||||
@ -75,14 +125,11 @@ namespace MWRender {
|
||||
|
||||
Ogre::MaterialPtr mMaterial;
|
||||
|
||||
Ogre::Camera* mReflectionCamera;
|
||||
|
||||
Ogre::TexturePtr mReflectionTexture;
|
||||
Ogre::RenderTarget* mReflectionTarget;
|
||||
|
||||
bool mUnderwaterEffect;
|
||||
int mVisibilityFlags;
|
||||
|
||||
Reflection* mReflection;
|
||||
|
||||
public:
|
||||
Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cell);
|
||||
~Water();
|
||||
|
Loading…
x
Reference in New Issue
Block a user