#include #include #include #include #include #include #include #include #include #include "GameData.h" #include "Components.h" #include "WaterModule.h" 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); #if 0 if (Ogre::TextureManager::getSingleton() .resourceExists(renderTargetName)) Ogre::TextureManager::getSingleton() .remove(renderTargetName); #endif 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"); #if 0 Ogre::GpuProgramPtr water_vp = Ogre::GpuProgramManager::getSingleton() .getByName( "Water/water_vp", Ogre::RGN_AUTODETECT); OgreAssert(water_vp != nullptr, "VP failed"); pass->setGpuProgram( Ogre::GPT_VERTEX_PROGRAM, water_vp); OgreAssert(water_vp->isSupported(), "VP not supported"); Ogre::GpuProgramPtr water_fp = Ogre::GpuProgramManager::getSingleton() .getByName( "Water/water_fp", Ogre::RGN_AUTODETECT); OgreAssert(water_vp != nullptr, "FP failed"); pass->setGpuProgram( Ogre::GPT_FRAGMENT_PROGRAM, water_fp); OgreAssert(water_fp->isSupported(), "FP not supported"); Ogre::GpuProgramParametersSharedPtr paramsVP = water_vp->getDefaultParameters(); paramsVP->setNamedAutoConstant( "world", Ogre::GpuProgramParameters:: ACT_WORLD_MATRIX); paramsVP->setNamedAutoConstant( "worldViewProj", Ogre::GpuProgramParameters:: ACT_WORLDVIEWPROJ_MATRIX); paramsVP->setNamedAutoConstant( "textureProjMatrix", Ogre::GpuProgramParameters:: ACT_TEXTURE_WORLDVIEWPROJ_MATRIX); paramsVP->setNamedAutoConstant( "eyePosition", Ogre::GpuProgramParameters:: ACT_CAMERA_POSITION_OBJECT_SPACE); paramsVP->setNamedAutoConstant( "normalMatrix", Ogre::GpuProgramParameters:: ACT_NORMAL_MATRIX); paramsVP->setNamedAutoConstant( "worldView", Ogre::GpuProgramParameters:: ACT_WORLDVIEW_MATRIX); paramsVP->setNamedAutoConstant( "viewProj", Ogre::GpuProgramParameters:: ACT_VIEWPROJ_MATRIX); Ogre::GpuProgramParametersSharedPtr paramsFP = water_fp->getDefaultParameters(); #endif 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); #if 0 bool success = Ogre::RTShader::ShaderGenerator::getSingletonPtr() ->createShaderBasedTechnique( *mat, Ogre::MSN_DEFAULT, Ogre::MSN_SHADERGEN); OgreAssert( success, "createShaderBasedTechnique"); Ogre::RTShader::RenderState *renderState = Ogre::RTShader::ShaderGenerator:: getSingletonPtr() ->getRenderState( Ogre::MSN_SHADERGEN, *mat, 0); Ogre::RTShader::SubRenderState *perPixelLightModel = Ogre::RTShader::ShaderGenerator::getSingletonPtr() ->createSubRenderState( Ogre::RTShader:: SRS_PER_PIXEL_LIGHTING); renderState->addTemplateSubRenderState( perPixelLightModel); #endif } #if 0 mat = Ogre::MaterialManager::getSingleton() .getByName("Water/Above"); mat->load(); #endif 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); #if 0 ecs.component().add(flecs::Singleton); ecs.component() .on_add([this](WaterBody &body) { #if 0 body.mShapeAabbMax = btVector3(0, 0, 0); body.mShapeAabbMin = btVector3(0, 0, 0); body.mSurface.clear(); body.mWaterBody = OGRE_NEW btPairCachingGhostObject(); createWaterShape(&body); body.mWaterBody->setCollisionShape(body.mWaterShape); btTransform bodyTransform; bodyTransform.setIdentity(); body.mWaterBody->setWorldTransform(bodyTransform); body.mWaterBody->setCollisionFlags( body.mWaterBody->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_NO_CONTACT_RESPONSE); body.mWaterBody->setActivationState( DISABLE_DEACTIVATION); const EngineData &eng = ECS::get(); const WaterSurface &water = ECS::get(); eng.mWorld->attachCollisionObject(body.mWaterBody, water.mWaterEnt, 16, 0x7fffffff & ~2); WaterPhysicsAction *action = OGRE_NEW WaterPhysicsAction(body.mWaterBody); body.action = action; ECS::get() .get() .mWorld->getBtWorld() ->addAction(body.action); #endif ECS::get().add(); }) .add(flecs::Singleton); #endif ecs.system("UpdateWater") .kind(flecs::OnUpdate) .with() .each([](const EngineData &eng, const Camera &camera, WaterSurface &water) { 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; // Ogre::Vector3 waterPosition = mCameraPos; // mWaterNode->setPosition(waterPosition); if (d.squaredLength() < 100.0f * 100.0f) water.mWaterNode->translate(d * 3.0f * delta); else water.mWaterNode->translate(d); // water.mWaterEnt->setVisible(false); water.mViewports[0]->update(); water.mViewports[1]->update(); // water.mRenderTargetListener.mInDepth = true; // water.mViewports[2]->update(); // water.mViewports[3]->update(); // water.mRenderTargetListener.mInDepth = false; // water.mWaterEnt->setVisible(true); }); #if 0 ecs.system( "UpdateWaterBody") .kind(flecs::OnUpdate) .with() .each([this](const EngineData &eng, const WaterSurface &water, WaterBody &body) { int i; #if 0 OgreAssert(body.mWaterBody, "Water not ready"); std::set currentOverlaps; Ogre::Vector3 waterPos = water.mWaterNode->_getDerivedPosition(); Ogre::Vector3 waterBodyPos = Ogre::Bullet::convert( body.mWaterBody->getWorldTransform() .getOrigin()); waterPos.y = 0; waterBodyPos.y = 0; Ogre::Vector3 d = waterPos - waterBodyPos; d.y = 0; if (d.squaredLength() > 10.0f * 10.0f) body.mWaterBody->getWorldTransform().setOrigin( Ogre::Bullet::convert(waterBodyPos + d)); #endif #if 0 btCompoundShape *mshape = static_cast( body.mWaterBody->getCollisionShape()); btDispatcher *dispatch = eng.mWorld->getBtWorld()->getDispatcher(); btHashedOverlappingPairCache *cache = body.mWaterBody->getOverlappingPairCache(); btBroadphasePairArray &collisionPairs = cache->getOverlappingPairArray(); const int numObjects = collisionPairs.size(); std::cout << "numObjects: " << numObjects << "\n"; std::cout << "numObjects: " << body.mWaterBody->getOverlappingPairs().size() << "\n"; for (int i = 0; i < numObjects; i++) { const btBroadphasePair &collisionPair = collisionPairs[i]; } #endif #if 0 body.mShapeAabbMin = body.mWaterBody->getWorldTransform() .getOrigin() + btVector3(-100, -100, -100); body.mShapeAabbMax = body.mWaterBody->getWorldTransform() .getOrigin() + btVector3(100, 100, 100); #if 0 body.mWaterShape->getAabb( body.mWaterBody->getWorldTransform(), body.mShapeAabbMin, body.mShapeAabbMax); #endif std::cout << "manifolds: " << static_cast( body.action) ->mManifoldArray.size() << "\n"; for (int j = 0; j < static_cast(body.action) ->mManifoldArray.size(); j++) { btPersistentManifold *manifold = static_cast( body.action) ->mManifoldArray[j]; std::cout << "contacts: " << manifold->getNumContacts() << "\n"; if (manifold->getNumContacts() == 0) continue; const btCollisionObject *obj = (manifold->getBody0() == body.mWaterBody) ? manifold->getBody1() : manifold->getBody0(); btCollisionObject *nobj = const_cast(obj); #if 0 if (obj->getCollisionFlags() & btCollisionObject::CF_STATIC_OBJECT) continue; #endif bool ok = false; Ogre::Vector3 contactPosA, contactPosB; float minDist = 0.0f; for (int p = 0; p < manifold->getNumContacts(); p++) { const btManifoldPoint &pt = manifold->getContactPoint(p); float dist = pt.getDistance(); if (dist < minDist) { minDist = dist; ok = true; } } if (ok) { currentOverlaps.insert(nobj); if (body.mInWater.find(nobj) == body.mInWater.end()) { /* new body */ body.mInWater.insert(nobj); /* calculate proj surface */ body.mSurface[nobj] = 100.0f; body.count++; } } } for (std::set::iterator it = body.mInWater.begin(); it != body.mInWater.end();) { btCollisionObject *obj = *it; if (currentOverlaps.find(obj) == currentOverlaps.end()) { /* remove body */ it = body.mInWater.erase(it); body.mSurface.erase(obj); body.count--; } else it++; } #endif }); #endif } 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 }, }; #if 0 void WaterModule::createWaterShape(WaterBody *water) { int i = 0; btCompoundShape *shape = OGRE_NEW btCompoundShape(); shape->setMargin(0.2f); { btVector3 inertia(0, 0, 0); std::vector masses; btTransform principal; principal.setIdentity(); for (i = 0; i < sizeof(childShapes) / sizeof(childShapes[0]); i++) { btTransform xform; xform.setIdentity(); xform.setOrigin(btVector3(childShapes[i].offsetX, childShapes[i].offsetY, childShapes[i].offsetZ)); btBoxShape *box = OGRE_NEW btBoxShape(btVector3( childShapes[i].boxX, childShapes[i].boxY, childShapes[i].boxZ)); water->mChildShapes.push_back(box); shape->addChildShape(xform, box); masses.push_back(0); } shape->calculatePrincipalAxisTransform(masses.data(), principal, inertia); } shape->recalculateLocalAabb(); water->mWaterShape = shape; } #endif 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; } #if 0 struct DeepPenetrationContactResultCallback : public btManifoldResult { DeepPenetrationContactResultCallback( const btCollisionObjectWrapper *body0Wrap, const btCollisionObjectWrapper *body1Wrap) : btManifoldResult(body0Wrap, body1Wrap) , mPenetrationDistance(0) , mOtherIndex(0) { } float mPenetrationDistance; int mOtherIndex; btVector3 mNormal, mPoint; void reset() { mPenetrationDistance = 0.0f; } bool hasHit() { return mPenetrationDistance < 0.0f; } virtual void addContactPoint(const btVector3 &normalOnBInWorld, const btVector3 &pointInWorldOnB, btScalar depth) { #ifdef VDEBUG std::cout << "contact: " << Ogre::Bullet::convert(pointInWorldOnB) << " " << Ogre::Bullet::convert(normalOnBInWorld) << "\n"; #endif if (mPenetrationDistance > depth) { // Has penetration? const bool isSwapped = m_manifoldPtr->getBody0() != m_body0Wrap->getCollisionObject(); mPenetrationDistance = depth; mOtherIndex = isSwapped ? m_index0 : m_index1; mPoint = isSwapped ? (pointInWorldOnB + (normalOnBInWorld * depth)) : pointInWorldOnB; mNormal = isSwapped ? normalOnBInWorld * -1 : normalOnBInWorld; } } }; void WaterPhysicsAction::updateAction(btCollisionWorld *collisionWorld, btScalar deltaTimeStep) { collisionWorld->updateSingleAabb(mWaterBody); mWaterBody->getCollisionShape()->getAabb( mWaterBody->getWorldTransform(), mShapeAabbMin, mShapeAabbMax); btDispatcher *dispatch = collisionWorld->getDispatcher(); btHashedOverlappingPairCache *cache = mWaterBody->getOverlappingPairCache(); btBroadphasePairArray &collisionPairs = cache->getOverlappingPairArray(); btVector3 a, b; collisionWorld->getBroadphase()->getAabb( mWaterBody->getBroadphaseHandle(), a, b); collisionWorld->getBroadphase()->setAabb( mWaterBody->getBroadphaseHandle(), mShapeAabbMin, mShapeAabbMax, dispatch); btDispatcherInfo &dispatchInfo = collisionWorld->getDispatchInfo(); dispatch->dispatchAllCollisionPairs(cache, dispatchInfo, dispatch); std::set currentOverlaps; std::set::iterator it; const int numObjects = collisionPairs.size(); #ifdef VDEBUG std::cout << "collision pairs: " << numObjects << "\n"; std::cout << "MIN: " << Ogre::Bullet::convert(mShapeAabbMin) << "\n"; std::cout << "MAX: " << Ogre::Bullet::convert(mShapeAabbMax) << "\n"; std::cout << "MIN: " << Ogre::Bullet::convert(a) << "\n"; std::cout << "MAX: " << Ogre::Bullet::convert(b) << "\n"; #endif std::set mCurrentInWater; /* perform narrow phase */ for (int i = 0; i < numObjects; i++) { int j; const btBroadphasePair *collisionPairPtr = collisionWorld->getBroadphase() ->getOverlappingPairCache() ->findPair(collisionPairs[i].m_pProxy0, collisionPairs[i].m_pProxy1); if (!collisionPairPtr) continue; #ifndef USE_MANIFOLD const btBroadphasePair &collisionPair = *collisionPairPtr; const btCollisionObject *objA = static_cast( collisionPair.m_pProxy0->m_clientObject); const btCollisionObject *objB = static_cast( collisionPair.m_pProxy1->m_clientObject); #ifdef VDEBUG std::cout << "bodies: " << objA << " " << objB << "\n"; std::cout << "bodies: " << objA->getCollisionShape()->getName() << " " << objB->getCollisionShape()->getName() << "\n"; std::cout << "pair: " << i << " " << collisionPair.m_algorithm << "\n"; #endif const btCollisionObject *me, *other; if (objA == static_cast(mWaterBody)) { me = objA; other = objB; } else { me = objB; other = objA; } const btCollisionShape *my_shape = me->getCollisionShape(); const btCollisionShape *other_shape = other->getCollisionShape(); btCollisionObjectWrapper obA(NULL, my_shape, mWaterBody, mWaterBody->getWorldTransform(), -1, j); btCollisionObjectWrapper obB(NULL, other_shape, other, other->getWorldTransform(), -1, 0); btCollisionAlgorithm *algorithm = dispatch->findAlgorithm( &obA, &obB, NULL, BT_CONTACT_POINT_ALGORITHMS); #else btCollisionAlgorithm *algorithm = collisionPairPtr->m_algorithm; OgreAssert(algorithm, "No algorithm found"); #endif #ifdef VDEBUG std::cout << "algorithm: " << algorithm << "\n"; #endif #ifndef USE_MANIFOLD DeepPenetrationContactResultCallback contactPointResult(&obA, &obB); #ifdef VDEBUG std::cout << "process collision\n"; #endif algorithm->processCollision(&obA, &obB, collisionWorld->getDispatchInfo(), &contactPointResult); algorithm->~btCollisionAlgorithm(); dispatch->freeCollisionAlgorithm(algorithm); if (contactPointResult.hasHit()) { mCurrentInWater.insert(other); mInWater.insert(other); } #ifdef VDEBUG std::cout << "process collision done\n"; #endif #else if (collisionPairPtr->m_algorithm) collisionPairPtr->m_algorithm->getAllContactManifolds( mManifoldArray); std::cout << "action: manifold: " << mManifoldArray.size() << "\n"; #endif #if 0 std::cout << " " << Ogre::Bullet::convert( collisionPair.m_pProxy0->m_aabbMin) << " -> " << Ogre::Bullet::convert( collisionPair.m_pProxy0->m_aabbMax) << " VS " << Ogre::Bullet::convert( collisionPair.m_pProxy1->m_aabbMin) << " -> " << Ogre::Bullet::convert( collisionPair.m_pProxy1->m_aabbMax) << "\n"; std::cout << "group: 0 " << std::dec << collisionPair.m_pProxy0->m_collisionFilterGroup << "mask: " << std::hex << collisionPair.m_pProxy0->m_collisionFilterMask << "\n"; std::cout << "group: 1 " << std::dec << collisionPair.m_pProxy1->m_collisionFilterGroup << "mask: " << std::hex << collisionPair.m_pProxy1->m_collisionFilterMask << std::dec << "\n"; if (collisionPair.m_algorithm) collisionPair.m_algorithm->getAllContactManifolds( mManifoldArray); std::cout << "action: manifold: " << mManifoldArray.size() << "\n"; #endif #ifdef USE_MANIFOLD for (int j = 0; j < mManifoldArray.size(); j++) { btPersistentManifold *manifold = mManifoldArray[j]; std::cout << "contacts: " << manifold->getNumContacts() << "\n"; if (manifold->getNumContacts() == 0) continue; const btCollisionObject *obj = (manifold->getBody0() == mWaterBody) ? manifold->getBody1() : manifold->getBody0(); btCollisionObject *nobj = const_cast(obj); #if 1 if (obj->getCollisionFlags() & btCollisionObject::CF_STATIC_OBJECT) continue; #endif bool ok = false; Ogre::Vector3 contactPosA, contactPosB; float minDist = 0.0f; for (int p = 0; p < manifold->getNumContacts(); p++) { const btManifoldPoint &pt = manifold->getContactPoint(p); float dist = pt.getDistance(); if (dist < minDist) { minDist = dist; ok = true; } } if (ok) { currentOverlaps.insert(nobj); if (mInWater.find(nobj) == mInWater.end()) { /* new body */ mInWater.insert(nobj); } } } #endif } for (std::set::iterator it = mInWater.begin(); it != mInWater.end();) { const btCollisionObject *obj = *it; if (mCurrentInWater.find(obj) == mCurrentInWater.end()) { /* remove body */ it = mInWater.erase(it); } else it++; } #ifdef VDEBUG std::cout << "water count: " << mInWater.size() << "\n"; #endif } void WaterPhysicsAction::debugDraw(btIDebugDraw *debugDrawer) { } void WaterPhysicsAction::setupBody() { } #endif #if 0 bool WaterBody::isInWater(const btCollisionObject *body) const { return static_cast(action)->isInWater(body); } #endif }