1011 lines
32 KiB
C++
1011 lines
32 KiB
C++
#include <iostream>
|
|
#include <Ogre.h>
|
|
#include <OgreColourValue.h>
|
|
#include <OgreShaderSubRenderState.h>
|
|
#include <OgreShaderGenerator.h>
|
|
#include <OgreRTShaderSystem.h>
|
|
#include <BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h>
|
|
#include <BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h>
|
|
#include <BulletCollision/NarrowPhaseCollision/btPointCollector.h>
|
|
#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<struct contact> mContacts;
|
|
std::set<const btCollisionObject *> 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<WaterModule>();
|
|
ecs.component<InWater>();
|
|
ecs.component<WaterReady>().add(flecs::Singleton);
|
|
ecs.component<WaterAlmostReady>().add(flecs::Singleton);
|
|
ecs.component<GroundCheckReady>().add(flecs::Singleton);
|
|
ecs.component<WaterSurface>()
|
|
.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<EngineData>();
|
|
const Camera &camera = ECS::get<Camera>();
|
|
|
|
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<WaterAlmostReady>();
|
|
})
|
|
.on_remove([](flecs::entity e, WaterSurface &water) {
|
|
const Ogre::String renderTargetName =
|
|
"ReflectionRefractionTexture";
|
|
ECS::get<EngineData>()
|
|
.mScnMgr->getRenderQueue()
|
|
->setRenderableListener(nullptr);
|
|
water.mReflectionTexture->removeAllViewports();
|
|
ECS::get<EngineData>().mScnMgr->destroyCamera(
|
|
water.mRefractionCamera);
|
|
ECS::get<EngineData>().mScnMgr->destroyCamera(
|
|
water.mRefractionDepthCamera);
|
|
ECS::get<EngineData>().mScnMgr->destroyCamera(
|
|
water.mReflectionCamera);
|
|
ECS::get<EngineData>().mScnMgr->destroyCamera(
|
|
water.mReflectionDepthCamera);
|
|
Ogre::TextureManager::getSingleton().remove(
|
|
renderTargetName);
|
|
water.mWaterNode->destroyAllChildrenAndObjects();
|
|
ECS::get<EngineData>().mScnMgr->destroySceneNode(
|
|
water.mWaterNode);
|
|
Ogre::MaterialManager::getSingleton().remove(
|
|
"Water/Depth");
|
|
Ogre::MaterialManager::getSingleton().remove(
|
|
"Water/Above");
|
|
})
|
|
.add(flecs::Singleton);
|
|
#if 0
|
|
ecs.component<WaterBody>().add(flecs::Singleton);
|
|
ecs.component<WaterBody>()
|
|
.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<EngineData>();
|
|
const WaterSurface &water = ECS::get<WaterSurface>();
|
|
|
|
eng.mWorld->attachCollisionObject(body.mWaterBody,
|
|
water.mWaterEnt, 16,
|
|
0x7fffffff & ~2);
|
|
WaterPhysicsAction *action =
|
|
OGRE_NEW WaterPhysicsAction(body.mWaterBody);
|
|
body.action = action;
|
|
ECS::get()
|
|
.get<EngineData>()
|
|
.mWorld->getBtWorld()
|
|
->addAction(body.action);
|
|
#endif
|
|
ECS::get().add<WaterReady>();
|
|
})
|
|
.add(flecs::Singleton);
|
|
#endif
|
|
ecs.system<const EngineData, const Camera, WaterSurface>("UpdateWater")
|
|
.kind(flecs::OnUpdate)
|
|
.with<WaterReady>()
|
|
.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<const EngineData, const WaterSurface, WaterBody>(
|
|
"UpdateWaterBody")
|
|
.kind(flecs::OnUpdate)
|
|
.with<WaterReady>()
|
|
.each([this](const EngineData &eng, const WaterSurface &water,
|
|
WaterBody &body) {
|
|
int i;
|
|
#if 0
|
|
OgreAssert(body.mWaterBody, "Water not ready");
|
|
std::set<btCollisionObject *> 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<btCompoundShape *>(
|
|
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<WaterPhysicsAction *>(
|
|
body.action)
|
|
->mManifoldArray.size()
|
|
<< "\n";
|
|
for (int j = 0;
|
|
j < static_cast<WaterPhysicsAction *>(body.action)
|
|
->mManifoldArray.size();
|
|
j++) {
|
|
btPersistentManifold *manifold =
|
|
static_cast<WaterPhysicsAction *>(
|
|
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<btCollisionObject *>(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<btCollisionObject *>::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<btScalar> 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<btCollisionObject *> currentOverlaps;
|
|
std::set<btCollisionObject *>::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<const btCollisionObject *> 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<btCollisionObject *>(
|
|
collisionPair.m_pProxy0->m_clientObject);
|
|
const btCollisionObject *objB =
|
|
static_cast<btCollisionObject *>(
|
|
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<btCollisionObject *>(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<btCollisionObject *>(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<const btCollisionObject *>::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<WaterPhysicsAction *>(action)->isInWater(body);
|
|
}
|
|
#endif
|
|
} |