mirror of
				https://github.com/TES3MP/openmw-tes3mp.git
				synced 2025-10-31 19:56:42 +00:00 
			
		
		
		
	initial commit
This commit is contained in:
		
							parent
							
								
									2b144ff3dd
								
							
						
					
					
						commit
						dda735c54a
					
				
					 23 changed files with 710 additions and 178 deletions
				
			
		|  | @ -72,7 +72,6 @@ RenderWidget::RenderWidget(QWidget *parent, Qt::WindowFlags f) | |||
|     mView->getCamera()->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) ); | ||||
| 
 | ||||
|     SceneUtil::LightManager* lightMgr = new SceneUtil::LightManager; | ||||
|     lightMgr->setStartLight(1); | ||||
|     lightMgr->setLightingMask(Mask_Lighting); | ||||
|     mRootNode = lightMgr; | ||||
| 
 | ||||
|  |  | |||
|  | @ -31,6 +31,7 @@ | |||
| #include <components/compiler/extensions0.hpp> | ||||
| 
 | ||||
| #include <components/sceneutil/workqueue.hpp> | ||||
| #include <components/sceneutil/lightmanager.hpp> | ||||
| 
 | ||||
| #include <components/files/configurationmanager.hpp> | ||||
| 
 | ||||
|  |  | |||
|  | @ -152,7 +152,7 @@ namespace MWRender | |||
| 
 | ||||
|         mCamera->setNodeMask(Mask_RenderToTexture); | ||||
| 
 | ||||
|         osg::ref_ptr<SceneUtil::LightManager> lightManager = new SceneUtil::LightManager; | ||||
|         osg::ref_ptr<SceneUtil::LightManager> lightManager = new SceneUtil::LightManager(mResourceSystem->getSceneManager()->getFFPLighting()); | ||||
|         lightManager->setStartLight(1); | ||||
|         osg::ref_ptr<osg::StateSet> stateset = lightManager->getOrCreateStateSet(); | ||||
|         stateset->setMode(GL_LIGHTING, osg::StateAttribute::ON); | ||||
|  | @ -215,6 +215,7 @@ namespace MWRender | |||
|         light->setConstantAttenuation(1.f); | ||||
|         light->setLinearAttenuation(0.f); | ||||
|         light->setQuadraticAttenuation(0.f); | ||||
|         lightManager->setSunlight(light); | ||||
| 
 | ||||
|         osg::ref_ptr<osg::LightSource> lightSource = new osg::LightSource; | ||||
|         lightSource->setLight(light); | ||||
|  |  | |||
|  | @ -18,7 +18,10 @@ | |||
| #include <components/settings/settings.hpp> | ||||
| #include <components/sceneutil/visitor.hpp> | ||||
| #include <components/sceneutil/shadow.hpp> | ||||
| #include <components/sceneutil/lightmanager.hpp> | ||||
| #include <components/files/memorystream.hpp> | ||||
| #include <components/resource/scenemanager.hpp> | ||||
| #include <components/resource/resourcesystem.hpp> | ||||
| 
 | ||||
| #include "../mwbase/environment.hpp" | ||||
| #include "../mwbase/world.hpp" | ||||
|  | @ -219,6 +222,14 @@ osg::ref_ptr<osg::Camera> LocalMap::createOrthographicCamera(float x, float y, f | |||
| 
 | ||||
|     SceneUtil::ShadowManager::disableShadowsForStateSet(stateset); | ||||
| 
 | ||||
|     // override sun for local map 
 | ||||
|     if (!MWBase::Environment::get().getResourceSystem()->getSceneManager()->getFFPLighting()) | ||||
|     { | ||||
|         osg::ref_ptr<SceneUtil::SunlightStateAttribute> sun = new SceneUtil::SunlightStateAttribute; | ||||
|         sun->setFromLight(light); | ||||
|         sun->setStateSet(stateset, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); | ||||
|     } | ||||
| 
 | ||||
|     camera->addChild(lightSource); | ||||
|     camera->setStateSet(stateset); | ||||
|     camera->setViewport(0, 0, mMapResolution, mMapResolution); | ||||
|  |  | |||
|  | @ -203,17 +203,19 @@ namespace MWRender | |||
|         resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders"); | ||||
|         // Shadows and radial fog have problems with fixed-function mode
 | ||||
|         bool forceShaders = Settings::Manager::getBool("radial fog", "Shaders") || Settings::Manager::getBool("force shaders", "Shaders") || Settings::Manager::getBool("enable shadows", "Shadows"); | ||||
|         bool clampLighting = Settings::Manager::getBool("clamp lighting", "Shaders"); | ||||
|         resourceSystem->getSceneManager()->setForceShaders(forceShaders); | ||||
|         // FIXME: calling dummy method because terrain needs to know whether lighting is clamped
 | ||||
|         resourceSystem->getSceneManager()->setClampLighting(Settings::Manager::getBool("clamp lighting", "Shaders")); | ||||
|         resourceSystem->getSceneManager()->setClampLighting(clampLighting); | ||||
|         resourceSystem->getSceneManager()->setAutoUseNormalMaps(Settings::Manager::getBool("auto use object normal maps", "Shaders")); | ||||
|         resourceSystem->getSceneManager()->setNormalMapPattern(Settings::Manager::getString("normal map pattern", "Shaders")); | ||||
|         resourceSystem->getSceneManager()->setNormalHeightMapPattern(Settings::Manager::getString("normal height map pattern", "Shaders")); | ||||
|         resourceSystem->getSceneManager()->setAutoUseSpecularMaps(Settings::Manager::getBool("auto use object specular maps", "Shaders")); | ||||
|         resourceSystem->getSceneManager()->setSpecularMapPattern(Settings::Manager::getString("specular map pattern", "Shaders")); | ||||
|         resourceSystem->getSceneManager()->setApplyLightingToEnvMaps(Settings::Manager::getBool("apply lighting to environment maps", "Shaders")); | ||||
|         resourceSystem->getSceneManager()->setFFPLighting(clampLighting || !forceShaders || !SceneUtil::LightManager::queryNonFFPLightingSupport()); | ||||
| 
 | ||||
|         osg::ref_ptr<SceneUtil::LightManager> sceneRoot = new SceneUtil::LightManager; | ||||
|         osg::ref_ptr<SceneUtil::LightManager> sceneRoot = new SceneUtil::LightManager(mResourceSystem->getSceneManager()->getFFPLighting()); | ||||
|         sceneRoot->setLightingMask(Mask_Lighting); | ||||
|         mSceneRoot = sceneRoot; | ||||
|         sceneRoot->setStartLight(1); | ||||
|  | @ -235,8 +237,12 @@ namespace MWRender | |||
|         mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask, mResourceSystem->getSceneManager()->getShaderManager())); | ||||
| 
 | ||||
|         Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines(); | ||||
|         Shader::ShaderManager::DefineMap lightDefines = sceneRoot->getLightDefines(); | ||||
|         Shader::ShaderManager::DefineMap globalDefines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); | ||||
| 
 | ||||
|         for (auto itr = lightDefines.begin(); itr != lightDefines.end(); itr++) | ||||
|             globalDefines[itr->first] = itr->second; | ||||
| 
 | ||||
|         for (auto itr = shadowDefines.begin(); itr != shadowDefines.end(); itr++) | ||||
|             globalDefines[itr->first] = itr->second; | ||||
| 
 | ||||
|  | @ -248,7 +254,7 @@ namespace MWRender | |||
|         float groundcoverDistance = (Constants::CellSizeInUnits * std::max(1, Settings::Manager::getInt("distance", "Groundcover")) - 1024) * 0.93; | ||||
|         globalDefines["groundcoverFadeStart"] = std::to_string(groundcoverDistance * 0.9f); | ||||
|         globalDefines["groundcoverFadeEnd"] = std::to_string(groundcoverDistance); | ||||
| 
 | ||||
|          | ||||
|         // It is unnecessary to stop/start the viewer as no frames are being rendered yet.
 | ||||
|         mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines); | ||||
| 
 | ||||
|  | @ -354,6 +360,7 @@ namespace MWRender | |||
|         mSunLight->setAmbient(osg::Vec4f(0,0,0,1)); | ||||
|         mSunLight->setSpecular(osg::Vec4f(0,0,0,0)); | ||||
|         mSunLight->setConstantAttenuation(1.f); | ||||
|         sceneRoot->setSunlight(mSunLight); | ||||
|         sceneRoot->addChild(source); | ||||
| 
 | ||||
|         sceneRoot->getOrCreateStateSet()->setMode(GL_CULL_FACE, osg::StateAttribute::ON); | ||||
|  |  | |||
|  | @ -27,6 +27,7 @@ | |||
| 
 | ||||
| #include <components/sceneutil/shadow.hpp> | ||||
| #include <components/sceneutil/waterutil.hpp> | ||||
| #include <components/sceneutil/lightmanager.hpp> | ||||
| 
 | ||||
| #include <components/misc/constants.hpp> | ||||
| 
 | ||||
|  | @ -644,6 +645,8 @@ void Water::createShaderWaterStateSet(osg::Node* node, Reflection* reflection, R | |||
|     osg::ref_ptr<osg::Program> program (new osg::Program); | ||||
|     program->addShader(vertexShader); | ||||
|     program->addShader(fragmentShader); | ||||
|     if (!mResourceSystem->getSceneManager()->getFFPLighting()) | ||||
|         program->addBindUniformBlock("SunlightBuffer", 9); | ||||
|     shaderStateset->setAttributeAndModes(program, osg::StateAttribute::ON); | ||||
| 
 | ||||
|     node->setStateSet(shaderStateset); | ||||
|  |  | |||
|  | @ -220,12 +220,13 @@ namespace Resource | |||
| 
 | ||||
|     SceneManager::SceneManager(const VFS::Manager *vfs, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager) | ||||
|         : ResourceManager(vfs) | ||||
|         , mShaderManager(new Shader::ShaderManager) | ||||
|         , mShaderManager(new Shader::ShaderManager(this)) | ||||
|         , mForceShaders(false) | ||||
|         , mClampLighting(true) | ||||
|         , mAutoUseNormalMaps(false) | ||||
|         , mAutoUseSpecularMaps(false) | ||||
|         , mApplyLightingToEnvMaps(false) | ||||
|         , mFFPLighting(true) | ||||
|         , mInstanceCache(new MultiObjectCache) | ||||
|         , mSharedStateManager(new SharedStateManager) | ||||
|         , mImageManager(imageManager) | ||||
|  | @ -297,6 +298,16 @@ namespace Resource | |||
|         mApplyLightingToEnvMaps = apply; | ||||
|     } | ||||
| 
 | ||||
|     void SceneManager::setFFPLighting(bool apply) | ||||
|     { | ||||
|         mFFPLighting = apply; | ||||
|     } | ||||
| 
 | ||||
|     bool SceneManager::getFFPLighting() const | ||||
|     { | ||||
|         return mFFPLighting; | ||||
|     } | ||||
| 
 | ||||
|     SceneManager::~SceneManager() | ||||
|     { | ||||
|         // this has to be defined in the .cpp file as we can't delete incomplete types
 | ||||
|  |  | |||
|  | @ -100,6 +100,9 @@ namespace Resource | |||
| 
 | ||||
|         void setApplyLightingToEnvMaps(bool apply); | ||||
| 
 | ||||
|         void setFFPLighting(bool apply); | ||||
|         bool getFFPLighting() const; | ||||
| 
 | ||||
|         void setShaderPath(const std::string& path); | ||||
| 
 | ||||
|         /// Check if a given scene is loaded and if so, update its usage timestamp to prevent it from being unloaded
 | ||||
|  | @ -184,6 +187,7 @@ namespace Resource | |||
|         bool mAutoUseSpecularMaps; | ||||
|         std::string mSpecularMapPattern; | ||||
|         bool mApplyLightingToEnvMaps; | ||||
|         bool mFFPLighting; | ||||
| 
 | ||||
|         osg::ref_ptr<MultiObjectCache> mInstanceCache; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,11 +1,145 @@ | |||
| #include "lightmanager.hpp" | ||||
| 
 | ||||
| #include <osg/BufferObject> | ||||
| 
 | ||||
| #include <osgUtil/CullVisitor> | ||||
| 
 | ||||
| #include <components/sceneutil/util.hpp> | ||||
| 
 | ||||
| #include <components/misc/stringops.hpp> | ||||
| 
 | ||||
| #include <components/settings/settings.hpp> | ||||
| 
 | ||||
| #include <components/debug/debuglog.hpp> | ||||
| 
 | ||||
| namespace  | ||||
| { | ||||
|     /* similar to the boost::hash_combine */ | ||||
|     template <class T> | ||||
|     inline void hash_combine(std::size_t& seed, const T& v) | ||||
|     { | ||||
|         std::hash<T> hasher; | ||||
|         seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); | ||||
|     } | ||||
| 
 | ||||
|     bool sortLights(const SceneUtil::LightManager::LightSourceViewBound* left, const SceneUtil::LightManager::LightSourceViewBound* right) | ||||
|     { | ||||
|         return left->mViewBound.center().length2() - left->mViewBound.radius2()*81 < right->mViewBound.center().length2() - right->mViewBound.radius2()*81; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| namespace SceneUtil | ||||
| { | ||||
|     static int sLightId = 0; | ||||
| 
 | ||||
|     class LightBuffer : public osg::Referenced | ||||
|     { | ||||
|     public: | ||||
|         LightBuffer(int elements, int count=1) | ||||
|             : mNumElements(elements) | ||||
|             , mData(new osg::Vec4Array(elements * count)) | ||||
|             , mDirty(false) | ||||
|         {} | ||||
| 
 | ||||
|         virtual ~LightBuffer() {} | ||||
| 
 | ||||
|         osg::ref_ptr<osg::Vec4Array> getData()  | ||||
|         { | ||||
|             return mData; | ||||
|         } | ||||
| 
 | ||||
|         bool isDirty() const | ||||
|         { | ||||
|             return mDirty; | ||||
|         } | ||||
| 
 | ||||
|         void dirty() | ||||
|         { | ||||
|             mData->dirty(); | ||||
|             mDirty = false; | ||||
|         } | ||||
| 
 | ||||
|         int blockSize() const  | ||||
|         { | ||||
|             return mData->getNumElements() * sizeof(GL_FLOAT) * osg::Vec4::num_components; | ||||
|         } | ||||
| 
 | ||||
|     protected: | ||||
|         size_t mNumElements; | ||||
|         osg::ref_ptr<osg::Vec4Array> mData; | ||||
|         bool mDirty; | ||||
|     }; | ||||
| 
 | ||||
|     /*
 | ||||
|      *  struct: | ||||
|      *      vec4 diffuse | ||||
|      *      vec4 ambient | ||||
|      *      vec4 specular | ||||
|      *      vec4 direction | ||||
|      */ | ||||
|     class SunlightBuffer : public LightBuffer | ||||
|     { | ||||
|     public: | ||||
| 
 | ||||
|         enum Type {Diffuse, Ambient, Specular, Direction}; | ||||
| 
 | ||||
|         SunlightBuffer() | ||||
|             : LightBuffer(4) | ||||
|         {} | ||||
| 
 | ||||
|         void setValue(Type type, const osg::Vec4& value) | ||||
|         { | ||||
|             if (getValue(type) == value) | ||||
|                 return; | ||||
| 
 | ||||
|             (*mData)[type] = value; | ||||
| 
 | ||||
|             mDirty = true; | ||||
|         }    | ||||
| 
 | ||||
|         osg::Vec4 getValue(Type type) | ||||
|         { | ||||
|             return (*mData)[type]; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     /*
 | ||||
|      *  struct: | ||||
|      *      vec4 diffuse | ||||
|      *      vec4 ambient | ||||
|      *      vec4 position | ||||
|      *      vec4 illumination (constant, linear, quadratic) | ||||
|      */ | ||||
|     class PointLightBuffer : public LightBuffer | ||||
|     { | ||||
|     public: | ||||
| 
 | ||||
|         enum Type {Diffuse, Ambient, Position, Attenuation}; | ||||
| 
 | ||||
|         PointLightBuffer(int count) | ||||
|             : LightBuffer(4, count) | ||||
|         {} | ||||
| 
 | ||||
|         void setValue(int index, Type type, const osg::Vec4& value) | ||||
|         { | ||||
|             if (getValue(index, type) == value) | ||||
|                 return; | ||||
| 
 | ||||
|             (*mData)[mNumElements * index + type] = value; | ||||
| 
 | ||||
|             mDirty = true; | ||||
|         } | ||||
| 
 | ||||
|         osg::Vec4 getValue(int index, Type type) | ||||
|         { | ||||
|             return (*mData)[mNumElements * index + type]; | ||||
|         } | ||||
| 
 | ||||
|         static constexpr int queryBlockSize(int sz) | ||||
|         { | ||||
|             return 4 * osg::Vec4::num_components * sizeof(GL_FLOAT) * sz; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     class LightStateCache | ||||
|     { | ||||
|  | @ -13,7 +147,7 @@ namespace SceneUtil | |||
|         osg::Light* lastAppliedLight[8]; | ||||
|     }; | ||||
| 
 | ||||
|     LightStateCache* getLightStateCache(unsigned int contextid) | ||||
|     LightStateCache* getLightStateCache(size_t contextid) | ||||
|     { | ||||
|         static std::vector<LightStateCache> cacheVector; | ||||
|         if (cacheVector.size() < contextid+1) | ||||
|  | @ -21,15 +155,53 @@ namespace SceneUtil | |||
|         return &cacheVector[contextid]; | ||||
|     } | ||||
| 
 | ||||
|     // Resets the modelview matrix to just the view matrix before applying lights.
 | ||||
|     class LightStateAttribute : public osg::StateAttribute | ||||
|     SunlightStateAttribute::SunlightStateAttribute() | ||||
|         : mBuffer(new SunlightBuffer) | ||||
|     { | ||||
|         osg::ref_ptr<osg::UniformBufferObject> ubo = new osg::UniformBufferObject; | ||||
|         mBuffer->getData()->setBufferObject(ubo); | ||||
|         mUbb = new osg::UniformBufferBinding(9 , mBuffer->getData().get(), 0, mBuffer->blockSize()); | ||||
|     } | ||||
| 
 | ||||
|     SunlightStateAttribute::SunlightStateAttribute(const SunlightStateAttribute ©, const osg::CopyOp ©op) | ||||
|         : osg::StateAttribute(copy, copyop), mBuffer(copy.mBuffer)  | ||||
|     {} | ||||
| 
 | ||||
|     int SunlightStateAttribute::compare(const StateAttribute &sa) const | ||||
|     { | ||||
|         throw std::runtime_error("LightStateAttribute::compare: unimplemented"); | ||||
|     } | ||||
| 
 | ||||
|     void SunlightStateAttribute::setFromLight(const osg::Light* light) | ||||
|     { | ||||
|         mBuffer->setValue(SunlightBuffer::Diffuse, light->getDiffuse()); | ||||
|         mBuffer->setValue(SunlightBuffer::Ambient, light->getAmbient()); | ||||
|         mBuffer->setValue(SunlightBuffer::Specular, light->getSpecular()); | ||||
|         mBuffer->setValue(SunlightBuffer::Direction, light->getPosition()); | ||||
|     } | ||||
| 
 | ||||
|     void SunlightStateAttribute::setStateSet(osg::StateSet* stateset, int mode) | ||||
|     { | ||||
|         stateset->setAttributeAndModes(mUbb, mode); | ||||
|         stateset->setAssociatedModes(this, mode); | ||||
|         mBuffer->dirty(); | ||||
|     } | ||||
| 
 | ||||
|     class DisableLight : public osg::StateAttribute | ||||
|     { | ||||
|     public: | ||||
|         LightStateAttribute() : mIndex(0) {} | ||||
|         LightStateAttribute(unsigned int index, const std::vector<osg::ref_ptr<osg::Light> >& lights) : mIndex(index), mLights(lights) {} | ||||
|         DisableLight() : mIndex(0) {} | ||||
|         DisableLight(int index) : mIndex(index) {} | ||||
| 
 | ||||
|         LightStateAttribute(const LightStateAttribute& copy,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) | ||||
|             : osg::StateAttribute(copy,copyop), mIndex(copy.mIndex), mLights(copy.mLights) {} | ||||
|         DisableLight(const DisableLight& copy,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) | ||||
|             : osg::StateAttribute(copy,copyop), mIndex(copy.mIndex) {} | ||||
| 
 | ||||
|         osg::Object* cloneType() const override { return new DisableLight(mIndex); } | ||||
|         osg::Object* clone(const osg::CopyOp& copyop) const override { return new DisableLight(*this,copyop); } | ||||
|         bool isSameKindAs(const osg::Object* obj) const override { return dynamic_cast<const DisableLight *>(obj)!=nullptr; } | ||||
|         const char* libraryName() const override { return "SceneUtil"; } | ||||
|         const char* className() const override { return "DisableLight"; } | ||||
|         Type getType() const override { return LIGHT; } | ||||
| 
 | ||||
|         unsigned int getMember() const override | ||||
|         { | ||||
|  | @ -38,11 +210,40 @@ namespace SceneUtil | |||
| 
 | ||||
|         bool getModeUsage(ModeUsage & usage) const override | ||||
|         { | ||||
|             for (unsigned int i=0; i<mLights.size(); ++i) | ||||
|                 usage.usesMode(GL_LIGHT0 + mIndex + i); | ||||
|             usage.usesMode(GL_LIGHT0 + mIndex); | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         int compare(const StateAttribute &sa) const override | ||||
|         { | ||||
|             throw std::runtime_error("DisableLight::compare: unimplemented"); | ||||
|         } | ||||
| 
 | ||||
|         void apply(osg::State& state) const override | ||||
|         { | ||||
|             int lightNum = GL_LIGHT0 + mIndex; | ||||
|             glLightfv( lightNum, GL_AMBIENT,               mnullptr.ptr() ); | ||||
|             glLightfv( lightNum, GL_DIFFUSE,               mnullptr.ptr() ); | ||||
|             glLightfv( lightNum, GL_SPECULAR,              mnullptr.ptr() ); | ||||
| 
 | ||||
|             LightStateCache* cache = getLightStateCache(state.getContextID()); | ||||
|             cache->lastAppliedLight[mIndex] = nullptr; | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         size_t mIndex; | ||||
|         osg::Vec4f mnullptr; | ||||
|     }; | ||||
| 
 | ||||
|     class LightStateAttribute : public osg::StateAttribute | ||||
|     { | ||||
|     public: | ||||
|         LightStateAttribute() : mBuffer(nullptr) {} | ||||
|         LightStateAttribute(const std::vector<osg::ref_ptr<osg::Light> >& lights, const osg::ref_ptr<PointLightBuffer>& buffer) : mLights(lights), mBuffer(buffer) {}  | ||||
| 
 | ||||
|         LightStateAttribute(const LightStateAttribute& copy,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) | ||||
|             : osg::StateAttribute(copy,copyop), mLights(copy.mLights), mBuffer(copy.mBuffer) {} | ||||
| 
 | ||||
|         int compare(const StateAttribute &sa) const override | ||||
|         { | ||||
|             throw std::runtime_error("LightStateAttribute::compare: unimplemented"); | ||||
|  | @ -50,6 +251,68 @@ namespace SceneUtil | |||
| 
 | ||||
|         META_StateAttribute(NifOsg, LightStateAttribute, osg::StateAttribute::LIGHT) | ||||
| 
 | ||||
|         void apply(osg::State& state) const override | ||||
|         { | ||||
|             if (mLights.empty()) | ||||
|                 return; | ||||
|             osg::Matrix modelViewMatrix = state.getModelViewMatrix(); | ||||
| 
 | ||||
|             state.applyModelViewMatrix(state.getInitialViewMatrix()); | ||||
| 
 | ||||
|             if (mBuffer) | ||||
|             { | ||||
|                 for (size_t i = 0; i < mLights.size(); ++i) | ||||
|                 { | ||||
| 
 | ||||
|                     mBuffer->setValue(i, PointLightBuffer::Diffuse, mLights[i]->getDiffuse()); | ||||
|                     mBuffer->setValue(i, PointLightBuffer::Ambient, mLights[i]->getAmbient()); | ||||
|                     mBuffer->setValue(i, PointLightBuffer::Position, mLights[i]->getPosition() * state.getModelViewMatrix()); | ||||
|                     mBuffer->setValue(i, PointLightBuffer::Attenuation, | ||||
|                                         osg::Vec4(mLights[i]->getConstantAttenuation(),  | ||||
|                                                   mLights[i]->getLinearAttenuation(),  | ||||
|                                                   mLights[i]->getQuadraticAttenuation(), 0.0)); | ||||
|                 } | ||||
| 
 | ||||
|                 if (mBuffer && mBuffer->isDirty()) | ||||
|                     mBuffer->dirty(); | ||||
|             } | ||||
| 
 | ||||
|             state.applyModelViewMatrix(modelViewMatrix); | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         std::vector<osg::ref_ptr<osg::Light>> mLights; | ||||
|         osg::ref_ptr<PointLightBuffer> mBuffer; | ||||
|     }; | ||||
| 
 | ||||
|     class FFPLightStateAttribute : public osg::StateAttribute | ||||
|     { | ||||
|     public: | ||||
|         FFPLightStateAttribute() : mIndex(0) {} | ||||
|         FFPLightStateAttribute(size_t index, const std::vector<osg::ref_ptr<osg::Light> >& lights) : mIndex(index), mLights(lights) {} | ||||
| 
 | ||||
|         FFPLightStateAttribute(const FFPLightStateAttribute& copy,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) | ||||
|             : osg::StateAttribute(copy,copyop), mIndex(copy.mIndex), mLights(copy.mLights) {} | ||||
| 
 | ||||
|         unsigned int getMember() const override | ||||
|         { | ||||
|             return mIndex; | ||||
|         } | ||||
| 
 | ||||
|         bool getModeUsage(ModeUsage & usage) const override | ||||
|         { | ||||
|             for (size_t i=0; i<mLights.size(); ++i) | ||||
|                 usage.usesMode(GL_LIGHT0 + mIndex + i); | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         int compare(const StateAttribute &sa) const override | ||||
|         { | ||||
|             throw std::runtime_error("FFPLightStateAttribute::compare: unimplemented"); | ||||
|         } | ||||
| 
 | ||||
|         META_StateAttribute(NifOsg, FFPLightStateAttribute, osg::StateAttribute::LIGHT) | ||||
| 
 | ||||
|         void apply(osg::State& state) const override | ||||
|         { | ||||
|             if (mLights.empty()) | ||||
|  | @ -60,7 +323,7 @@ namespace SceneUtil | |||
| 
 | ||||
|             LightStateCache* cache = getLightStateCache(state.getContextID()); | ||||
| 
 | ||||
|             for (unsigned int i=0; i<mLights.size(); ++i) | ||||
|             for (size_t i=0; i<mLights.size(); ++i) | ||||
|             { | ||||
|                 osg::Light* current = cache->lastAppliedLight[i+mIndex]; | ||||
|                 if (current != mLights[i].get()) | ||||
|  | @ -90,14 +353,14 @@ namespace SceneUtil | |||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         unsigned int mIndex; | ||||
|         size_t mIndex; | ||||
| 
 | ||||
|         std::vector<osg::ref_ptr<osg::Light> > mLights; | ||||
|         std::vector<osg::ref_ptr<osg::Light>> mLights; | ||||
|     }; | ||||
| 
 | ||||
|     LightManager* findLightManager(const osg::NodePath& path) | ||||
|     { | ||||
|         for (unsigned int i=0;i<path.size(); ++i) | ||||
|         for (size_t i=0;i<path.size(); ++i) | ||||
|         { | ||||
|             if (LightManager* lightManager = dynamic_cast<LightManager*>(path[i])) | ||||
|                 return lightManager; | ||||
|  | @ -160,33 +423,161 @@ namespace SceneUtil | |||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     LightManager::LightManager() | ||||
|     class SunlightCallback : public osg::NodeCallback | ||||
|     { | ||||
|     public: | ||||
|         SunlightCallback(LightManager* lightManager) : mLightManager(lightManager) {} | ||||
| 
 | ||||
|         void operator()(osg::Node* node, osg::NodeVisitor* nv) override | ||||
|         { | ||||
|             osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(nv); | ||||
| 
 | ||||
|             if (mLastFrameNumber != cv->getTraversalNumber()) | ||||
|             { | ||||
|                 mLastFrameNumber = cv->getTraversalNumber(); | ||||
| 
 | ||||
|                 auto sun = mLightManager->getSunlight(); | ||||
| 
 | ||||
|                 if (!sun) | ||||
|                     return; | ||||
| 
 | ||||
|                 auto buf = mLightManager->getSunBuffer(); | ||||
| 
 | ||||
|                 buf->setValue(SunlightBuffer::Diffuse, sun->getDiffuse()); | ||||
|                 buf->setValue(SunlightBuffer::Ambient, sun->getAmbient()); | ||||
|                 buf->setValue(SunlightBuffer::Specular, sun->getSpecular()); | ||||
|                 buf->setValue(SunlightBuffer::Direction, sun->getPosition() * *cv->getCurrentRenderStage()->getInitialViewMatrix());                            | ||||
| 
 | ||||
|                 if (buf->isDirty()) | ||||
|                     buf->dirty(); | ||||
|             } | ||||
| 
 | ||||
|             traverse(node, nv); | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         LightManager* mLightManager; | ||||
|         size_t mLastFrameNumber; | ||||
|     }; | ||||
| 
 | ||||
|     LightManager::LightManager(bool ffp) | ||||
|         : mStartLight(0) | ||||
|         , mLightingMask(~0u) | ||||
|         , mSun(nullptr) | ||||
|         , mSunBuffer(nullptr) | ||||
|         , mFFP(ffp) | ||||
|     { | ||||
|         setUpdateCallback(new LightManagerUpdateCallback); | ||||
|         for (unsigned int i=0; i<8; ++i) | ||||
|             mDummies.push_back(new LightStateAttribute(i, std::vector<osg::ref_ptr<osg::Light> >())); | ||||
| 
 | ||||
|         if (usingFFP()) | ||||
|         { | ||||
|             for (int i=0; i<getMaxLights(); ++i) | ||||
|                 mDummies.push_back(new FFPLightStateAttribute(i, std::vector<osg::ref_ptr<osg::Light> >())); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         auto* stateset = getOrCreateStateSet(); | ||||
| 
 | ||||
|         mSunBuffer = new SunlightBuffer(); | ||||
|         osg::ref_ptr<osg::UniformBufferObject> ubo = new osg::UniformBufferObject; | ||||
|         mSunBuffer->getData()->setBufferObject(ubo); | ||||
|         osg::ref_ptr<osg::UniformBufferBinding> ubb = new osg::UniformBufferBinding(9 , mSunBuffer->getData().get(), 0, mSunBuffer->blockSize()); | ||||
|         stateset->setAttributeAndModes(ubb.get(), osg::StateAttribute::ON); | ||||
| 
 | ||||
|         stateset->addUniform(new osg::Uniform("PointLightCount", 0)); | ||||
| 
 | ||||
|         addCullCallback(new SunlightCallback(this)); | ||||
|     } | ||||
| 
 | ||||
|     LightManager::LightManager(const LightManager ©, const osg::CopyOp ©op) | ||||
|         : osg::Group(copy, copyop) | ||||
|         , mStartLight(copy.mStartLight) | ||||
|         , mLightingMask(copy.mLightingMask) | ||||
|         , mSun(copy.mSun) | ||||
|         , mSunBuffer(copy.mSunBuffer) | ||||
|         , mFFP(copy.mFFP) | ||||
|     { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     void LightManager::setLightingMask(unsigned int mask) | ||||
|     bool LightManager::usingFFP() const | ||||
|     { | ||||
|         return mFFP; | ||||
|     } | ||||
| 
 | ||||
|     int LightManager::getMaxLights() const | ||||
|     { | ||||
|         if (usingFFP()) return LightManager::mFFPMaxLights; | ||||
|         return std::clamp(Settings::Manager::getInt("max lights", "Shaders"), 0, getMaxLightsInScene()); | ||||
|     } | ||||
| 
 | ||||
|     int LightManager::getMaxLightsInScene() const | ||||
|     { | ||||
|         static constexpr int max = 16384 / PointLightBuffer::queryBlockSize(1);         | ||||
|         return  max;           | ||||
|     } | ||||
| 
 | ||||
|     Shader::ShaderManager::DefineMap LightManager::getLightDefines() const | ||||
|     { | ||||
|         Shader::ShaderManager::DefineMap defines; | ||||
| 
 | ||||
|         bool ffp = usingFFP(); | ||||
|          | ||||
|         defines["ffpLighting"] = ffp ? "1" : "0"; | ||||
|         defines["sunDirection"] = ffp ? "gl_LightSource[0].position" : "Sun.direction"; | ||||
|         defines["sunAmbient"] = ffp ? "gl_LightSource[0].ambient" : "Sun.ambient"; | ||||
|         defines["sunDiffuse"] = ffp ? "gl_LightSource[0].diffuse" : "Sun.diffuse"; | ||||
|         defines["sunSpecular"] = ffp ? "gl_LightSource[0].specular" : "Sun.specular"; | ||||
|         defines["maxLights"] = std::to_string(getMaxLights()); | ||||
|         defines["maxLightsInScene"] = std::to_string(getMaxLightsInScene()); | ||||
| 
 | ||||
|         return defines; | ||||
|     } | ||||
| 
 | ||||
|     bool LightManager::queryNonFFPLightingSupport() | ||||
|     { | ||||
|         osg::GLExtensions* exts = osg::GLExtensions::Get(0, false); | ||||
|         if (!exts || !exts->isUniformBufferObjectSupported) | ||||
|         { | ||||
|             auto ffpWarning = Misc::StringUtils::format("GL_ARB_uniform_buffer_object not supported:  Falling back to FFP %zu light limit. Can not set lights to %i." | ||||
|                                                     , LightManager::mFFPMaxLights | ||||
|                                                     , Settings::Manager::getInt("max lights", "Shaders")); | ||||
|             Log(Debug::Warning) << ffpWarning; | ||||
|             return false; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     void LightManager::setLightingMask(size_t mask) | ||||
|     { | ||||
|         mLightingMask = mask; | ||||
|     } | ||||
| 
 | ||||
|     unsigned int LightManager::getLightingMask() const | ||||
|     size_t LightManager::getLightingMask() const | ||||
|     { | ||||
|         return mLightingMask; | ||||
|     } | ||||
| 
 | ||||
|     void LightManager::setStartLight(int start) | ||||
|     { | ||||
|         if (!usingFFP()) return; | ||||
| 
 | ||||
|         mStartLight = start; | ||||
| 
 | ||||
|         // Set default light state to zero
 | ||||
|         // This is necessary because shaders don't respect glDisable(GL_LIGHTX) so in addition to disabling
 | ||||
|         // we'll have to set a light state that has no visible effect
 | ||||
|         for (int i=start; i<getMaxLights(); ++i) | ||||
|         { | ||||
|             osg::ref_ptr<DisableLight> defaultLight (new DisableLight(i)); | ||||
|             getOrCreateStateSet()->setAttributeAndModes(defaultLight, osg::StateAttribute::OFF); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     int LightManager::getStartLight() const | ||||
|     { | ||||
|         return mStartLight; | ||||
|     } | ||||
| 
 | ||||
|     void LightManager::update() | ||||
|     { | ||||
|         mLights.clear(); | ||||
|  | @ -200,7 +591,7 @@ namespace SceneUtil | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     void LightManager::addLight(LightSource* lightSource, const osg::Matrixf& worldMat, unsigned int frameNum) | ||||
|     void LightManager::addLight(LightSource* lightSource, const osg::Matrixf& worldMat, size_t frameNum) | ||||
|     { | ||||
|         LightSourceTransform l; | ||||
|         l.mLightSource = lightSource; | ||||
|  | @ -211,19 +602,28 @@ namespace SceneUtil | |||
|         mLights.push_back(l); | ||||
|     } | ||||
| 
 | ||||
|     /* similar to the boost::hash_combine */ | ||||
|     template <class T> | ||||
|     inline void hash_combine(std::size_t& seed, const T& v) | ||||
|     void LightManager::setSunlight(osg::ref_ptr<osg::Light> sun) | ||||
|     { | ||||
|         std::hash<T> hasher; | ||||
|         seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); | ||||
|         if (usingFFP()) return; | ||||
| 
 | ||||
|         mSun = sun; | ||||
|     } | ||||
| 
 | ||||
|     osg::ref_ptr<osg::StateSet> LightManager::getLightListStateSet(const LightList &lightList, unsigned int frameNum) | ||||
|     osg::ref_ptr<osg::Light> LightManager::getSunlight() | ||||
|     { | ||||
|         return mSun; | ||||
|     } | ||||
| 
 | ||||
|     osg::ref_ptr<SunlightBuffer> LightManager::getSunBuffer() | ||||
|     { | ||||
|         return mSunBuffer; | ||||
|     } | ||||
| 
 | ||||
|     osg::ref_ptr<osg::StateSet> LightManager::getLightListStateSet(const LightList &lightList, size_t frameNum) | ||||
|     { | ||||
|         // possible optimization: return a StateSet containing all requested lights plus some extra lights (if a suitable one exists)
 | ||||
|         size_t hash = 0; | ||||
|         for (unsigned int i=0; i<lightList.size();++i) | ||||
|         for (size_t i=0; i<lightList.size();++i) | ||||
|             hash_combine(hash, lightList[i]->mLightSource->getId()); | ||||
| 
 | ||||
|         LightStateSetMap& stateSetCache = mStateSetCache[frameNum%2]; | ||||
|  | @ -236,21 +636,35 @@ namespace SceneUtil | |||
|             osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet; | ||||
|             std::vector<osg::ref_ptr<osg::Light> > lights; | ||||
|             lights.reserve(lightList.size()); | ||||
|             for (unsigned int i=0; i<lightList.size();++i) | ||||
|             for (size_t i=0; i<lightList.size();++i) | ||||
|                 lights.emplace_back(lightList[i]->mLightSource->getLight(frameNum)); | ||||
| 
 | ||||
|             // the first light state attribute handles the actual state setting for all lights
 | ||||
|             // it's best to batch these up so that we don't need to touch the modelView matrix more than necessary
 | ||||
|             // don't use setAttributeAndModes, that does not support light indices!
 | ||||
|             stateset->setAttribute(new LightStateAttribute(mStartLight, std::move(lights)), osg::StateAttribute::ON); | ||||
|             if (usingFFP()) | ||||
|             { | ||||
|                 // the first light state attribute handles the actual state setting for all lights
 | ||||
|                 // it's best to batch these up so that we don't need to touch the modelView matrix more than necessary
 | ||||
|                 // don't use setAttributeAndModes, that does not support light indices!
 | ||||
|                 stateset->setAttribute(new FFPLightStateAttribute(mStartLight, std::move(lights)), osg::StateAttribute::ON); | ||||
| 
 | ||||
|             for (unsigned int i=0; i<lightList.size(); ++i) | ||||
|                 stateset->setMode(GL_LIGHT0 + mStartLight + i, osg::StateAttribute::ON); | ||||
|                 for (size_t i=0; i<lightList.size(); ++i) | ||||
|                     stateset->setMode(GL_LIGHT0 + mStartLight + i, osg::StateAttribute::ON); | ||||
| 
 | ||||
|             // need to push some dummy attributes to ensure proper state tracking
 | ||||
|             // lights need to reset to their default when the StateSet is popped
 | ||||
|             for (unsigned int i=1; i<lightList.size(); ++i) | ||||
|                 stateset->setAttribute(mDummies[i+mStartLight].get(), osg::StateAttribute::ON); | ||||
|                 // need to push some dummy attributes to ensure proper state tracking
 | ||||
|                 // lights need to reset to their default when the StateSet is popped
 | ||||
|                 for (size_t i=1; i<lightList.size(); ++i) | ||||
|                     stateset->setAttribute(mDummies[i+mStartLight].get(), osg::StateAttribute::ON); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 osg::ref_ptr<PointLightBuffer> buffer = new PointLightBuffer(lights.size()); | ||||
|                 osg::ref_ptr<osg::UniformBufferObject> ubo = new osg::UniformBufferObject; | ||||
|                 buffer->getData()->setBufferObject(ubo); | ||||
|                 osg::ref_ptr<osg::UniformBufferBinding> ubb = new osg::UniformBufferBinding(8 ,buffer->getData().get(), 0, buffer->blockSize()); | ||||
|                 stateset->addUniform(new osg::Uniform("PointLightCount", (int)lights.size())); | ||||
|                 stateset->setAttributeAndModes(ubb.get(), osg::StateAttribute::ON); | ||||
| 
 | ||||
|                 stateset->setAttribute(new LightStateAttribute(std::move(lights), buffer), osg::StateAttribute::ON); | ||||
|             } | ||||
| 
 | ||||
|             stateSetCache.emplace(hash, stateset); | ||||
|             return stateset; | ||||
|  | @ -262,7 +676,7 @@ namespace SceneUtil | |||
|         return mLights; | ||||
|     } | ||||
| 
 | ||||
|     const std::vector<LightManager::LightSourceViewBound>& LightManager::getLightsInViewSpace(osg::Camera *camera, const osg::RefMatrix* viewMatrix) | ||||
|     const std::vector<LightManager::LightSourceViewBound>& LightManager::getLightsInViewSpace(osg::Camera *camera, const osg::RefMatrix* viewMatrix, size_t frameNum) | ||||
|     { | ||||
|         osg::observer_ptr<osg::Camera> camPtr (camera); | ||||
|         std::map<osg::observer_ptr<osg::Camera>, LightSourceViewBoundCollection>::iterator it = mLightsInViewSpace.find(camPtr); | ||||
|  | @ -286,75 +700,6 @@ namespace SceneUtil | |||
|         return it->second; | ||||
|     } | ||||
| 
 | ||||
|     class DisableLight : public osg::StateAttribute | ||||
|     { | ||||
|     public: | ||||
|         DisableLight() : mIndex(0) {} | ||||
|         DisableLight(int index) : mIndex(index) {} | ||||
| 
 | ||||
|         DisableLight(const DisableLight& copy,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) | ||||
|             : osg::StateAttribute(copy,copyop), mIndex(copy.mIndex) {} | ||||
| 
 | ||||
|         osg::Object* cloneType() const override { return new DisableLight(mIndex); } | ||||
|         osg::Object* clone(const osg::CopyOp& copyop) const override { return new DisableLight(*this,copyop); } | ||||
|         bool isSameKindAs(const osg::Object* obj) const override { return dynamic_cast<const DisableLight *>(obj)!=nullptr; } | ||||
|         const char* libraryName() const override { return "SceneUtil"; } | ||||
|         const char* className() const override { return "DisableLight"; } | ||||
|         Type getType() const override { return LIGHT; } | ||||
| 
 | ||||
|         unsigned int getMember() const override | ||||
|         { | ||||
|             return mIndex; | ||||
|         } | ||||
| 
 | ||||
|         bool getModeUsage(ModeUsage & usage) const override | ||||
|         { | ||||
|             usage.usesMode(GL_LIGHT0 + mIndex); | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         int compare(const StateAttribute &sa) const override | ||||
|         { | ||||
|             throw std::runtime_error("DisableLight::compare: unimplemented"); | ||||
|         } | ||||
| 
 | ||||
|         void apply(osg::State& state) const override | ||||
|         { | ||||
|             int lightNum = GL_LIGHT0 + mIndex; | ||||
|             glLightfv( lightNum, GL_AMBIENT,               mnullptr.ptr() ); | ||||
|             glLightfv( lightNum, GL_DIFFUSE,               mnullptr.ptr() ); | ||||
|             glLightfv( lightNum, GL_SPECULAR,              mnullptr.ptr() ); | ||||
| 
 | ||||
|             LightStateCache* cache = getLightStateCache(state.getContextID()); | ||||
|             cache->lastAppliedLight[mIndex] = nullptr; | ||||
|         } | ||||
| 
 | ||||
|     private: | ||||
|         unsigned int mIndex; | ||||
|         osg::Vec4f mnullptr; | ||||
|     }; | ||||
| 
 | ||||
|     void LightManager::setStartLight(int start) | ||||
|     { | ||||
|         mStartLight = start; | ||||
| 
 | ||||
|         // Set default light state to zero
 | ||||
|         // This is necessary because shaders don't respect glDisable(GL_LIGHTX) so in addition to disabling
 | ||||
|         // we'll have to set a light state that has no visible effect
 | ||||
|         for (int i=start; i<8; ++i) | ||||
|         { | ||||
|             osg::ref_ptr<DisableLight> defaultLight (new DisableLight(i)); | ||||
|             getOrCreateStateSet()->setAttributeAndModes(defaultLight, osg::StateAttribute::OFF); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     int LightManager::getStartLight() const | ||||
|     { | ||||
|         return mStartLight; | ||||
|     } | ||||
| 
 | ||||
|     static int sLightId = 0; | ||||
| 
 | ||||
|     LightSource::LightSource() | ||||
|         : mRadius(0.f) | ||||
|     { | ||||
|  | @ -372,12 +717,6 @@ namespace SceneUtil | |||
|             mLight[i] = new osg::Light(*copy.mLight[i].get(), copyop); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     bool sortLights (const LightManager::LightSourceViewBound* left, const LightManager::LightSourceViewBound* right) | ||||
|     { | ||||
|         return left->mViewBound.center().length2() - left->mViewBound.radius2()*81 < right->mViewBound.center().length2() - right->mViewBound.radius2()*81; | ||||
|     } | ||||
| 
 | ||||
|     void LightListCallback::operator()(osg::Node *node, osg::NodeVisitor *nv) | ||||
|     { | ||||
|         osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(nv); | ||||
|  | @ -413,7 +752,7 @@ namespace SceneUtil | |||
| 
 | ||||
|             // Don't use Camera::getViewMatrix, that one might be relative to another camera!
 | ||||
|             const osg::RefMatrix* viewMatrix = cv->getCurrentRenderStage()->getInitialViewMatrix(); | ||||
|             const std::vector<LightManager::LightSourceViewBound>& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera(), viewMatrix); | ||||
|             const std::vector<LightManager::LightSourceViewBound>& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera(), viewMatrix, mLastFrameNumber); | ||||
| 
 | ||||
|             // get the node bounds in view space
 | ||||
|             // NB do not node->getBound() * modelView, that would apply the node's transformation twice
 | ||||
|  | @ -421,7 +760,7 @@ namespace SceneUtil | |||
|             osg::Transform* transform = node->asTransform(); | ||||
|             if (transform) | ||||
|             { | ||||
|                 for (unsigned int i=0; i<transform->getNumChildren(); ++i) | ||||
|                 for (size_t i=0; i<transform->getNumChildren(); ++i) | ||||
|                     nodeBound.expandBy(transform->getChild(i)->getBound()); | ||||
|             } | ||||
|             else | ||||
|  | @ -430,7 +769,7 @@ namespace SceneUtil | |||
|             transformBoundingSphere(mat, nodeBound); | ||||
| 
 | ||||
|             mLightList.clear(); | ||||
|             for (unsigned int i=0; i<lights.size(); ++i) | ||||
|             for (size_t i=0; i<lights.size(); ++i) | ||||
|             { | ||||
|                 const LightManager::LightSourceViewBound& l = lights[i]; | ||||
| 
 | ||||
|  | @ -443,7 +782,7 @@ namespace SceneUtil | |||
|         } | ||||
|         if (!mLightList.empty()) | ||||
|         { | ||||
|             unsigned int maxLights = static_cast<unsigned int> (8 - mLightManager->getStartLight()); | ||||
|             size_t maxLights = mLightManager->getMaxLights() - mLightManager->getStartLight(); | ||||
| 
 | ||||
|             osg::StateSet* stateset = nullptr; | ||||
| 
 | ||||
|  |  | |||
|  | @ -8,6 +8,9 @@ | |||
| #include <osg/Group> | ||||
| #include <osg/NodeVisitor> | ||||
| #include <osg/observer_ptr> | ||||
| #include <osg/BufferIndexBinding> | ||||
| 
 | ||||
| #include <components/shader/shadermanager.hpp> | ||||
| 
 | ||||
| namespace osgUtil | ||||
| { | ||||
|  | @ -16,6 +19,27 @@ namespace osgUtil | |||
| 
 | ||||
| namespace SceneUtil | ||||
| { | ||||
|     class SunlightBuffer; | ||||
| 
 | ||||
|     // Used to override sun. Rarely useful but necassary for local map. 
 | ||||
|     class SunlightStateAttribute : public osg::StateAttribute | ||||
|     { | ||||
|     public: | ||||
|         SunlightStateAttribute(); | ||||
|         SunlightStateAttribute(const SunlightStateAttribute& copy,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY); | ||||
|          | ||||
|         int compare(const StateAttribute &sa) const override; | ||||
| 
 | ||||
|         META_StateAttribute(NifOsg, SunlightStateAttribute, osg::StateAttribute::LIGHT) | ||||
| 
 | ||||
|         void setFromLight(const osg::Light* light); | ||||
| 
 | ||||
|         void setStateSet(osg::StateSet* stateset, int mode=osg::StateAttribute::ON); | ||||
| 
 | ||||
|     private: | ||||
|         osg::ref_ptr<SunlightBuffer> mBuffer; | ||||
|         osg::ref_ptr<osg::UniformBufferBinding> mUbb; | ||||
|     }; | ||||
| 
 | ||||
|     /// LightSource managed by a LightManager.
 | ||||
|     /// @par Typically used for point lights. Spot lights are not supported yet. Directional lights affect the whole scene
 | ||||
|  | @ -57,7 +81,7 @@ namespace SceneUtil | |||
|         /// Get the osg::Light safe for modification in the given frame.
 | ||||
|         /// @par May be used externally to animate the light's color/attenuation properties,
 | ||||
|         /// and is used internally to synchronize the light's position with the position of the LightSource.
 | ||||
|         osg::Light* getLight(unsigned int frame) | ||||
|         osg::Light* getLight(size_t frame) | ||||
|         { | ||||
|             return mLight[frame % 2]; | ||||
|         } | ||||
|  | @ -83,51 +107,62 @@ namespace SceneUtil | |||
|     class LightManager : public osg::Group | ||||
|     { | ||||
|     public: | ||||
| 
 | ||||
|         META_Node(SceneUtil, LightManager) | ||||
| 
 | ||||
|         LightManager(); | ||||
| 
 | ||||
|         LightManager(const LightManager& copy, const osg::CopyOp& copyop); | ||||
| 
 | ||||
|         /// @param mask This mask is compared with the current Camera's cull mask to determine if lighting is desired.
 | ||||
|         /// By default, it's ~0u i.e. always on.
 | ||||
|         /// If you have some views that do not require lighting, then set the Camera's cull mask to not include
 | ||||
|         /// the lightingMask for a much faster cull and rendering.
 | ||||
|         void setLightingMask (unsigned int mask); | ||||
| 
 | ||||
|         unsigned int getLightingMask() const; | ||||
| 
 | ||||
|         /// Set the first light index that should be used by this manager, typically the number of directional lights in the scene.
 | ||||
|         void setStartLight(int start); | ||||
| 
 | ||||
|         int getStartLight() const; | ||||
| 
 | ||||
|         /// Internal use only, called automatically by the LightManager's UpdateCallback
 | ||||
|         void update(); | ||||
| 
 | ||||
|         /// Internal use only, called automatically by the LightSource's UpdateCallback
 | ||||
|         void addLight(LightSource* lightSource, const osg::Matrixf& worldMat, unsigned int frameNum); | ||||
| 
 | ||||
|         struct LightSourceTransform | ||||
|         { | ||||
|             LightSource* mLightSource; | ||||
|             osg::Matrixf mWorldMatrix; | ||||
|         }; | ||||
| 
 | ||||
|         const std::vector<LightSourceTransform>& getLights() const; | ||||
| 
 | ||||
|         struct LightSourceViewBound | ||||
|         { | ||||
|             LightSource* mLightSource; | ||||
|             osg::BoundingSphere mViewBound; | ||||
|         }; | ||||
| 
 | ||||
|         const std::vector<LightSourceViewBound>& getLightsInViewSpace(osg::Camera* camera, const osg::RefMatrix* viewMatrix); | ||||
| 
 | ||||
|         typedef std::vector<const LightSourceViewBound*> LightList; | ||||
| 
 | ||||
|         osg::ref_ptr<osg::StateSet> getLightListStateSet(const LightList& lightList, unsigned int frameNum); | ||||
|         static bool queryNonFFPLightingSupport(); | ||||
| 
 | ||||
|         META_Node(SceneUtil, LightManager) | ||||
| 
 | ||||
|         LightManager(bool ffp = true); | ||||
| 
 | ||||
|         LightManager(const LightManager& copy, const osg::CopyOp& copyop); | ||||
| 
 | ||||
|         /// @param mask This mask is compared with the current Camera's cull mask to determine if lighting is desired.
 | ||||
|         /// By default, it's ~0u i.e. always on.
 | ||||
|         /// If you have some views that do not require lighting, then set the Camera's cull mask to not include
 | ||||
|         /// the lightingMask for a much faster cull and rendering.
 | ||||
|         void setLightingMask (size_t mask); | ||||
|         size_t getLightingMask() const; | ||||
| 
 | ||||
|         /// Set the first light index that should be used by this manager, typically the number of directional lights in the scene.
 | ||||
|         void setStartLight(int start); | ||||
|         int getStartLight() const; | ||||
| 
 | ||||
|         /// Internal use only, called automatically by the LightManager's UpdateCallback
 | ||||
|         void update(); | ||||
| 
 | ||||
|         /// Internal use only, called automatically by the LightSource's UpdateCallback
 | ||||
|         void addLight(LightSource* lightSource, const osg::Matrixf& worldMat, size_t frameNum); | ||||
| 
 | ||||
|         const std::vector<LightSourceTransform>& getLights() const; | ||||
| 
 | ||||
|         const std::vector<LightSourceViewBound>& getLightsInViewSpace(osg::Camera* camera, const osg::RefMatrix* viewMatrix, size_t frameNum); | ||||
| 
 | ||||
|         osg::ref_ptr<osg::StateSet> getLightListStateSet(const LightList& lightList, size_t frameNum); | ||||
| 
 | ||||
|         void setSunlight(osg::ref_ptr<osg::Light> sun); | ||||
|         osg::ref_ptr<osg::Light> getSunlight(); | ||||
| 
 | ||||
|         osg::ref_ptr<SunlightBuffer> getSunBuffer(); | ||||
| 
 | ||||
|         bool usingFFP() const; | ||||
| 
 | ||||
|         int getMaxLights() const; | ||||
|         int getMaxLightsInScene() const; | ||||
| 
 | ||||
|         Shader::ShaderManager::DefineMap getLightDefines() const; | ||||
| 
 | ||||
|     private: | ||||
|         // Lights collected from the scene graph. Only valid during the cull traversal.
 | ||||
|  | @ -144,7 +179,14 @@ namespace SceneUtil | |||
| 
 | ||||
|         int mStartLight; | ||||
| 
 | ||||
|         unsigned int mLightingMask; | ||||
|         size_t mLightingMask; | ||||
| 
 | ||||
|         osg::ref_ptr<osg::Light> mSun; | ||||
|         osg::ref_ptr<SunlightBuffer> mSunBuffer; | ||||
| 
 | ||||
|         bool mFFP; | ||||
| 
 | ||||
|         static constexpr int mFFPMaxLights = 8; | ||||
|     }; | ||||
| 
 | ||||
|     /// To receive lighting, objects must be decorated by a LightListCallback. Light list callbacks must be added via
 | ||||
|  | @ -180,7 +222,7 @@ namespace SceneUtil | |||
| 
 | ||||
|     private: | ||||
|         LightManager* mLightManager; | ||||
|         unsigned int mLastFrameNumber; | ||||
|         size_t mLastFrameNumber; | ||||
|         LightManager::LightList mLightList; | ||||
|         std::set<SceneUtil::LightSource*> mIgnoredLightSources; | ||||
|     }; | ||||
|  |  | |||
|  | @ -9,12 +9,20 @@ | |||
| #include <boost/filesystem/path.hpp> | ||||
| #include <boost/filesystem/fstream.hpp> | ||||
| 
 | ||||
| #include <components/sceneutil/lightmanager.hpp> | ||||
| #include <components/resource/scenemanager.hpp> | ||||
| #include <components/debug/debuglog.hpp> | ||||
| #include <components/misc/stringops.hpp> | ||||
| 
 | ||||
| namespace Shader | ||||
| { | ||||
| 
 | ||||
|     ShaderManager::ShaderManager(Resource::SceneManager* sceneManager) | ||||
|         : mSceneManager(sceneManager) | ||||
|     { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     void ShaderManager::setShaderPath(const std::string &path) | ||||
|     { | ||||
|         mPath = path; | ||||
|  | @ -344,6 +352,11 @@ namespace Shader | |||
|             program->addShader(fragmentShader); | ||||
|             program->addBindAttribLocation("aOffset", 6); | ||||
|             program->addBindAttribLocation("aRotation", 7); | ||||
|             if (!mSceneManager->getFFPLighting()) | ||||
|             { | ||||
|                 program->addBindUniformBlock("PointLightBuffer", 8); | ||||
|                 program->addBindUniformBlock("SunlightBuffer", 9); | ||||
|             } | ||||
|             found = mPrograms.insert(std::make_pair(std::make_pair(vertexShader, fragmentShader), program)).first; | ||||
|         } | ||||
|         return found->second; | ||||
|  |  | |||
|  | @ -11,6 +11,11 @@ | |||
| 
 | ||||
| #include <osgViewer/Viewer> | ||||
| 
 | ||||
| namespace Resource | ||||
| { | ||||
|     class SceneManager; | ||||
| } | ||||
| 
 | ||||
| namespace Shader | ||||
| { | ||||
| 
 | ||||
|  | @ -19,6 +24,9 @@ namespace Shader | |||
|     class ShaderManager | ||||
|     { | ||||
|     public: | ||||
| 
 | ||||
|         ShaderManager(Resource::SceneManager* sceneManager); | ||||
| 
 | ||||
|         void setShaderPath(const std::string& path); | ||||
| 
 | ||||
|         typedef std::map<std::string, std::string> DefineMap; | ||||
|  | @ -59,6 +67,8 @@ namespace Shader | |||
|         typedef std::map<std::pair<osg::ref_ptr<osg::Shader>, osg::ref_ptr<osg::Shader> >, osg::ref_ptr<osg::Program> > ProgramMap; | ||||
|         ProgramMap mPrograms; | ||||
| 
 | ||||
|         Resource::SceneManager* mSceneManager; | ||||
| 
 | ||||
|         std::mutex mMutex; | ||||
|     }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -442,6 +442,11 @@ apply lighting to environment maps = false | |||
| # This makes fogging independent from the viewing angle. Shaders will be used to render all objects. | ||||
| radial fog = false | ||||
| 
 | ||||
| # Set maximum number of lights per object, does not include the sun.  | ||||
| # This feature may not work on your device, in which case it will fall back to the previous OpenGL limit of 8 lights.  | ||||
| # "[Shaders]/clamp lighting" must be set to 'false' and "[Shaders]/force shaders" must be set to 'true' for this to take effect.  | ||||
| max lights = 16 | ||||
| 
 | ||||
| [Input] | ||||
| 
 | ||||
| # Capture control of the cursor prevent movement outside the window. | ||||
|  |  | |||
|  | @ -25,6 +25,7 @@ set(SHADER_FILES | |||
|     shadowcasting_vertex.glsl | ||||
|     shadowcasting_fragment.glsl | ||||
|     vertexcolors.glsl | ||||
|     sun.glsl | ||||
| ) | ||||
| 
 | ||||
| copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_SHADERS_ROOT} ${DDIRRELATIVE} "${SHADER_FILES}") | ||||
|  |  | |||
|  | @ -1,4 +1,5 @@ | |||
| #version 120 | ||||
| #extension GL_ARB_uniform_buffer_object : enable | ||||
| 
 | ||||
| #define GROUNDCOVER | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| #version 120 | ||||
| 
 | ||||
| #extension GL_ARB_uniform_buffer_object : enable | ||||
| 
 | ||||
| #define GROUNDCOVER | ||||
| 
 | ||||
| attribute vec4 aOffset; | ||||
|  |  | |||
|  | @ -1,13 +1,62 @@ | |||
| #define MAX_LIGHTS 8 | ||||
| #if !@ffpLighting | ||||
| 
 | ||||
| void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 viewPos, vec3 viewNormal) | ||||
| #include "sun.glsl" | ||||
| 
 | ||||
| #define getLight PointLights | ||||
| 
 | ||||
| struct PointLight | ||||
| { | ||||
|     vec3 lightDir = gl_LightSource[lightIndex].position.xyz - viewPos * gl_LightSource[lightIndex].position.w; | ||||
|     vec4 diffuse; | ||||
|     vec4 ambient; | ||||
|     vec4 position; | ||||
|     vec4 attenuation; | ||||
| }; | ||||
| 
 | ||||
| uniform mat4 osg_ViewMatrix; | ||||
| uniform int PointLightCount; | ||||
| uniform int PointLightIndex[@maxLights]; | ||||
| 
 | ||||
| layout(std140) uniform PointLightBuffer | ||||
| { | ||||
|     PointLight PointLights[@maxLights]; | ||||
| }; | ||||
| 
 | ||||
| #else | ||||
| #define getLight gl_LightSource | ||||
| #endif | ||||
| 
 | ||||
| void perLightSun(out vec3 ambientOut, out vec3 diffuseOut, vec3 viewPos, vec3 viewNormal) | ||||
| { | ||||
|     vec3 lightDir = @sunDirection.xyz; | ||||
|     lightDir = normalize(lightDir); | ||||
| 
 | ||||
|     ambientOut = @sunAmbient.xyz; | ||||
| 
 | ||||
|     float lambert = dot(viewNormal.xyz, lightDir); | ||||
| #ifndef GROUNDCOVER | ||||
|     lambert = max(lambert, 0.0); | ||||
| #else | ||||
|     float eyeCosine = dot(normalize(viewPos), viewNormal.xyz); | ||||
|     if (lambert < 0.0) | ||||
|     { | ||||
|         lambert = -lambert; | ||||
|         eyeCosine = -eyeCosine; | ||||
|     } | ||||
|     lambert *= clamp(-8.0 * (1.0 - 0.3) * eyeCosine + 1.0, 0.3, 1.0); | ||||
| #endif | ||||
|     diffuseOut = @sunDiffuse.xyz * lambert; | ||||
| } | ||||
| 
 | ||||
| void perLightPoint(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 viewPos, vec3 viewNormal) | ||||
| { | ||||
|     vec3 lightDir = getLight[lightIndex].position.xyz - viewPos; | ||||
|     //vec3 lightDir = (osg_ViewMatrix * vec4(getLight[lightIndex].position, 1.0)).xyz - viewPos; | ||||
| 
 | ||||
|     float lightDistance = length(lightDir); | ||||
|     lightDir = normalize(lightDir); | ||||
|     float illumination = clamp(1.0 / (gl_LightSource[lightIndex].constantAttenuation + gl_LightSource[lightIndex].linearAttenuation * lightDistance + gl_LightSource[lightIndex].quadraticAttenuation * lightDistance * lightDistance), 0.0, 1.0); | ||||
| 
 | ||||
|     ambientOut = gl_LightSource[lightIndex].ambient.xyz * illumination; | ||||
|     float illumination = clamp(1.0 / (getLight[lightIndex].attenuation.x + getLight[lightIndex].attenuation.y * lightDistance + getLight[lightIndex].attenuation.z * lightDistance * lightDistance), 0.0, 1.0); | ||||
|     ambientOut = getLight[lightIndex].ambient.xyz * illumination; | ||||
| 
 | ||||
|     float lambert = dot(viewNormal.xyz, lightDir) * illumination; | ||||
| #ifndef GROUNDCOVER | ||||
|  | @ -21,7 +70,7 @@ void perLight(out vec3 ambientOut, out vec3 diffuseOut, int lightIndex, vec3 vie | |||
|     } | ||||
|     lambert *= clamp(-8.0 * (1.0 - 0.3) * eyeCosine + 1.0, 0.3, 1.0); | ||||
| #endif | ||||
|     diffuseOut = gl_LightSource[lightIndex].diffuse.xyz * lambert; | ||||
|     diffuseOut = getLight[lightIndex].diffuse.xyz * lambert; | ||||
| } | ||||
| 
 | ||||
| #if PER_PIXEL_LIGHTING | ||||
|  | @ -32,7 +81,8 @@ void doLighting(vec3 viewPos, vec3 viewNormal, out vec3 diffuseLight, out vec3 a | |||
| { | ||||
|     vec3 ambientOut, diffuseOut; | ||||
|     // This light gets added a second time in the loop to fix Mesa users' slowdown, so we need to negate its contribution here. | ||||
|     perLight(ambientOut, diffuseOut, 0, viewPos, viewNormal); | ||||
|     perLightSun(ambientOut, diffuseOut, viewPos, viewNormal); | ||||
| 
 | ||||
| #if PER_PIXEL_LIGHTING | ||||
|     diffuseLight = diffuseOut * shadowing - diffuseOut; | ||||
| #else | ||||
|  | @ -40,22 +90,31 @@ void doLighting(vec3 viewPos, vec3 viewNormal, out vec3 diffuseLight, out vec3 a | |||
|     diffuseLight = -diffuseOut; | ||||
| #endif | ||||
|     ambientLight = gl_LightModel.ambient.xyz; | ||||
|     for (int i=0; i<MAX_LIGHTS; ++i) | ||||
| 
 | ||||
| #if !@ffpLighting | ||||
|     perLightSun(ambientOut, diffuseOut, viewPos, viewNormal); | ||||
|     ambientLight += ambientOut; | ||||
|     diffuseLight += diffuseOut; | ||||
|     for (int i=0; i<PointLightCount; ++i) | ||||
|     { | ||||
|         perLight(ambientOut, diffuseOut, i, viewPos, viewNormal); | ||||
|         perLightPoint(ambientOut, diffuseOut, i, viewPos, viewNormal); | ||||
| #else | ||||
|     for (int i=0; i<@maxLights; ++i) | ||||
|     { | ||||
|         perLightPoint(ambientOut, diffuseOut, i, viewPos, viewNormal); | ||||
| #endif | ||||
|         ambientLight += ambientOut; | ||||
|         diffuseLight += diffuseOut; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| vec3 getSpecular(vec3 viewNormal, vec3 viewDirection, float shininess, vec3 matSpec) | ||||
| { | ||||
|     vec3 lightDir = normalize(gl_LightSource[0].position.xyz); | ||||
|     vec3 lightDir = normalize(@sunDirection.xyz); | ||||
|     float NdotL = dot(viewNormal, lightDir); | ||||
|     if (NdotL <= 0.0) | ||||
|         return vec3(0.0); | ||||
|     vec3 halfVec = normalize(lightDir - viewDirection); | ||||
|     float NdotH = dot(viewNormal, halfVec); | ||||
|     return pow(max(NdotH, 0.0), max(1e-4, shininess)) * gl_LightSource[0].specular.xyz * matSpec; | ||||
|     return pow(max(NdotH, 0.0), max(1e-4, shininess)) * @sunSpecular.xyz * matSpec; | ||||
| } | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| #version 120 | ||||
| 
 | ||||
| #extension GL_ARB_uniform_buffer_object : enable | ||||
| 
 | ||||
| #if @diffuseMap | ||||
| uniform sampler2D diffuseMap; | ||||
| varying vec2 diffuseMapUV; | ||||
|  | @ -66,8 +68,8 @@ varying vec3 passNormal; | |||
| 
 | ||||
| #include "vertexcolors.glsl" | ||||
| #include "shadows_fragment.glsl" | ||||
| #include "lighting.glsl" | ||||
| #include "parallax.glsl" | ||||
| #include "lighting.glsl" | ||||
| 
 | ||||
| void main() | ||||
| { | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| #version 120 | ||||
| 
 | ||||
| #extension GL_ARB_uniform_buffer_object : enable | ||||
| 
 | ||||
| #if @diffuseMap | ||||
| varying vec2 diffuseMapUV; | ||||
| #endif | ||||
|  | @ -51,7 +53,6 @@ varying vec3 passNormal; | |||
| 
 | ||||
| #include "vertexcolors.glsl" | ||||
| #include "shadows_vertex.glsl" | ||||
| 
 | ||||
| #include "lighting.glsl" | ||||
| 
 | ||||
| void main(void) | ||||
|  |  | |||
							
								
								
									
										14
									
								
								files/shaders/sun.glsl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								files/shaders/sun.glsl
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| #if !@ffpLighting | ||||
| struct Sunlight | ||||
| { | ||||
|     vec4 diffuse; | ||||
|     vec4 ambient; | ||||
|     vec4 specular; | ||||
|     vec4 direction; | ||||
| }; | ||||
| 
 | ||||
| layout(std140) uniform SunlightBuffer | ||||
| { | ||||
|     Sunlight Sun; | ||||
| }; | ||||
| #endif | ||||
|  | @ -1,5 +1,7 @@ | |||
| #version 120 | ||||
| 
 | ||||
| #extension GL_ARB_uniform_buffer_object : enable | ||||
| 
 | ||||
| varying vec2 uv; | ||||
| 
 | ||||
| uniform sampler2D diffuseMap; | ||||
|  | @ -26,8 +28,8 @@ varying vec3 passNormal; | |||
| 
 | ||||
| #include "vertexcolors.glsl" | ||||
| #include "shadows_fragment.glsl" | ||||
| #include "lighting.glsl" | ||||
| #include "parallax.glsl" | ||||
| #include "lighting.glsl" | ||||
| 
 | ||||
| void main() | ||||
| { | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| #version 120 | ||||
| 
 | ||||
| #extension GL_ARB_uniform_buffer_object : enable | ||||
| 
 | ||||
| varying vec2 uv; | ||||
| varying float euclideanDepth; | ||||
| varying float linearDepth; | ||||
|  | @ -15,7 +17,6 @@ varying vec3 passNormal; | |||
| 
 | ||||
| #include "vertexcolors.glsl" | ||||
| #include "shadows_vertex.glsl" | ||||
| 
 | ||||
| #include "lighting.glsl" | ||||
| 
 | ||||
| void main(void) | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| #version 120 | ||||
| 
 | ||||
| #extension GL_ARB_uniform_buffer_object : enable | ||||
| 
 | ||||
| #define REFRACTION @refraction_enabled | ||||
| 
 | ||||
| // Inspired by Blender GLSL Water by martinsh ( https://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) | ||||
|  | @ -143,6 +145,7 @@ uniform vec3 nodePosition; | |||
| uniform float rainIntensity; | ||||
| 
 | ||||
| #include "shadows_fragment.glsl" | ||||
| #include "sun.glsl" | ||||
| 
 | ||||
| float frustumDepth; | ||||
| 
 | ||||
|  | @ -192,7 +195,7 @@ void main(void) | |||
|                    normal3 * midWaves.y + normal4 * smallWaves.x + normal5 * smallWaves.y + rippleAdd); | ||||
|     normal = normalize(vec3(-normal.x * bump, -normal.y * bump, normal.z)); | ||||
| 
 | ||||
|     vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(gl_LightSource[0].position.xyz, 0.0)).xyz); | ||||
|     vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(@sunDirection.xyz, 0.0)).xyz); | ||||
| 
 | ||||
|     vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0,0,0,1)).xyz; | ||||
|     vec3 vVec = normalize(position.xyz - cameraPos.xyz); | ||||
|  | @ -247,11 +250,11 @@ void main(void) | |||
|     vec3 scatterColour = mix(SCATTER_COLOUR*vec3(1.0,0.4,0.0), SCATTER_COLOUR, clamp(1.0-exp(-sunHeight*SUN_EXT), 0.0, 1.0)); | ||||
|     vec3 lR = reflect(lVec, lNormal); | ||||
|     float lightScatter = clamp(dot(lVec,lNormal)*0.7+0.3, 0.0, 1.0) * clamp(dot(lR, vVec)*2.0-1.2, 0.0, 1.0) * SCATTER_AMOUNT * sunFade * clamp(1.0-exp(-sunHeight), 0.0, 1.0); | ||||
|     gl_FragData[0].xyz = mix( mix(refraction,  scatterColour,  lightScatter),  reflection,  fresnel) + specular * gl_LightSource[0].specular.xyz + vec3(rainRipple.w) * 0.2; | ||||
|     gl_FragData[0].xyz = mix( mix(refraction,  scatterColour,  lightScatter),  reflection,  fresnel) + specular * @sunSpecular.xyz + vec3(rainRipple.w) * 0.2; | ||||
|     gl_FragData[0].w = 1.0; | ||||
| #else | ||||
|     gl_FragData[0].xyz = mix(reflection,  waterColor,  (1.0-fresnel)*0.5) + specular * gl_LightSource[0].specular.xyz + vec3(rainRipple.w) * 0.7; | ||||
|     gl_FragData[0].w = clamp(fresnel*6.0 + specular * gl_LightSource[0].specular.w, 0.0, 1.0);     //clamp(fresnel*2.0 + specular * gl_LightSource[0].specular.w, 0.0, 1.0); | ||||
|     gl_FragData[0].xyz = mix(reflection,  waterColor,  (1.0-fresnel)*0.5) + specular * @sunSpecular.xyz + vec3(rainRipple.w) * 0.7; | ||||
|     gl_FragData[0].w = clamp(fresnel*6.0 + specular * @sunSpecular.w, 0.0, 1.0);     //clamp(fresnel*2.0 + specular * gl_LightSource[0].specular.w, 0.0, 1.0); | ||||
| #endif | ||||
| 
 | ||||
|     // fog | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue