1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-16 20:19:57 +00:00

Merge branch 'next' into tooltips

This commit is contained in:
scrawl 2012-04-29 17:30:34 +02:00
commit 50d79a8815
18 changed files with 269 additions and 91 deletions

View file

@ -140,8 +140,7 @@ namespace MWClass
case ESM::Armor::Boots: typeGmst = "iBootsWeight"; break; case ESM::Armor::Boots: typeGmst = "iBootsWeight"; break;
case ESM::Armor::LGauntlet: case ESM::Armor::LGauntlet:
case ESM::Armor::RGauntlet: typeGmst = "iGauntletWeight"; break; case ESM::Armor::RGauntlet: typeGmst = "iGauntletWeight"; break;
/// \todo how to determine if shield light, medium or heavy? case ESM::Armor::Shield: typeGmst = "iShieldWeight"; break;
// case ESM::Armor::Shield:
case ESM::Armor::LBracer: case ESM::Armor::LBracer:
case ESM::Armor::RBracer: typeGmst = "iGauntletWeight"; break; case ESM::Armor::RBracer: typeGmst = "iGauntletWeight"; break;
} }

View file

@ -299,7 +299,6 @@ namespace MWClass
void Npc::registerSelf() void Npc::registerSelf()
{ {
boost::shared_ptr<Class> instance (new Npc); boost::shared_ptr<Class> instance (new Npc);
std::cout << "class npc:" << typeid (ESM::NPC).name();
registerClass (typeid (ESM::NPC).name(), instance); registerClass (typeid (ESM::NPC).name(), instance);
} }

View file

@ -8,20 +8,15 @@
using namespace MWRender; using namespace MWRender;
bool Objects::lightConst = false; // These are the Morrowind.ini defaults
float Objects::lightConstValue = 0.0f;
bool Objects::lightLinear = true;
int Objects::lightLinearMethod = 1;
float Objects::lightLinearValue = 3; float Objects::lightLinearValue = 3;
float Objects::lightLinearRadiusMult = 1; float Objects::lightLinearRadiusMult = 1;
bool Objects::lightQuadratic = false;
int Objects::lightQuadraticMethod = 2;
float Objects::lightQuadraticValue = 16; float Objects::lightQuadraticValue = 16;
float Objects::lightQuadraticRadiusMult = 1; float Objects::lightQuadraticRadiusMult = 1;
bool Objects::lightOutQuadInLin = false; bool Objects::lightOutQuadInLin = true;
bool Objects::lightQuadratic = false;
int Objects::uniqueID = 0; int Objects::uniqueID = 0;
@ -132,7 +127,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
} }
} }
if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects")) if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || transparent)
{ {
insert->attachObject(ent); insert->attachObject(ent);
@ -144,18 +139,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh)
{ {
Ogre::StaticGeometry* sg = 0; Ogre::StaticGeometry* sg = 0;
/* if (transparent) if (small)
{
if( mStaticGeometryAlpha.find(ptr.getCell()) == mStaticGeometryAlpha.end())
{
uniqueID = uniqueID +1;
sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID));
mStaticGeometryAlpha[ptr.getCell()] = sg;
}
else
sg = mStaticGeometryAlpha[ptr.getCell()];
}
else*/ if (small)
{ {
if( mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end()) if( mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end())
{ {
@ -207,35 +191,61 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f
assert(insert); assert(insert);
Ogre::Light *light = mRenderer.getScene()->createLight(); Ogre::Light *light = mRenderer.getScene()->createLight();
light->setDiffuseColour (r, g, b); light->setDiffuseColour (r, g, b);
mLights.push_back(light->getName());
float cval=0.0f, lval=0.0f, qval=0.0f; ESMS::LiveCellRef<ESM::Light, MWWorld::RefData> *ref =
ptr.get<ESM::Light>();
if(lightConst) LightInfo info;
cval = lightConstValue; info.name = light->getName();
info.radius = radius;
info.colour = Ogre::ColourValue(r, g, b);
if(!lightOutQuadInLin) if (ref->base->data.flags & ESM::Light::Negative)
info.colour *= -1;
info.interior = (ptr.getCell()->cell->data.flags & ESM::Cell::Interior);
if (ref->base->data.flags & ESM::Light::Flicker)
info.type = LT_Flicker;
else if (ref->base->data.flags & ESM::Light::FlickerSlow)
info.type = LT_FlickerSlow;
else if (ref->base->data.flags & ESM::Light::Pulse)
info.type = LT_Pulse;
else if (ref->base->data.flags & ESM::Light::PulseSlow)
info.type = LT_PulseSlow;
else
info.type = LT_Normal;
// random starting phase for the animation
info.time = Ogre::Math::RangeRandom(0, 2 * M_PI);
// adjust the lights depending if we're in an interior or exterior cell
// quadratic means the light intensity falls off quite fast, resulting in a
// dark, atmospheric environment (perfect for exteriors)
// for interiors, we want more "warm" lights, so use linear attenuation.
bool quadratic = false;
if (!lightOutQuadInLin)
quadratic = lightQuadratic;
else
{ {
if(lightLinear) quadratic = !info.interior;
radius *= lightLinearRadiusMult; }
if(lightQuadratic)
radius *= lightQuadraticRadiusMult;
if(lightLinear) if (!quadratic)
lval = lightLinearValue / pow(radius, lightLinearMethod); {
if(lightQuadratic) float r = radius * lightLinearRadiusMult;
qval = lightQuadraticValue / pow(radius, lightQuadraticMethod); float attenuation = lightLinearValue / r;
light->setAttenuation(r*10, 0, attenuation, 0);
} }
else else
{ {
// FIXME: float r = radius * lightQuadraticRadiusMult;
// Do quadratic or linear, depending if we're in an exterior or interior float attenuation = lightQuadraticValue / pow(r, 2);
// cell, respectively. Ignore lightLinear and lightQuadratic. light->setAttenuation(r*10, 0, 0, attenuation);
} }
light->setAttenuation(10*radius, cval, lval, qval);
insert->attachObject(light); insert->attachObject(light);
mLights.push_back(info);
} }
bool Objects::deleteObject (const MWWorld::Ptr& ptr) bool Objects::deleteObject (const MWWorld::Ptr& ptr)
@ -290,13 +300,6 @@ void Objects::removeCell(MWWorld::Ptr::CellStore* store)
mRenderer.getScene()->destroyStaticGeometry (sg); mRenderer.getScene()->destroyStaticGeometry (sg);
sg = 0; sg = 0;
} }
/*if(mStaticGeometryAlpha.find(store) != mStaticGeometryAlpha.end())
{
Ogre::StaticGeometry* sg = mStaticGeometryAlpha[store];
mStaticGeometryAlpha.erase(store);
mRenderer.getScene()->destroyStaticGeometry (sg);
sg = 0;
}*/
if(mBounds.find(store) != mBounds.end()) if(mBounds.find(store) != mBounds.end())
mBounds.erase(store); mBounds.erase(store);
@ -314,11 +317,6 @@ void Objects::buildStaticGeometry(ESMS::CellStore<MWWorld::RefData>& cell)
Ogre::StaticGeometry* sg = mStaticGeometrySmall[&cell]; Ogre::StaticGeometry* sg = mStaticGeometrySmall[&cell];
sg->build(); sg->build();
} }
/*if(mStaticGeometryAlpha.find(&cell) != mStaticGeometryAlpha.end())
{
Ogre::StaticGeometry* sg = mStaticGeometryAlpha[&cell];
sg->build();
}*/
} }
Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell) Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell)
@ -328,12 +326,12 @@ Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell)
void Objects::enableLights() void Objects::enableLights()
{ {
std::vector<std::string>::iterator it = mLights.begin(); std::vector<LightInfo>::iterator it = mLights.begin();
while (it != mLights.end()) while (it != mLights.end())
{ {
if (mMwRoot->getCreator()->hasLight(*it)) if (mMwRoot->getCreator()->hasLight(it->name))
{ {
mMwRoot->getCreator()->getLight(*it)->setVisible(true); mMwRoot->getCreator()->getLight(it->name)->setVisible(true);
++it; ++it;
} }
else else
@ -343,12 +341,12 @@ void Objects::enableLights()
void Objects::disableLights() void Objects::disableLights()
{ {
std::vector<std::string>::iterator it = mLights.begin(); std::vector<LightInfo>::iterator it = mLights.begin();
while (it != mLights.end()) while (it != mLights.end())
{ {
if (mMwRoot->getCreator()->hasLight(*it)) if (mMwRoot->getCreator()->hasLight(it->name))
{ {
mMwRoot->getCreator()->getLight(*it)->setVisible(false); mMwRoot->getCreator()->getLight(it->name)->setVisible(false);
++it; ++it;
} }
else else
@ -356,3 +354,90 @@ void Objects::disableLights()
} }
} }
void Objects::update(const float dt)
{
std::vector<LightInfo>::iterator it = mLights.begin();
while (it != mLights.end())
{
if (mMwRoot->getCreator()->hasLight(it->name))
{
Ogre::Light* light = mMwRoot->getCreator()->getLight(it->name);
// Light animation (pulse & flicker)
it->time += dt;
const float phase = std::fmod(static_cast<double> (it->time), (32 * 2 * M_PI)) * 20;
float pulseConstant;
// These formulas are just guesswork, but they work pretty well
if (it->type == LT_Normal)
{
// Less than 1/255 light modifier for a constant light:
pulseConstant = (const float)(1.0 + sin(phase) / 255.0 );
}
else if (it->type == LT_Flicker)
{
// Let's do a 50% -> 100% sine wave pulse over 1 second:
// This is 75% +/- 25%
pulseConstant = (const float)(0.75 + sin(phase) * 0.25);
// Then add a 25% flicker variation:
it->resetTime -= dt;
if (it->resetTime < 0)
{
it->flickerVariation = (rand() % 1000) / 1000 * 0.25;
it->resetTime = 0.5;
}
if (it->resetTime > 0.25)
{
pulseConstant = (pulseConstant+it->flickerVariation) * (1-it->resetTime * 2.0f) + pulseConstant * it->resetTime * 2.0f;
}
else
{
pulseConstant = (pulseConstant+it->flickerVariation) * (it->resetTime * 2.0f) + pulseConstant * (1-it->resetTime * 2.0f);
}
}
else if (it->type == LT_FlickerSlow)
{
// Let's do a 50% -> 100% sine wave pulse over 1 second:
// This is 75% +/- 25%
pulseConstant = (const float)(0.75 + sin(phase / 4.0) * 0.25);
// Then add a 25% flicker variation:
it->resetTime -= dt;
if (it->resetTime < 0)
{
it->flickerVariation = (rand() % 1000) / 1000 * 0.25;
it->resetTime = 0.5;
}
if (it->resetTime > 0.5)
{
pulseConstant = (pulseConstant+it->flickerVariation) * (1-it->resetTime) + pulseConstant * it->resetTime;
}
else
{
pulseConstant = (pulseConstant+it->flickerVariation) * (it->resetTime) + pulseConstant * (1-it->resetTime);
}
}
else if (it->type == LT_Pulse)
{
// Let's do a 75% -> 125% sine wave pulse over 1 second:
// This is 100% +/- 25%
pulseConstant = (const float)(1.0 + sin(phase) * 0.25);
}
else if (it->type == LT_PulseSlow)
{
// Let's do a 75% -> 125% sine wave pulse over 1 second:
// This is 100% +/- 25%
pulseConstant = (const float)(1.0 + sin(phase / 4.0) * 0.25);
}
else
assert(0 && "Invalid light type");
light->setDiffuseColour( it->colour * pulseConstant );
++it;
}
else
it = mLights.erase(it);
}
}

View file

@ -10,27 +10,55 @@
namespace MWRender{ namespace MWRender{
/// information about light needed for rendering
enum LightType
{
// These are all mutually exclusive
LT_Normal=0,
LT_Flicker=1,
LT_FlickerSlow=2,
LT_Pulse=3,
LT_PulseSlow=4
};
struct LightInfo
{
// Constants
std::string name; // ogre handle
Ogre::ColourValue colour;
float radius;
bool interior; // Does this light belong to an interior or exterior cell
LightType type;
// Runtime variables
float flickerVariation; // 25% flicker variation, reset once every 0.5 seconds
float flickerSlowVariation; // 25% flicker variation, reset once every 1.0 seconds
float resetTime;
long double time;
LightInfo() :
flickerVariation(0), resetTime(0.5),
flickerSlowVariation(0), time(0), interior(true)
{
}
};
class Objects{ class Objects{
OEngine::Render::OgreRenderer &mRenderer; OEngine::Render::OgreRenderer &mRenderer;
std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *> mCellSceneNodes; std::map<MWWorld::Ptr::CellStore *, Ogre::SceneNode *> mCellSceneNodes;
std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometry; std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometry;
std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometrySmall; std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometrySmall;
//std::map<MWWorld::Ptr::CellStore *, Ogre::StaticGeometry*> mStaticGeometryAlpha;
std::map<MWWorld::Ptr::CellStore *, Ogre::AxisAlignedBox> mBounds; std::map<MWWorld::Ptr::CellStore *, Ogre::AxisAlignedBox> mBounds;
std::vector<std::string> mLights; std::vector<LightInfo> mLights;
Ogre::SceneNode* mMwRoot; Ogre::SceneNode* mMwRoot;
bool mIsStatic; bool mIsStatic;
static int uniqueID; static int uniqueID;
static bool lightConst;
static float lightConstValue;
static bool lightLinear;
static int lightLinearMethod;
static float lightLinearValue; static float lightLinearValue;
static float lightLinearRadiusMult; static float lightLinearRadiusMult;
static bool lightQuadratic; static bool lightQuadratic;
static int lightQuadraticMethod;
static float lightQuadraticValue; static float lightQuadraticValue;
static float lightQuadraticRadiusMult; static float lightQuadraticRadiusMult;
@ -40,7 +68,7 @@ class Objects{
///< Remove all movable objects from \a node. ///< Remove all movable objects from \a node.
public: public:
Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer){} Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer) {}
~Objects(){} ~Objects(){}
void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_);
void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh); void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh);
@ -49,6 +77,9 @@ public:
void enableLights(); void enableLights();
void disableLights(); void disableLights();
void update (const float dt);
///< per-frame update
Ogre::AxisAlignedBox getDimensions(MWWorld::Ptr::CellStore*); Ogre::AxisAlignedBox getDimensions(MWWorld::Ptr::CellStore*);
///< get a bounding box that encloses all objects in the specified cell ///< get a bounding box that encloses all objects in the specified cell

View file

@ -65,6 +65,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod
mBBQueryTotal->createBillboard(Vector3::ZERO); mBBQueryTotal->createBillboard(Vector3::ZERO);
mBBQueryTotal->setMaterialName("QueryTotalPixels"); mBBQueryTotal->setMaterialName("QueryTotalPixels");
mBBQueryTotal->setRenderQueueGroup(RQG_OcclusionQuery+1); mBBQueryTotal->setRenderQueueGroup(RQG_OcclusionQuery+1);
mBBQueryTotal->setVisibilityFlags(RV_OcclusionQuery);
mBBNodeReal->attachObject(mBBQueryTotal); mBBNodeReal->attachObject(mBBQueryTotal);
mBBQueryVisible = mRendering->getScene()->createBillboardSet(1); mBBQueryVisible = mRendering->getScene()->createBillboardSet(1);
@ -73,6 +74,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod
mBBQueryVisible->createBillboard(Vector3::ZERO); mBBQueryVisible->createBillboard(Vector3::ZERO);
mBBQueryVisible->setMaterialName("QueryVisiblePixels"); mBBQueryVisible->setMaterialName("QueryVisiblePixels");
mBBQueryVisible->setRenderQueueGroup(RQG_OcclusionQuery+1); mBBQueryVisible->setRenderQueueGroup(RQG_OcclusionQuery+1);
mBBQueryVisible->setVisibilityFlags(RV_OcclusionQuery);
mBBNodeReal->attachObject(mBBQueryVisible); mBBNodeReal->attachObject(mBBQueryVisible);
mBBQuerySingleObject = mRendering->getScene()->createBillboardSet(1); mBBQuerySingleObject = mRendering->getScene()->createBillboardSet(1);
@ -82,6 +84,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod
mBBQuerySingleObject->createBillboard(Vector3::ZERO); mBBQuerySingleObject->createBillboard(Vector3::ZERO);
mBBQuerySingleObject->setMaterialName("QueryVisiblePixels"); mBBQuerySingleObject->setMaterialName("QueryVisiblePixels");
mBBQuerySingleObject->setRenderQueueGroup(RQG_OcclusionQuery); mBBQuerySingleObject->setRenderQueueGroup(RQG_OcclusionQuery);
mBBQuerySingleObject->setVisibilityFlags(RV_OcclusionQuery);
mObjectNode->attachObject(mBBQuerySingleObject); mObjectNode->attachObject(mBBQuerySingleObject);
mRendering->getScene()->addRenderObjectListener(this); mRendering->getScene()->addRenderObjectListener(this);

View file

@ -52,6 +52,8 @@ enum VisibilityFlags
// Sun glare (not visible in reflection) // Sun glare (not visible in reflection)
RV_Glare = 128, RV_Glare = 128,
RV_OcclusionQuery = 256,
RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water, RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water,
/// \todo markers (normally hidden) /// \todo markers (normally hidden)

View file

@ -52,11 +52,16 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const
// Load resources // Load resources
ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); ResourceGroupManager::getSingleton().initialiseAllResourceGroups();
// Due to the huge world size of MW, we'll want camera-relative rendering.
// This prevents precision artifacts when moving very far from the origin.
mRendering.getScene()->setCameraRelativeRendering(true);
// disable unsupported effects // disable unsupported effects
const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities();
if (caps->getNumMultiRenderTargets() < 2) if (caps->getNumMultiRenderTargets() < 2 || !Settings::Manager::getBool("shaders", "Objects"))
Settings::Manager::setBool("shader", "Water", false); Settings::Manager::setBool("shader", "Water", false);
if (!caps->isShaderProfileSupported("fp40") && !caps->isShaderProfileSupported("ps_4_0")) if ( !(caps->isShaderProfileSupported("fp40") || caps->isShaderProfileSupported("ps_4_0"))
|| !Settings::Manager::getBool("shaders", "Objects"))
Settings::Manager::setBool("enabled", "Shadows", false); Settings::Manager::setBool("enabled", "Shadows", false);
// note that the order is important here // note that the order is important here
@ -207,6 +212,7 @@ void RenderingManager::moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Ve
void RenderingManager::update (float duration){ void RenderingManager::update (float duration){
mActors.update (duration); mActors.update (duration);
mObjects.update (duration);
mOcclusionQuery->update(duration); mOcclusionQuery->update(duration);
@ -219,6 +225,8 @@ void RenderingManager::update (float duration){
mLocalMap->updatePlayer( mRendering.getCamera()->getRealPosition(), mRendering.getCamera()->getRealOrientation() ); mLocalMap->updatePlayer( mRendering.getCamera()->getRealPosition(), mRendering.getCamera()->getRealOrientation() );
checkUnderwater(); checkUnderwater();
mWater->update();
} }
void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){ void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){
if(store->cell->data.flags & store->cell->HasWater){ if(store->cell->data.flags & store->cell->HasWater){
@ -500,4 +508,14 @@ Shadows* RenderingManager::getShadows()
return mShadows; return mShadows;
} }
void RenderingManager::switchToInterior()
{
mRendering.getScene()->setCameraRelativeRendering(false);
}
void RenderingManager::switchToExterior()
{
mRendering.getScene()->setCameraRelativeRendering(true);
}
} // namespace } // namespace

View file

@ -117,6 +117,9 @@ class RenderingManager: private RenderingInterface {
Shadows* getShadows(); Shadows* getShadows();
void switchToInterior();
void switchToExterior();
void setGlare(bool glare); void setGlare(bool glare);
void skyEnable (); void skyEnable ();
void skyDisable (); void skyDisable ();

View file

@ -256,9 +256,9 @@ void ShaderHelper::createShader(const bool mrt, const bool shadows, const bool s
} }
outStream << outStream <<
" float3 lightingFinal = lightColour.xyz * diffuse.xyz * vertexColour.xyz + ambient.xyz * lightAmbient.xyz + emissive.xyz; \n" " float3 lightingFinal = lightColour.xyz * diffuse.xyz + ambient.xyz * lightAmbient.xyz + emissive.xyz; \n"
" float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); \n" " float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); \n"
" oColor.xyz = lerp(lightingFinal * tex.xyz, fogColour.xyz, fogValue); \n" " oColor.xyz = lerp(lightingFinal * tex.xyz * vertexColour.xyz, fogColour.xyz, fogValue); \n"
" oColor.a = tex.a * diffuse.a * vertexColour.a; \n"; " oColor.a = tex.a * diffuse.a * vertexColour.a; \n";
if (mrt) outStream << if (mrt) outStream <<

View file

@ -1149,8 +1149,8 @@ namespace Ogre
// simple per-pixel lighting with no normal mapping // simple per-pixel lighting with no normal mapping
for (int i=0; i<prof->getNumberOfLightsSupported(); ++i) for (int i=0; i<prof->getNumberOfLightsSupported(); ++i)
{ {
outStream << " float3 halfAngle"<<i<<" = normalize(lightDir"<<i<<" + eyeDir);\n" outStream <<
" float4 litRes"<<i<<" = lit(dot(normalize(lightDir"<<i<<"), normal), dot(halfAngle"<<i<<", normal), scaleBiasSpecular.z);\n"; " float4 litRes"<<i<<" = lit(dot(normalize(lightDir"<<i<<"), normalize(normal)), 0, scaleBiasSpecular.z);\n";
if (i > 0) if (i > 0)
outStream << outStream <<

View file

@ -11,7 +11,8 @@ namespace MWRender
Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) :
mCamera (camera), mViewport (camera->getViewport()), mSceneManager (camera->getSceneManager()), mCamera (camera), mViewport (camera->getViewport()), mSceneManager (camera->getSceneManager()),
mIsUnderwater(false), mVisibilityFlags(0), mIsUnderwater(false), mVisibilityFlags(0),
mReflectionTarget(0), mActive(1), mToggled(1) mReflectionTarget(0), mActive(1), mToggled(1),
mReflectionRenderActive(false)
{ {
mSky = sky; mSky = sky;
@ -81,6 +82,8 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) :
mUnderwaterEffect = Settings::Manager::getBool("underwater effect", "Water"); mUnderwaterEffect = Settings::Manager::getBool("underwater effect", "Water");
mSceneManager->addRenderQueueListener(this);
// ---------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------
// ---------------------------------- reflection debug overlay ---------------------------------- // ---------------------------------- reflection debug overlay ----------------------------------
@ -161,6 +164,7 @@ void Water::changeCell(const ESM::Cell* cell)
void Water::setHeight(const float height) void Water::setHeight(const float height)
{ {
mTop = height; mTop = height;
mWaterPlane = Plane(Vector3::UNIT_Y, height);
mWaterNode->setPosition(0, height, 0); mWaterNode->setPosition(0, height, 0);
} }
@ -172,7 +176,12 @@ void Water::toggle()
void Water::checkUnderwater(float y) void Water::checkUnderwater(float y)
{ {
if (!mActive) return; if (!mActive)
{
CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, false);
return;
}
if ((mIsUnderwater && y > mTop) || !mWater->isVisible() || mCamera->getPolygonMode() != Ogre::PM_SOLID) if ((mIsUnderwater && y > mTop) || !mWater->isVisible() || mCamera->getPolygonMode() != Ogre::PM_SOLID)
{ {
CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, false); CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, false);
@ -220,17 +229,15 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt)
mReflectionCamera->setFarClipDistance(mCamera->getFarClipDistance()); mReflectionCamera->setFarClipDistance(mCamera->getFarClipDistance());
mReflectionCamera->setAspectRatio(mCamera->getAspectRatio()); mReflectionCamera->setAspectRatio(mCamera->getAspectRatio());
mReflectionCamera->setFOVy(mCamera->getFOVy()); mReflectionCamera->setFOVy(mCamera->getFOVy());
mReflectionRenderActive = true;
// Some messy code to get the skybox to show up at all /// \todo For some reason this camera is delayed for 1 frame, which causes ugly sky reflection behaviour..
// The problem here is that it gets clipped by the water plane /// to circumvent this we just scale the sky up, so it's not that noticable
// Therefore scale it up a bit
Vector3 pos = mCamera->getRealPosition(); Vector3 pos = mCamera->getRealPosition();
pos.y = mTop*2 - pos.y; pos.y = mTop*2 - pos.y;
mSky->setSkyPosition(pos); mSky->setSkyPosition(pos);
mSky->scaleSky(mCamera->getFarClipDistance() / 1000.f); mSky->scaleSky(mCamera->getFarClipDistance() / 5000.f);
mReflectionCamera->enableReflection(mWaterPlane);
mReflectionCamera->enableCustomNearClipPlane(Plane(Vector3::UNIT_Y, mTop));
mReflectionCamera->enableReflection(Plane(Vector3::UNIT_Y, mTop));
} }
} }
@ -240,8 +247,9 @@ void Water::postRenderTargetUpdate(const RenderTargetEvent& evt)
{ {
mSky->resetSkyPosition(); mSky->resetSkyPosition();
mSky->scaleSky(1); mSky->scaleSky(1);
mReflectionCamera->disableCustomNearClipPlane();
mReflectionCamera->disableReflection(); mReflectionCamera->disableReflection();
mReflectionCamera->disableCustomNearClipPlane();
mReflectionRenderActive = false;
} }
} }
@ -290,4 +298,27 @@ void Water::updateVisible()
mReflectionTarget->setActive(mToggled && mActive && !mIsUnderwater); mReflectionTarget->setActive(mToggled && mActive && !mIsUnderwater);
} }
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)
{
mReflectionCamera->disableCustomNearClipPlane();
Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mReflectionCamera->getProjectionMatrixRS());
}
}
void Water::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation)
{
if (queueGroupId < 20 && mReflectionRenderActive)
{
mReflectionCamera->enableCustomNearClipPlane(mWaterPlane);
Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mReflectionCamera->getProjectionMatrixRS());
}
}
void Water::update()
{
}
} // namespace } // namespace

View file

@ -11,7 +11,7 @@ namespace MWRender {
class SkyManager; class SkyManager;
/// Water rendering /// Water rendering
class Water : public Ogre::RenderTargetListener class Water : public Ogre::RenderTargetListener, public Ogre::RenderQueueListener
{ {
static const int CELL_SIZE = 8192; static const int CELL_SIZE = 8192;
Ogre::Camera *mCamera; Ogre::Camera *mCamera;
@ -27,11 +27,17 @@ namespace MWRender {
bool mToggled; bool mToggled;
int mTop; int mTop;
bool mReflectionRenderActive;
Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY); Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY);
protected: protected:
void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt);
void postRenderTargetUpdate(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 updateVisible(); void updateVisible();
SkyManager* mSky; SkyManager* mSky;
@ -55,6 +61,7 @@ namespace MWRender {
void setActive(bool active); void setActive(bool active);
void toggle(); void toggle();
void update();
void setViewportBackground(const Ogre::ColourValue& bg); void setViewportBackground(const Ogre::ColourValue& bg);

View file

@ -24,8 +24,6 @@ namespace MWWorld
float* playerPos = mPlayer.mData.getPosition().pos; float* playerPos = mPlayer.mData.getPosition().pos;
playerPos[0] = playerPos[1] = playerPos[2] = 0; playerPos[0] = playerPos[1] = playerPos[2] = 0;
std::cout << renderer->getHandle();
mPlayer.mData.setBaseNode(renderer->getNode()); mPlayer.mData.setBaseNode(renderer->getNode());
/// \todo Do not make a copy of classes defined in esm/p records. /// \todo Do not make a copy of classes defined in esm/p records.
mClass = new ESM::Class (*world.getStore().classes.find (player->cls)); mClass = new ESM::Class (*world.getStore().classes.find (player->cls));

View file

@ -203,6 +203,8 @@ namespace MWWorld
// Sky system // Sky system
mWorld->adjustSky(); mWorld->adjustSky();
mRendering.switchToExterior();
mCellChanged = true; mCellChanged = true;
} }
@ -250,6 +252,7 @@ namespace MWWorld
playerCellChange (cell, position); playerCellChange (cell, position);
// adjust fog // adjust fog
mRendering.switchToInterior();
mRendering.configureFog(*cell); mRendering.configureFog(*cell);
// Sky system // Sky system

View file

@ -522,7 +522,6 @@ void WeatherManager::update(float duration)
// re-scale to 100 percent // re-scale to 100 percent
const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight;//+snow+blizzard; const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight;//+snow+blizzard;
srand(time(NULL));
float random = ((rand()%100)/100.f) * total; float random = ((rand()%100)/100.f) * total;
//if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) //if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear)

View file

@ -17,7 +17,7 @@ struct Light
{ {
Dynamic = 0x001, Dynamic = 0x001,
Carry = 0x002, // Can be carried Carry = 0x002, // Can be carried
Negative = 0x004, // Negative light? Negative = 0x004, // Negative light - i.e. darkness
Flicker = 0x008, Flicker = 0x008,
Fire = 0x010, Fire = 0x010,
OffDefault = 0x020, // Off by default OffDefault = 0x020, // Off by default

View file

@ -86,6 +86,7 @@ num lights = 8
[Water] [Water]
# Enable this to get fancy-looking water with reflections and refractions # Enable this to get fancy-looking water with reflections and refractions
# Only available if object shaders are on
# All the settings below have no effect if this is false # All the settings below have no effect if this is false
shader = true shader = true

View file

@ -54,7 +54,7 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest
TEX_TYPE_2D, TEX_TYPE_2D,
width, height, width, height,
0, 0,
PF_A8R8G8B8, PF_FLOAT16_RGBA,
TU_RENDERTARGET); TU_RENDERTARGET);
RenderTarget* rtt = destTexture->getBuffer()->getRenderTarget(); RenderTarget* rtt = destTexture->getBuffer()->getRenderTarget();
@ -63,7 +63,6 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest
vp->setOverlaysEnabled(false); vp->setOverlaysEnabled(false);
vp->setShadowsEnabled(false); vp->setShadowsEnabled(false);
vp->setBackgroundColour(ColourValue(0,0,0,0)); vp->setBackgroundColour(ColourValue(0,0,0,0));
vp->setClearEveryFrame(true, FBT_DEPTH);
rtt->update(); rtt->update();