You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw-tes3mp/apps/openmw/mwrender/refraction.cpp

111 lines
4.4 KiB
C++

#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);
}
}