#include #include #include #include #include #include #include #include #include #include "GameData.h" #include "Components.h" #include "WaterModule.h" #include namespace ECS { #if 0 class WaterPhysicsAction : public btActionInterface { btPairCachingGhostObject *mWaterBody; btManifoldArray mManifoldArray; public: btVector3 mShapeAabbMin, mShapeAabbMax; btGjkEpaPenetrationDepthSolver *gjk_epa_pen_solver; btVoronoiSimplexSolver *gjk_simplex_solver; struct contact { const btCollisionObject *body; float mDistance; btVector3 mNormal; btVector3 mPoint; bool mHasResult; }; std::vector mContacts; std::set mInWater; WaterPhysicsAction(btPairCachingGhostObject *waterBody) : btActionInterface() , mWaterBody(waterBody) , mShapeAabbMin(0, 0, 0) , mShapeAabbMax(0, 0, 0) , gjk_epa_pen_solver(OGRE_NEW btGjkEpaPenetrationDepthSolver) , gjk_simplex_solver(OGRE_NEW btVoronoiSimplexSolver) { mManifoldArray.reserve(160); mManifoldArray.resize(0); setupBody(); } ~WaterPhysicsAction() { } void updateAction(btCollisionWorld *collisionWorld, btScalar deltaTimeStep) override; void debugDraw(btIDebugDraw *debugDrawer) override; void setupBody(); bool isInWater(const btCollisionObject *body) const { return (mInWater.find(body) != mInWater.end()); } }; #endif static const uint32_t WATER_MASK = 0xF00; static bool debugEnabled = false; WaterModule::WaterModule(flecs::world &ecs) { ecs.module(); ecs.component(); ecs.component().add(flecs::Singleton); ecs.component().add(flecs::Singleton); ecs.component().add(flecs::Singleton); ecs.component() .on_add([](flecs::entity e, WaterSurface &water) { water.mAbove = false; water.mDepthMaterial = nullptr; water.mDepthTech = nullptr; water.mInRefTexUpdate = false; water.mReflectionCamera = nullptr; water.mReflectionCameraNode = nullptr; water.mReflectionDepthCamera = nullptr; water.mReflectionTexture = nullptr; water.mRefractionCamera = nullptr; water.mRefractionCameraNode = nullptr; water.mRefractionDepthCamera = nullptr; water.mWaterEnt = nullptr; water.mWaterNode = nullptr; const EngineData &eng = ECS::get(); const Camera &camera = ECS::get(); std::cout << "Water setup\n"; water.mDepthMaterial = Ogre::MaterialManager::getSingleton().getByName( "Water/Depth"); OgreAssert(water.mDepthMaterial, "Water Depth material not found."); water.mDepthMaterial->load(); water.mDepthTech = water.mDepthMaterial->getBestTechnique(); OgreAssert(water.mDepthTech, "Bad material technique"); water.mAbove = false; water.mInRefTexUpdate = false; water.mRenderTargetListener.mSurface = &water; const Ogre::String renderTargetName = "ReflectionRefractionTexture"; water.mWaterPlane = Ogre::Plane(Ogre::Vector3::UNIT_Y, 0); water.mReflectionPlane = Ogre::Plane(Ogre::Vector3(0.0, 1.0, 0.0), 0.5f /* water height */); float h = 0.0f; water.mReflectionClipPlaneAbove = Ogre::Plane(Ogre::Vector3(0.0, 1.0, 0.0), -h); water.mReflectionClipPlaneBelow = Ogre::Plane(Ogre::Vector3(0.0, -1.0, 0.0), h); water.mRefractionClipPlaneAbove = Ogre::Plane(Ogre::Vector3(0.0, -1.0, 0.0), h); water.mRefractionClipPlaneBelow = Ogre::Plane(Ogre::Vector3(0.0, 1.0, 0.0), -h); Ogre::TexturePtr reflectionTexture = Ogre::TextureManager::getSingleton().createManual( renderTargetName, Ogre::ResourceGroupManager:: DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 512, 512, 0, Ogre::PF_R8G8B8A8, Ogre::TU_RENDERTARGET); Ogre::MaterialPtr debug_mat = Ogre::MaterialManager::getSingleton().getByName( "Water/Debug", "Water"); if (!debug_mat) { debug_mat = Ogre::MaterialManager::getSingleton() .create("Water/Debug", "Water"); Ogre::Technique *tech = debug_mat->getTechnique(0); Ogre::Pass *pass = tech->getPass(0); pass->setLightingEnabled(false); pass->setAmbient(Ogre::ColourValue(1, 1, 1, 1)); pass->setDiffuse(Ogre::ColourValue(0.0f, 0.2f, 0.5f, 1.0f)); pass->setDepthCheckEnabled(false); pass->setDepthWriteEnabled(false); pass->setAlphaRejectFunction( Ogre::CMPF_ALWAYS_PASS); pass->setCullingMode(Ogre::CULL_NONE); pass->setManualCullingMode( Ogre::MANUAL_CULL_NONE); Ogre::TextureUnitState *texture_unit = pass->createTextureUnitState(); texture_unit->setTextureName( "ReflectionRefractionTexture"); Ogre::Sampler::UVWAddressingMode uvw; uvw.u = Ogre::TextureUnitState::TAM_MIRROR; uvw.v = Ogre::TextureUnitState::TAM_MIRROR; uvw.w = Ogre::TextureUnitState::TAM_MIRROR; texture_unit->setTextureAddressingMode(uvw); texture_unit->setTextureFiltering( Ogre::FT_MIN, Ogre::FO_LINEAR); texture_unit->setTextureFiltering( Ogre::FT_MAG, Ogre::FO_LINEAR); texture_unit->setTextureFiltering( Ogre::FT_MIP, Ogre::FO_LINEAR); } // create a frosted screen in front of the camera, using our dynamic texture to "thaw" certain areas if (debugEnabled) { Ogre::Entity *ent = eng.mScnMgr->createEntity( "WaterDebugPlane", Ogre::SceneManager::PT_PLANE); ent->setMaterialName("Water/Debug", "Water"); ent->setVisibilityFlags(WATER_MASK); Ogre::SceneNode *node = camera.mCameraNode ->createChildSceneNode(); node->setPosition(-150, 60, -400); node->attachObject(ent); } water.mReflectionTexture = reflectionTexture->getBuffer() ->getRenderTarget(); water.mReflectionTexture->setAutoUpdated(false); water.mWaterNode = eng.mScnMgr->getRootSceneNode() ->createChildSceneNode("Water"); Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().getByName( "Water/Above", "Water"); if (!mat) { mat = Ogre::MaterialManager::getSingleton() .create("Water/Above", "Water"); Ogre::Technique *tech = mat->getTechnique(0); Ogre::Pass *pass = tech->getPass(0); pass->setLightingEnabled(true); pass->setAmbient(Ogre::ColourValue(1, 1, 1, 1)); pass->setDiffuse(Ogre::ColourValue(0.0f, 0.2f, 0.5f, 1.0f)); pass->setCullingMode(Ogre::CULL_NONE); pass->setManualCullingMode( Ogre::MANUAL_CULL_NONE); pass->setVertexProgram("Water/water_vp"); pass->setFragmentProgram("Water/water_fp"); Ogre::TextureUnitState *texture_unit = pass->createTextureUnitState(); texture_unit->setTextureName( "ReflectionRefractionTexture"); Ogre::Sampler::UVWAddressingMode uvw; uvw.u = Ogre::TextureUnitState::TAM_MIRROR; uvw.v = Ogre::TextureUnitState::TAM_MIRROR; uvw.w = Ogre::TextureUnitState::TAM_MIRROR; texture_unit->setTextureAddressingMode(uvw); texture_unit->setTextureFiltering( Ogre::FT_MIN, Ogre::FO_LINEAR); texture_unit->setTextureFiltering( Ogre::FT_MAG, Ogre::FO_LINEAR); texture_unit->setTextureFiltering( Ogre::FT_MIP, Ogre::FO_LINEAR); Ogre::TextureUnitState *texture_unit2 = pass->createTextureUnitState(); texture_unit2->setTextureName("waves2.png"); texture_unit2->setTextureAddressingMode(uvw); texture_unit2->setTextureFiltering( Ogre::FT_MIN, Ogre::FO_LINEAR); texture_unit2->setTextureFiltering( Ogre::FT_MAG, Ogre::FO_LINEAR); texture_unit2->setTextureFiltering( Ogre::FT_MIP, Ogre::FO_LINEAR); } mat->load(); mat->setReceiveShadows(false); /* auto mat2 = Ogre::MaterialManager::getSingleton() .getByName("Water/Below"); mat2->load(); mat2->setReceiveShadows(false); */ Ogre::Vector3 cameraPosition = camera.mCameraNode->getPosition(); water.mWaterEnt = eng.mScnMgr->createEntity("Ocean", "sea.glb"); water.mWaterEnt->setVisibilityFlags(WATER_MASK); water.mWaterEnt->setCastShadows(true); // water.mWaterEnt->setMaterialName("Water/Above"); water.mWaterEnt->setMaterial(mat); water.mWaterNode->attachObject(water.mWaterEnt); // mDynWorld->attachCollisionObject( // mWaterBody, water_ent, 1, 0x7FFFFFFF); water.mReflectionTexture->addListener( &water.mRenderTargetListener); water.mReflectionCamera = eng.mScnMgr->createCamera("ReflectionCamera"); water.mReflectionDepthCamera = eng.mScnMgr->createCamera( "ReflectionDepthCamera"); water.mReflectionCameraNode = camera.mCamera->getParentSceneNode() ->createChildSceneNode( "ReflectionCameraNode"); water.mReflectionCameraNode->setPosition( Ogre::Vector3(0, 1.0f, 0)); water.mReflectionCameraNode->attachObject( water.mReflectionCamera); water.mReflectionCameraNode->attachObject( water.mReflectionDepthCamera); water.mReflectionCamera->setAspectRatio( camera.mCamera->getAspectRatio()); water.mReflectionCamera->setNearClipDistance( camera.mCamera->getNearClipDistance()); water.mReflectionCamera->setFarClipDistance( Ogre::Math::Clamp( camera.mCamera->getFarClipDistance(), 10.0f, 10.0f)); water.mReflectionCamera->enableCustomNearClipPlane( water.mReflectionClipPlaneAbove); water.mReflectionCamera->enableReflection( water.mReflectionPlane); water.mReflectionDepthCamera->setAspectRatio( camera.mCamera->getAspectRatio()); water.mReflectionDepthCamera->setNearClipDistance( camera.mCamera->getNearClipDistance()); water.mReflectionDepthCamera->setFarClipDistance( camera.mCamera->getFarClipDistance()); water.mReflectionDepthCamera->enableCustomNearClipPlane( water.mReflectionClipPlaneAbove); water.mReflectionDepthCamera->enableReflection( water.mReflectionPlane); Ogre::Viewport *reflectionViewport = water.mReflectionTexture->addViewport( water.mReflectionCamera, 0, 0, 0, 0.5f, 0.5f); reflectionViewport->setClearEveryFrame(true); reflectionViewport->setBackgroundColour( Ogre::ColourValue(0.0, 0.0, 1.0, 1.0)); reflectionViewport->setOverlaysEnabled(false); reflectionViewport->setSkiesEnabled(true); reflectionViewport->setAutoUpdated(false); reflectionViewport->setVisibilityMask(~WATER_MASK); water.mViewports[0] = reflectionViewport; Ogre::Viewport *reflectionDepthViewport = water.mReflectionTexture->addViewport( water.mReflectionDepthCamera, 2, 0, 0.5f, 0.5f, 0.5f); reflectionDepthViewport->setClearEveryFrame(true); reflectionDepthViewport->setBackgroundColour( Ogre::ColourValue(0.0, 0.0, 0.0, 0.0)); reflectionDepthViewport->setOverlaysEnabled(false); reflectionDepthViewport->setSkiesEnabled(true); reflectionDepthViewport->setAutoUpdated(false); reflectionDepthViewport->setVisibilityMask(~WATER_MASK); water.mViewports[2] = reflectionDepthViewport; water.mRefractionCamera = eng.mScnMgr->createCamera("RefractionCamera"); water.mRefractionDepthCamera = eng.mScnMgr->createCamera( "RefractionDepthCamera"); water.mRefractionCameraNode = camera.mCamera->getParentSceneNode() ->createChildSceneNode( "RefractionCameraNode"); water.mRefractionCameraNode->attachObject( water.mRefractionCamera); water.mRefractionCameraNode->attachObject( water.mRefractionDepthCamera); water.mRefractionCamera->setAspectRatio( camera.mCamera->getAspectRatio()); water.mRefractionCamera->setNearClipDistance( camera.mCamera->getNearClipDistance()); water.mRefractionCamera->setFarClipDistance( Ogre::Math::Clamp( camera.mCamera->getFarClipDistance(), 1.0f, 10.0f)); water.mRefractionCamera->enableCustomNearClipPlane( water.mRefractionClipPlaneAbove); water.mRefractionDepthCamera->setAspectRatio( camera.mCamera->getAspectRatio()); water.mRefractionDepthCamera->setNearClipDistance( camera.mCamera->getNearClipDistance()); water.mRefractionDepthCamera->setFarClipDistance( camera.mCamera->getFarClipDistance()); water.mRefractionDepthCamera->enableCustomNearClipPlane( water.mRefractionClipPlaneAbove); Ogre::Viewport *refractionViewport = water.mReflectionTexture->addViewport( water.mRefractionCamera, 1, 0.5, 0, 0.5f, 0.5f); refractionViewport->setClearEveryFrame(true); refractionViewport->setBackgroundColour( Ogre::ColourValue(0.0, 0.5, 1.0, 1.0)); refractionViewport->setOverlaysEnabled(false); refractionViewport->setSkiesEnabled(false); refractionViewport->setAutoUpdated(false); refractionViewport->setVisibilityMask(~WATER_MASK); water.mViewports[1] = refractionViewport; Ogre::Viewport *refractionDepthViewport = water.mReflectionTexture->addViewport( water.mRefractionDepthCamera, 3, 0.5, 0.5, 0.5f, 0.5f); refractionDepthViewport->setClearEveryFrame(true); refractionDepthViewport->setBackgroundColour( Ogre::ColourValue(0.0, 0.0, 0.0, 0.0)); refractionDepthViewport->setOverlaysEnabled(false); refractionDepthViewport->setSkiesEnabled(false); refractionDepthViewport->setAutoUpdated(false); refractionDepthViewport->setVisibilityMask(~WATER_MASK); water.mViewports[3] = refractionDepthViewport; water.mRenderTargetListener.mInDepth = false; eng.mScnMgr->getRenderQueue()->setRenderableListener( &water.mRenderTargetListener); std::cout << "Water setup done\n"; ECS::get().add(); }) .on_remove([](flecs::entity e, WaterSurface &water) { const Ogre::String renderTargetName = "ReflectionRefractionTexture"; ECS::get() .mScnMgr->getRenderQueue() ->setRenderableListener(nullptr); water.mReflectionTexture->removeAllViewports(); ECS::get().mScnMgr->destroyCamera( water.mRefractionCamera); ECS::get().mScnMgr->destroyCamera( water.mRefractionDepthCamera); ECS::get().mScnMgr->destroyCamera( water.mReflectionCamera); ECS::get().mScnMgr->destroyCamera( water.mReflectionDepthCamera); Ogre::TextureManager::getSingleton().remove( renderTargetName); water.mWaterNode->destroyAllChildrenAndObjects(); ECS::get().mScnMgr->destroySceneNode( water.mWaterNode); Ogre::MaterialManager::getSingleton().remove( "Water/Depth"); Ogre::MaterialManager::getSingleton().remove( "Water/Above"); }) .add(flecs::Singleton); ecs.system( "UpdateWaterPosition") .kind(flecs::OnUpdate) .with() .interval(0.3f) .each([](const EngineData &eng, const Camera &camera, WaterSurface &water) { ZoneScopedN("UpdateWaterPosition"); float delta = eng.delta; Ogre::Vector3 mCameraPos = camera.mCameraNode->_getDerivedPosition(); Ogre::Vector3 waterPos = water.mWaterNode->_getDerivedPosition(); mCameraPos.y = 0; waterPos.y = 0; Ogre::Vector3 d = mCameraPos - waterPos; if (d.squaredLength() < 100.0f * 100.0f) water.mWaterNode->translate(d * 3.0f * delta); else water.mWaterNode->translate(d); }); ecs.system("UpdateWater") .kind(flecs::OnUpdate) .with() .each([](WaterSurface &water) { static int updateViewport = 0; ZoneScopedN("UpdateWaterRender"); water.mViewports[updateViewport++]->update(); if (updateViewport > 1) updateViewport = 0; }); } struct shapeParams { float offsetX, offsetY, offsetZ; float boxX, boxY, boxZ; }; static struct shapeParams childShapes[] = { { 0.0f, 0.0f, 0.0f, 100.0f, 100.0f, 100.0f }, }; void WaterSurface::RenderTextureListener::preRenderTargetUpdate( const Ogre::RenderTargetEvent &evt) { int i; if (evt.source == mSurface->mReflectionTexture) { mSurface->mWaterEnt->setVisible(false); if (evt.source == mSurface->mReflectionTexture) mSurface->mInRefTexUpdate = true; } else { mSurface->mWaterEnt->setVisible(true); mSurface->mInRefTexUpdate = false; } } void WaterSurface::RenderTextureListener::postRenderTargetUpdate( const Ogre::RenderTargetEvent &evt) { int i; mSurface->mWaterEnt->setVisible(true); mSurface->mInRefTexUpdate = false; } bool WaterSurface::RenderTextureListener::renderableQueued( Ogre::Renderable *rend, Ogre::uint8 groupID, ushort priority, Ogre::Technique **ppTech, Ogre::RenderQueue *pQueue) { if (mInDepth) *ppTech = mSurface->mDepthTech; return true; } }