#include #include #include #include #include #include #include "water.h" /* TODO: use blender glb model for water shape. * TODO: Finish main shader * TODO: Add caustics * TODO: Add below shader */ static const uint32_t SUBMERGED_MASK = 0x0F0; static const uint32_t SURFACE_MASK = 0x00F; static const uint32_t WATER_MASK = 0xF00; Water::Water() : RenderTargetListener() , mWaterNode(nullptr) , mScnMgr(nullptr) , mWindow(nullptr) , mCameraNode(nullptr) , mWaterPlane(Ogre::Vector3::UNIT_Y, 0) , mReflectionPlane(Ogre::Vector3(0.0, 1.0, 0.0), 0.0f /* water height */) , mReflectionClipPlaneAbove(Ogre::Vector3(0.0, 1.0, 0.0), 0.0f /* water height */ - 2.0f) , mReflectionClipPlaneBelow(Ogre::Vector3(0.0, -1.0, 0.0), -(0.0f /* water height */ + 2.0)) , mRefractionClipPlaneAbove(Ogre::Vector3(0.0, -1.0, 0.0), -(0.0f /* water height */ + 2.0)) , mRefractionClipPlaneBelow(Ogre::Vector3(0.0, 1.0, 0.0), 0.0f /* water height */ - 2.0) , mAbove(true) , mWaterBody(nullptr) , mDynWorld(nullptr) { } Water::~Water() { if (mWaterNode) mScnMgr->destroySceneNode(mWaterNode); if (mReflectionTexture) mReflectionTexture->removeAllListeners(); if (mWaterBody) { if (mWaterBody->getWorldArrayIndex() >= 0) if (mDynWorld) mDynWorld->getBtWorld()->removeCollisionObject( mWaterBody); delete mWaterBody; mWaterBody = nullptr; } } void Water::create_cameras() { mReflectionTexture->addListener(this); mReflectionCamera = mScnMgr->createCamera("ReflectionCamera"); mCamera->getParentSceneNode()->attachObject(mReflectionCamera); mReflectionCamera->setAspectRatio(mCamera->getAspectRatio()); mReflectionCamera->setNearClipDistance(mCamera->getNearClipDistance()); mReflectionCamera->setFarClipDistance(mCamera->getFarClipDistance()); mReflectionCamera->enableCustomNearClipPlane(mReflectionClipPlaneAbove); mReflectionCamera->enableReflection(mReflectionPlane); Ogre::Viewport *reflectionViewport = mReflectionTexture->addViewport( mReflectionCamera, 0, 0, 0, 0.5f, 1.0f); reflectionViewport->setClearEveryFrame(true); reflectionViewport->setBackgroundColour( Ogre::ColourValue(0.0, 0.0, 1.0, 1.0)); reflectionViewport->setOverlaysEnabled(false); reflectionViewport->setSkiesEnabled(true); reflectionViewport->setAutoUpdated(false); mViewports.push_back(reflectionViewport); mRefractionCamera = mScnMgr->createCamera("RefractionCamera"); mCamera->getParentSceneNode()->attachObject(mRefractionCamera); mRefractionCamera->setAspectRatio(mCamera->getAspectRatio()); mRefractionCamera->setNearClipDistance(mCamera->getNearClipDistance()); mRefractionCamera->setFarClipDistance(mCamera->getFarClipDistance()); mRefractionCamera->enableCustomNearClipPlane(mRefractionClipPlaneAbove); Ogre::Viewport *refractionViewport = mReflectionTexture->addViewport( mRefractionCamera, 1, 0.5, 0, 0.5f, 1.0f); refractionViewport->setClearEveryFrame(true); refractionViewport->setBackgroundColour( Ogre::ColourValue(0.0, 0.5, 1.0, 1.0)); refractionViewport->setOverlaysEnabled(false); refractionViewport->setSkiesEnabled(false); refractionViewport->setAutoUpdated(false); mViewports.push_back(refractionViewport); } void Water::create_textures() { Ogre::TexturePtr reflectionTexture = Ogre::TextureManager::getSingleton().createManual( "ReflectionRefractionTexture", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 512, 512, 0, Ogre::PF_R8G8B8A8, Ogre::TU_RENDERTARGET); mReflectionTexture = reflectionTexture->getBuffer()->getRenderTarget(); mReflectionTexture->setAutoUpdated(false); } void Water::init() { int i; float w = 1000.0f; // mWindow->addListener(this); create_cameras(); #if 0 Ogre::MeshPtr water_plane = Ogre::MeshManager::getSingleton().createPlane( "water", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, w, w, 100, 100, true, 1, 100, 100, Ogre::Vector3::UNIT_Z); #endif if (!Ogre::MeshLodGenerator::getSingletonPtr()) new Ogre::MeshLodGenerator(); #if 0 Ogre::LodConfig lod_config(water_plane); lod_config.createGeneratedLodLevel(w, 0.5f); lod_config.createGeneratedLodLevel(w * 2.0, 0.25f); Ogre::MeshLodGenerator::getSingleton().generateLodLevels(lod_config); #endif Ogre::Vector3 positions[] = { { 0, 0, 0 }, { 0, 0, -1 }, { 0, 0, 1 }, { -1, 0, 0 }, { 1, 0, 0 }, { -1, 0, -1 }, { -1, 0, 1 }, { 1, 0, -1 }, { 1, 0, 1 } }; mWaterNode = mScnMgr->getRootSceneNode()->createChildSceneNode("Water"); auto mat = Ogre::MaterialManager::getSingleton().getByName("Water/Above"); mat->load(); mat->setReceiveShadows(false); auto mat2 = Ogre::MaterialManager::getSingleton().getByName("Water/Below"); mat2->load(); mat2->setReceiveShadows(false); #if 0 for (i = 0; i < (int)sizeof(positions) / (int)sizeof(positions[0]); i++) { Ogre::Entity *water_lod1 = mScnMgr->createEntity( "Water" + Ogre::StringConverter::toString(i), "water"); water_lod1->setVisibilityFlags(WATER_MASK); water_lod1->setCastShadows(true); water_lod1->setMaterialName("Water/Above"); water_lod1->setMaterial(mat); Ogre::SceneNode *node_w = mWaterNode->createChildSceneNode( "Water" + Ogre::StringConverter::toString(i), positions[i] * w, Ogre::Quaternion::IDENTITY); node_w->attachObject(water_lod1); water_lod1->setVisibilityFlags(WATER_MASK); mWaterMeshes.push_back(water_lod1); } #endif Ogre::Entity *water_ent = mScnMgr->createEntity("Ocean", "sea.glb"); water_ent->setVisibilityFlags(WATER_MASK); water_ent->setCastShadows(true); water_ent->setMaterialName("Water/Above"); water_ent->setMaterial(mat); mWaterNode->attachObject(water_ent); mWaterMeshes.push_back(water_ent); mDynWorld->attachCollisionObject(mWaterBody, water_ent, 1, 0x7FFFFFFF); } void Water::createWater(Ogre::RenderWindow *window, Ogre::Camera *camera, Ogre::Bullet::DynamicsWorld *world) { int i; mCamera = camera; mScnMgr = camera->getSceneManager(); mCameraNode = camera->getParentSceneNode(); Ogre::Viewport *viewport = camera->getViewport(); mWindow = window; mCameraPosition = mCameraNode->getPosition(); create_textures(); mDynWorld = world; mWaterBody = new btGhostObject; btBoxShape *boxShape = new btBoxShape(btVector3(1000, 1000, 1000)); btCompoundShape *shape = new btCompoundShape; shape->addChildShape( btTransform(btQuaternion(), btVector3(0, -1000, 0)), boxShape); mWaterBody->setCollisionShape(shape); mWaterBody->setCollisionFlags( mWaterBody->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE | btCollisionObject::CF_STATIC_OBJECT); } void Water::updateWater(float delta) { int i; Ogre::Vector3 mCameraPos = mCameraNode->_getDerivedPosition(); Ogre::Vector3 waterPos = 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) mWaterNode->translate(d * 3.0f * delta); else mWaterNode->translate(d); if (mAbove) { if (mCameraNode->getPosition().y < 0) { mAbove = false; for (i = 0; i < mWaterMeshes.size(); i++) mWaterMeshes[i]->setMaterialName("Water/Below"); } } else { if (mCameraNode->getPosition().y > 0) { mAbove = true; for (i = 0; i < mWaterMeshes.size(); i++) mWaterMeshes[i]->setMaterialName("Water/Above"); } } for (i = 0; i < mWaterMeshes.size(); i++) mWaterMeshes[i]->setVisible(false); for (i = 0; i < mViewports.size(); i++) mViewports[i]->update(); for (i = 0; i < mWaterMeshes.size(); i++) mWaterMeshes[i]->setVisible(true); mOverlaps.clear(); for (i = 0; i < mWaterBody->getNumOverlappingObjects(); i++) { btCollisionObject *sb = mWaterBody->getOverlappingObject(i); mOverlaps.insert(sb); } } void Water::preRenderTargetUpdate(const Ogre::RenderTargetEvent &evt) { int i; if (evt.source == mReflectionTexture) { for (i = 0; i < mWaterMeshes.size(); i++) mWaterMeshes[i]->setVisible(false); if (evt.source == mReflectionTexture) mInRefTexUpdate = true; } else { for (i = 0; i < mWaterMeshes.size(); i++) mWaterMeshes[i]->setVisible(true); mInRefTexUpdate = false; } } void Water::postRenderTargetUpdate(const Ogre::RenderTargetEvent &evt) { int i; for (i = 0; i < mWaterMeshes.size(); i++) mWaterMeshes[i]->setVisible(true); mInRefTexUpdate = false; } void Water::add_submerged_entity(Ogre::Entity *ent) { ent->setVisibilityFlags(SUBMERGED_MASK); } void Water::add_surface_entity(Ogre::Entity *ent) { ent->setVisibilityFlags(SURFACE_MASK); } void Water::dump_textures() { mReflectionTexture->writeContentsToFile("Reflection.png"); }