diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index f8a39f40b..121b07654 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -82,41 +82,6 @@ namespace return waterGeom; } - void createSimpleWaterStateSet(Resource::ResourceSystem* resourceSystem, osg::ref_ptr node) - { - osg::ref_ptr stateset (new osg::StateSet); - - osg::ref_ptr 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); - - stateset->setMode(GL_BLEND, osg::StateAttribute::ON); - stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); - - osg::ref_ptr depth (new osg::Depth); - depth->setWriteMask(false); - stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); - - stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); - - std::vector > textures; - for (int i=0; i<32; ++i) - { - 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)); - } - - osg::ref_ptr controller (new NifOsg::FlipController(0, 2/32.f, textures)); - controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); - node->addUpdateCallback(controller); - node->setStateSet(stateset); - stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON); - } - } namespace MWRender @@ -419,6 +384,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem : mParent(parent) , mSceneRoot(sceneRoot) , mResourceSystem(resourceSystem) + , mResourcePath(resourcePath) , mEnabled(true) , mToggled(true) , mTop(0) @@ -427,19 +393,19 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem osg::ref_ptr waterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900); - osg::ref_ptr geode (new osg::Geode); - geode->addDrawable(waterGeom); - geode->setNodeMask(Mask_Water); + mWaterGeode = new osg::Geode; + mWaterGeode->addDrawable(waterGeom); + mWaterGeode->setNodeMask(Mask_Water); if (ico) - ico->add(geode); + ico->add(mWaterGeode); mWaterNode = new osg::PositionAttitudeTransform; - mWaterNode->addChild(geode); + mWaterNode->addChild(mWaterGeode); // simple water fallback for the local map - osg::ref_ptr geode2 (osg::clone(geode.get(), osg::CopyOp::DEEP_COPY_NODES)); - createSimpleWaterStateSet(mResourceSystem, geode2); + osg::ref_ptr geode2 (osg::clone(mWaterGeode.get(), osg::CopyOp::DEEP_COPY_NODES)); + createSimpleWaterStateSet(geode2); geode2->setNodeMask(Mask_SimpleWater); mWaterNode->addChild(geode2); @@ -453,31 +419,65 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem mRefraction = new Refraction(); mRefraction->setWaterLevel(waterLevel); mRefraction->setScene(mSceneRoot); - - // TODO: add ingame setting for texture quality - mParent->addChild(mRefraction); // reflection mReflection = new Reflection(); mReflection->setWaterLevel(waterLevel); mReflection->setScene(mSceneRoot); + mParent->addChild(mReflection); - // TODO: add to waterNode so cameras don't get updated when water is hidden? + createShaderWaterStateSet(mWaterGeode, mReflection, mRefraction); - mParent->addChild(mReflection); + // TODO: add ingame setting for texture quality +} - // shader +void Water::createSimpleWaterStateSet(osg::Node* node) +{ + osg::ref_ptr stateset (new osg::StateSet); - osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, resourcePath + "/shaders/water_vertex.glsl")); + osg::ref_ptr 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); - osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, resourcePath + "/shaders/water_fragment.glsl")); + stateset->setMode(GL_BLEND, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + + osg::ref_ptr depth (new osg::Depth); + depth->setWriteMask(false); + stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + + stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); + + std::vector > textures; + for (int i=0; i<32; ++i) + { + std::ostringstream texname; + texname << "textures/water/water" << std::setw(2) << std::setfill('0') << i << ".dds"; + textures.push_back(mResourceSystem->getTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT)); + } + + osg::ref_ptr controller (new NifOsg::FlipController(0, 2/32.f, textures)); + controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); + node->addUpdateCallback(controller); + node->setStateSet(stateset); + stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON); +} + +void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, Refraction* refraction) +{ + osg::ref_ptr vertexShader (readShader(osg::Shader::VERTEX, mResourcePath + "/shaders/water_vertex.glsl")); + + osg::ref_ptr fragmentShader (readShader(osg::Shader::FRAGMENT, mResourcePath + "/shaders/water_fragment.glsl")); osg::ref_ptr program (new osg::Program); program->addShader(vertexShader); program->addShader(fragmentShader); - osg::ref_ptr normalMap (new osg::Texture2D(readPngImage(resourcePath + "/shaders/water_nm.png"))); + osg::ref_ptr normalMap (new osg::Texture2D(readPngImage(mResourcePath + "/shaders/water_nm.png"))); normalMap->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT); normalMap->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT); normalMap->setMaxAnisotropy(16); @@ -487,26 +487,33 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem osg::ref_ptr shaderStateset = new osg::StateSet; shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); - shaderStateset->addUniform(new osg::Uniform("reflectionMap", 0)); - shaderStateset->addUniform(new osg::Uniform("refractionMap", 1)); - shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 2)); - shaderStateset->addUniform(new osg::Uniform("normalMap", 3)); - - shaderStateset->setTextureAttributeAndModes(0, mReflection->getReflectionTexture(), osg::StateAttribute::ON); - shaderStateset->setTextureAttributeAndModes(1, mRefraction->getRefractionTexture(), osg::StateAttribute::ON); - shaderStateset->setTextureAttributeAndModes(2, mRefraction->getRefractionDepthTexture(), osg::StateAttribute::ON); - shaderStateset->setTextureAttributeAndModes(3, normalMap, osg::StateAttribute::ON); - shaderStateset->setMode(GL_BLEND, osg::StateAttribute::ON); // TODO: set Off when refraction is on - shaderStateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + shaderStateset->addUniform(new osg::Uniform("normalMap", 0)); + shaderStateset->addUniform(new osg::Uniform("reflectionMap", 1)); + shaderStateset->addUniform(new osg::Uniform("refractionMap", 2)); + shaderStateset->addUniform(new osg::Uniform("refractionDepthMap", 3)); + + 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->setRenderBinDetails(MWRender::RenderBin_Default, "RenderBin"); + } + else + { + shaderStateset->setMode(GL_BLEND, osg::StateAttribute::ON); - osg::ref_ptr depth (new osg::Depth); - depth->setWriteMask(false); - shaderStateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + shaderStateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); - // TODO: render after transparent bin when refraction is on - shaderStateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); + osg::ref_ptr depth (new osg::Depth); + depth->setWriteMask(false); + shaderStateset->setAttributeAndModes(depth, osg::StateAttribute::ON); + } + + shaderStateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); - geode->setStateSet(shaderStateset); + node->setStateSet(shaderStateset); } Water::~Water() @@ -551,7 +558,12 @@ void Water::update(float dt) void Water::updateVisible() { - mWaterNode->setNodeMask(mEnabled && mToggled ? ~0 : 0); + unsigned int mask = mEnabled && mToggled ? ~0 : 0; + mWaterNode->setNodeMask(mask); + if (mRefraction) + mRefraction->setNodeMask(mask); + if (mReflection) + mReflection->setNodeMask(mask); } bool Water::toggle() diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 46b6382e7..857f7fbb0 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -9,6 +9,8 @@ namespace osg { class Group; class PositionAttitudeTransform; + class Geode; + class Node; } namespace osgUtil @@ -41,6 +43,7 @@ namespace MWRender osg::ref_ptr mParent; osg::ref_ptr mSceneRoot; osg::ref_ptr mWaterNode; + osg::ref_ptr mWaterGeode; Resource::ResourceSystem* mResourceSystem; osg::ref_ptr mIncrementalCompileOperation; @@ -49,6 +52,8 @@ namespace MWRender osg::ref_ptr mRefraction; osg::ref_ptr mReflection; + const std::string mResourcePath; + bool mEnabled; bool mToggled; float mTop; @@ -56,6 +61,12 @@ namespace MWRender osg::Vec3f getSceneNodeCoordinates(int gridX, int gridY); void updateVisible(); + void createSimpleWaterStateSet(osg::Node* node); + + /// @param reflection the reflection camera (required) + /// @param refraction the refraction camera (optional) + void createShaderWaterStateSet(osg::Node* node, Reflection* reflection, Refraction* refraction); + public: Water(osg::Group* parent, osg::Group* sceneRoot, Resource::ResourceSystem* resourceSystem, osgUtil::IncrementalCompileOperation* ico, const MWWorld::Fallback* fallback, diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index c11c18a2d..6f7b173bf 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -60,13 +60,13 @@ varying vec3 screenCoordsPassthrough; varying vec4 position; varying float depthPassthrough; +uniform sampler2D normalMap; + uniform sampler2D reflectionMap; #if REFRACTION uniform sampler2D refractionMap; uniform sampler2D refractionDepthMap; #endif - -uniform sampler2D normalMap; uniform float osg_SimulationTime;