From b2e010bdb45c5682a0f585082fdf6e5ca0f564cb Mon Sep 17 00:00:00 2001 From: Sergey Lapin Date: Fri, 4 Jul 2025 01:10:08 +0300 Subject: [PATCH] Render target water --- CMakeLists.txt | 53 ++++++++++--- GuiTest.cpp | 53 +++++++++---- resources.cfg | 3 +- src/terrain/terrain.cpp | 5 +- water/water.compositor | 3 + water/water.cpp | 169 +++++++++++++++++++++++++++++++++------- water/water.frag | 111 ++++---------------------- water/water.h | 26 ++++++- water/water.material | 95 +++++++++++++++++++++- water/water.program | 32 ++++++-- water/water.vert | 34 ++++---- 11 files changed, 405 insertions(+), 179 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9351c69..728998f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,24 +15,34 @@ set(CREATE_SCENES ${CMAKE_SOURCE_DIR}/characters/male/vroid-normal-male.scene ) +option(OGRE_DYNAMIC "Build against dynamic ogre" ON) # workaround horribly broken assimp cmake, fixed with assimp 5.1 -add_library(fix::assimp INTERFACE IMPORTED) -set_target_properties(fix::assimp PROPERTIES - INTERFACE_LINK_LIBRARIES "${ASSIMP_LIBRARIES};pugixml" - INTERFACE_LINK_DIRECTORIES "${ASSIMP_LIBRARY_DIRS}" -) +#add_library(assimp INTERFACE IMPORTED) +#set_target_properties(assimp PROPERTIES +# INTERFACE_LINK_LIBRARIES "assimp;pugixml" +# # INTERFACE_LINK_DIRECTORIES "${ASSIMP_LIBRARY_DIRS}" +# INTERFACE_LINK_DIRECTORIES "${CMAKE_PREFIX_PATH}/lib" +#) file(GLOB TERRAIN_SRC ${CMAKE_SOURCE_DIR}/src/terrain/*.cpp) file(GLOB WATER_SRC ${CMAKE_SOURCE_DIR}/water/*.cpp) # The COMPONENTS part checks that OGRE was built the way we need it # The CONFIG flag makes sure we get OGRE instead of OGRE-next -find_package(OGRE REQUIRED COMPONENTS Bites Bullet Paging CONFIG) +find_package(OGRE REQUIRED COMPONENTS Bites Bullet Paging Terrain CONFIG) find_package(ZLIB) find_package(SDL2) -find_package(assimp) +find_package(assimp REQUIRED CONFIG) find_package(Bullet) find_package(OgreProcedural REQUIRED CONFIG) +find_package(pugixml REQUIRED CONFIG) + +add_library(fix::assimp INTERFACE IMPORTED) +set_target_properties(fix::assimp PROPERTIES + INTERFACE_LINK_LIBRARIES "${ASSIMP_LIBRARIES};pugixml" + INTERFACE_LINK_DIRECTORIES "${ASSIMP_LIBRARY_DIRS}" +# INTERFACE_LINK_DIRECTORIES "${CMAKE_PREFIX_PATH}/lib" +) add_library(fix::OgreProcedural INTERFACE IMPORTED) set_target_properties(fix::OgreProcedural PROPERTIES @@ -40,6 +50,21 @@ set_target_properties(fix::OgreProcedural PROPERTIES INTERFACE_LINK_DIRECTORIES "${CMAKE_PREFIX_PATH}/lib" ) +if(NOT OGRE_DYNAMIC) +add_library(OgreGLSupportStatic INTERFACE IMPORTED) +set_target_properties(OgreGLSupportStatic PROPERTIES + INTERFACE_LINK_LIBRARIES "OgreGLSupportStatic" + INTERFACE_LINK_DIRECTORIES "${CMAKE_PREFIX_PATH}/lib" +) +endif() + +add_library(fix::pugixml INTERFACE IMPORTED) +set_target_properties(fix::pugixml PROPERTIES + INTERFACE_LINK_LIBRARIES "pugixml" + INTERFACE_LINK_DIRECTORIES "${CMAKE_PREFIX_PATH}/lib" +) + + add_subdirectory(src/lua) @@ -47,7 +72,7 @@ add_subdirectory(src/lua) add_executable(0_Bootstrap Bootstrap.cpp) # this also sets the includes and pulls third party dependencies -target_link_libraries(0_Bootstrap OgreBites OgreBullet OgrePaging ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY}) +target_link_libraries(0_Bootstrap OgreBites OgreBullet OgrePaging ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY} ${ASSIMP_LIBRARIES}) target_include_directories(0_Bootstrap PUBLIC OgreBites OgrePaging OgreBullet) add_dependencies(0_Bootstrap stage_files) @@ -60,7 +85,6 @@ add_executable(Procedural Procedural.cpp ${TERRAIN_SRC}) target_link_libraries(Procedural OgreBites OgreBullet OgrePaging OgreTerrain OgreProcedural::OgreProcedural ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY}) target_include_directories(Procedural PUBLIC OgreBites OgrePaging OgreBullet OgreTerrain OgreProcedural::OgreProcedural ${CMAKE_PREFIX_PATH}/include/OgreProcedural) add_dependencies(Procedural stage_files import_buildings) - file(GLOB BUILDINGS_SRC ${CMAKE_SOURCE_DIR}/assets/blender/buildings/*.blend) set(BUILDING_OUTPUT_FILES) foreach(BUILDING_FILE ${BUILDINGS_SRC}) @@ -83,6 +107,13 @@ add_custom_target(import_buildings ALL DEPENDS ${BUILDING_OUTPUT_FILES}) add_executable(TerrainTest terrain.cpp ${TERRAIN_SRC}) target_link_libraries(TerrainTest OgreBites OgreBullet OgrePaging OgreTerrain lua ${BULLET_DYNAMICS_LIBRARY} ${BULLET_COLLISION_LIBRARY} ${BULLET_MATH_LIBRARY}) target_include_directories(TerrainTest PUBLIC OgreBites OgrePaging OgreTerrain OgreBullet PRIVATE . src/terrain src/lua src/lua/lua-5.4.8/src) +if(NOT OGRE_DYNAMIC) + target_link_libraries(TerrainTest fix::assimp pugixml) + target_link_libraries(Procedural fix::assimp pugixml) + target_link_libraries(0_Bootstrap fix::assimp pugixml) + target_link_libraries(GuiTest fix::assimp pugixml) +endif() + file(GLOB LUA_SCRIPTS_SRC ${CMAKE_SOURCE_DIR}/lua-scripts/*.lua) set(LUA_SCRIPTS_OUTPUT) @@ -150,6 +181,8 @@ set(WATER_SRC water.program water.frag water.vert + depth.frag + depth.vert water.compositor waves2.png ) @@ -201,3 +234,5 @@ add_custom_target(remove_scenes COMMAND rm -f ${CREATE_SCENES}) add_custom_target(import_vrm DEPENDS ${CREATE_SCENES}) +install(TARGETS GuiTest DESTINATION bin) + diff --git a/GuiTest.cpp b/GuiTest.cpp index 6912958..ea32c51 100644 --- a/GuiTest.cpp +++ b/GuiTest.cpp @@ -395,10 +395,13 @@ public: mDbgDraw.reset(new Ogre::Bullet::DebugDrawer( mScnMgr->getRootSceneNode(), mDynWorld->getBtWorld())); } - void locateResources() + void locateResources() override { OgreBites::ApplicationContext::locateResources(); } + void loadResources() override + { + } void initCamera() { @@ -429,8 +432,38 @@ public: // our model is quite small, so reduce the clipping planes mCamera->setNearClipDistance(0.1f); mCamera->setFarClipDistance(800); - mPivotPitch = 0; + } + void configure() + { + std::cout << "Startup" << "\n"; + initApp(); + std::cout << "Set up RTSS" << "\n"; + Ogre::Root *root = getRoot(); + Ogre::SceneManager *scnMgr = getSceneManager(); + + // register our scene with the RTSS + Ogre::RTShader::ShaderGenerator *shadergen = + Ogre::RTShader::ShaderGenerator::getSingletonPtr(); + shadergen->addSceneManager(scnMgr); + setWindowGrab(true); + std::cout << "Init camera" << "\n"; + initCamera(); + std::cout << "Set up water" << "\n"; + m_water.createWater(getRenderWindow(), mCamera); + std::cout << "Set up cursor" << "\n"; + Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); + // OgreBites::ApplicationContext::loadResources(); + setupCursor(); + std::cout << "Create content" << "\n"; + createContent(); + std::cout << "Setup terrain" << "\n"; + setupTerrain(); + m_water.init(); + } + void setupCursor() + { + // mKeyDirection = Ogre::Vector3::ZERO; // mVerticalVelocity = 0; Ogre::ManualObject *mobj = @@ -600,7 +633,7 @@ public: Ogre::Timer mTerrainUpd; void updateTerrain(float delta) { - mDbgDraw->update(); + // mDbgDraw->update(); #if 0 if (mTerrainUpd.getMilliseconds() > 1000) { m_terrain.create_colliders(); @@ -641,7 +674,6 @@ public: "Skybox/Dynamic", "General"); OgreAssert(m, "Sky box material not found."); m->load(); - m_water.createWater(mCamera); getRoot()->addFrameListener(&m_water); #endif } @@ -845,20 +877,9 @@ void EditUI::initGui() int main() { App ctx; - ctx.initApp(); + ctx.configure(); // ctx.runRenderingSettingsDialog(); // get a pointer to the already created root - Ogre::Root *root = ctx.getRoot(); - Ogre::SceneManager *scnMgr = ctx.getSceneManager(); - - // register our scene with the RTSS - Ogre::RTShader::ShaderGenerator *shadergen = - Ogre::RTShader::ShaderGenerator::getSingletonPtr(); - shadergen->addSceneManager(scnMgr); - ctx.setWindowGrab(true); - ctx.initCamera(); - ctx.createContent(); - ctx.setupTerrain(); // register for input events // KeyHandler keyHandler; // ctx.addInputListener(&keyHandler); diff --git a/resources.cfg b/resources.cfg index 57be0a0..1a5dd85 100644 --- a/resources.cfg +++ b/resources.cfg @@ -19,9 +19,9 @@ FileSystem=resources/terrain # samples which require them. [General] FileSystem=skybox -FileSystem=water FileSystem=resources/buildings FileSystem=resources/debug +FileSystem=water # PBR media must come before the scripts that reference it #FileSystem=./Media/PBR #FileSystem=./Media/PBR/filament @@ -73,4 +73,3 @@ FileSystem=lua-scripts [Characters] FileSystem=./characters/male FileSystem=./characters/female - diff --git a/src/terrain/terrain.cpp b/src/terrain/terrain.cpp index 0078115..978d99b 100644 --- a/src/terrain/terrain.cpp +++ b/src/terrain/terrain.cpp @@ -21,7 +21,7 @@ #define ENDLESS_TERRAIN_FILE_PREFIX Ogre::String("EndlessWorldTerrain") #define ENDLESS_TERRAIN_FILE_SUFFIX Ogre::String("dat") #define TERRAIN_WORLD_SIZE 4000.0f -#define TERRAIN_SIZE 129 +#define TERRAIN_SIZE 513 // #define HOLD_LOD_DISTANCE 3000.0 #define USE_PERLIN_DEFINER 0 template T CLAMP(T value, T low, T high) @@ -258,7 +258,8 @@ public: if (!created || true) { btRigidBody *body = mWorld->addTerrainRigidBody( - group, x, y); + group, x, y, 2, + 0x7ffffffd); Ogre::LogManager::getSingleton().logError( "created rigid body " + Ogre::StringConverter::toString( diff --git a/water/water.compositor b/water/water.compositor index 41338dd..4080428 100644 --- a/water/water.compositor +++ b/water/water.compositor @@ -1,9 +1,11 @@ +/* compositor Fresnel { technique { texture reflection 512 512 PF_BYTE_RGB texture refraction 512 512 PF_BYTE_RGB + target reflection { visibility_mask 0x00F // SURFACE objects @@ -20,4 +22,5 @@ compositor Fresnel } } } +*/ diff --git a/water/water.cpp b/water/water.cpp index acd379b..e553cac 100644 --- a/water/water.cpp +++ b/water/water.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -9,10 +10,18 @@ static const uint32_t SURFACE_MASK = 0x00F; static const uint32_t WATER_MASK = 0xF00; Water::Water() : FrameListener() + , 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) { } @@ -20,30 +29,75 @@ Water::~Water() { if (mWaterNode) mScnMgr->destroySceneNode(mWaterNode); + if(mReflectionTexture) + mReflectionTexture->removeAllListeners(); } -void Water::createWater(Ogre::Camera *camera) +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); + reflectionViewport->setClearEveryFrame(true); + reflectionViewport->setBackgroundColour(Ogre::ColourValue(0.0, 0.0, 0.0, 0.0)); + reflectionViewport->setOverlaysEnabled(false); + // reflectionViewport->setVisibilityMask(0xFFF); + + mRefractionTexture->addListener(this); + 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 = mRefractionTexture->addViewport(mRefractionCamera); + refractionViewport->setClearEveryFrame(true); + refractionViewport->setBackgroundColour(Ogre::ColourValue(0.0, 0.0, 0.0, 0.0)); + refractionViewport->setOverlaysEnabled(false); + refractionViewport->setSkiesEnabled(false); +} + +void Water::create_textures() +{ + Ogre::TexturePtr reflectionTexture = Ogre::TextureManager::getSingleton().createManual( + "ReflectionTexture", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, 256, 256, + 0, + Ogre::PF_R8G8B8A8, + Ogre::TU_RENDERTARGET); + + mReflectionTexture = reflectionTexture->getBuffer()->getRenderTarget(); + Ogre::TexturePtr refractionTexture = Ogre::TextureManager::getSingleton().createManual( + "RefractionTexture", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, 512, 512, + 0, + Ogre::PF_R8G8B8A8, + Ogre::TU_RENDERTARGET); + + mRefractionTexture = refractionTexture->getBuffer()->getRenderTarget(); +} + +void Water::init() { int i; - float w = 1000; - mCamera = camera; - mScnMgr = camera->getSceneManager(); - mCameraNode = camera->getParentSceneNode(); - Ogre::Viewport *viewport = camera->getViewport(); - mCameraPosition = mCameraNode->getPosition(); - auto compositor = Ogre::CompositorManager::getSingleton().addCompositor( - viewport, "Fresnel"); - Ogre::CompositorManager::getSingleton().setCompositorEnabled( - viewport, "Fresnel", true); - - // toggle reflection in camera - compositor->getRenderTarget("reflection")->addListener(this); - + float w = 600.0f; + // mWindow->addListener(this); + create_cameras(); Ogre::MeshPtr water_plane = Ogre::MeshManager::getSingleton().createPlane( "water", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, - mWaterPlane, w, w, 100, 100, true, 1, 100, 100, + mWaterPlane, w, w, 10, 10, true, 1, 100, 100, Ogre::Vector3::UNIT_Z); if (!Ogre::MeshLodGenerator::getSingletonPtr()) new Ogre::MeshLodGenerator(); @@ -53,45 +107,82 @@ void Water::createWater(Ogre::Camera *camera) lod_config.createGeneratedLodLevel(w * 2.0, 0.25f); Ogre::MeshLodGenerator::getSingleton().generateLodLevels(lod_config); - Ogre::Vector3 positions[] = { { 0, 0, -1 }, { 0, 0, 1 }, { -1, 0, 0 }, - { 1, 0, 0 }, { -1, 0, -1 }, { -1, 0, 1 }, - { 1, 0, -1 }, { 1, 0, 1 } }; + 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"); - Ogre::Entity *water = mScnMgr->createEntity("WaterR", "water"); - water->setVisibilityFlags(WATER_MASK); - water->setCastShadows(true); - auto mat = Ogre::MaterialManager::getSingleton().getByName("Water"); + + auto mat = Ogre::MaterialManager::getSingleton().getByName("Water/Above"); + mat->load(); mat->setReceiveShadows(false); +#if 0 mat->getTechnique(0) ->getPass(0) ->getTextureUnitState(0) ->setProjectiveTexturing(true, mCamera); - water->setMaterial(mat); - Ogre::SceneNode *node0 = mWaterNode->createChildSceneNode("WaterR"); - node0->attachObject(water); +#endif + auto mat2 = Ogre::MaterialManager::getSingleton().getByName("Water/Below"); + mat2->load(); + mat2->setReceiveShadows(false); +#if 0 + mat2->getTechnique(0) + ->getPass(0) + ->getTextureUnitState(0) + ->setProjectiveTexturing(true, mCamera); +#endif + 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->setMaterialName("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); } } +void Water::createWater(Ogre::RenderWindow * window, Ogre::Camera *camera) +{ + int i; + mCamera = camera; + mScnMgr = camera->getSceneManager(); + mCameraNode = camera->getParentSceneNode(); + Ogre::Viewport *viewport = camera->getViewport(); + mWindow = window; + mCameraPosition = mCameraNode->getPosition(); + create_textures(); +} + void Water::updateWater(float delta) { + int i; if (mCameraPosition.squaredDistance(mCameraNode->getPosition()) > - 100.0f) { + 200.0f * 200.0f) { mCameraPosition = mCameraNode->getPosition(); Ogre::Vector3 waterPosition = mCameraPosition; waterPosition.y = 0; mWaterNode->setPosition(waterPosition); } + 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"); + } + } } bool Water::frameEnded(const Ogre::FrameEvent &evt) @@ -106,12 +197,25 @@ bool Water::frameRenderingQueued(const Ogre::FrameEvent &evt) void Water::preRenderTargetUpdate(const Ogre::RenderTargetEvent &evt) { - mCamera->enableReflection(mWaterPlane); + int i; + if (evt.source == mReflectionTexture || evt.source == mRefractionTexture) { + 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) { - mCamera->disableReflection(); + int i; + for (i = 0; i < mWaterMeshes.size(); i++) + mWaterMeshes[i]->setVisible(true); + mInRefTexUpdate = false; } void Water::add_submerged_entity(Ogre::Entity *ent) @@ -123,3 +227,8 @@ void Water::add_surface_entity(Ogre::Entity *ent) { ent->setVisibilityFlags(SURFACE_MASK); } +void Water::dump_textures() +{ + mReflectionTexture->writeContentsToFile("Reflection.png"); + mRefractionTexture->writeContentsToFile("Refraction.png"); +} diff --git a/water/water.frag b/water/water.frag index 53ab117..af14b6a 100644 --- a/water/water.frag +++ b/water/water.frag @@ -1,103 +1,24 @@ -/*********************************************************************NVMH3**** -Copyright NVIDIA Corporation 2003 -TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THIS SOFTWARE IS PROVIDED -*AS IS* AND NVIDIA AND ITS SUPPLIERS DISCLAIM ALL WARRANTIES, EITHER EXPRESS -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL NVIDIA OR ITS SUPPLIERS -BE LIABLE FOR ANY SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES -WHATSOEVER (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF BUSINESS PROFITS, -BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, OR ANY OTHER PECUNIARY LOSS) -ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF NVIDIA HAS -BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - - -Comments: - Simple ocean shader with animated bump map and geometric waves - Based partly on "Effective Water Simulation From Physical Models", GPU Gems - -11 Aug 05: converted from HLSL to GLSL by Jeff Doyle (nfz) to work in Ogre -15 Jun 25: converted to OgreUnifiedShader.h by Sergey Lapin - -******************************************************************************/ - OGRE_NATIVE_GLSL_VERSION_DIRECTIVE #include - -SAMPLER2D(noiseMap, 0); -SAMPLER2D(reflectMap, 1); -SAMPLER2D(refractMap, 2); - +// SAMPLER2D(noiseMap, 0); +SAMPLER2D(reflectMap, 0); +SAMPLER2D(refractMap, 1); OGRE_UNIFORMS( - uniform vec4 ambient; - uniform vec4 diffuse; - uniform highp float time; - uniform vec4 deepColor; - uniform vec4 shallowColor; - uniform vec4 reflectionColor; - uniform float reflectionAmount; - uniform float reflectionBlur; - uniform float waterAmount; - uniform vec4 tintColour; - uniform float noiseScale; - uniform float fresnelScale; - uniform float fresnelPower; - uniform float fresnelBias; - uniform float hdrMultiplier; +uniform vec4 viewportSize; +uniform f32vec4 cameraPosition; ) MAIN_PARAMETERS -IN(mat3 rotMatrix, 17) // first row of the 3x3 transform from tangent to cube space -IN(vec2 bumpCoord0, 18) -IN(vec2 bumpCoord1, 19) -IN(vec2 bumpCoord2, 20) -IN(vec3 eyeVector, 21) -IN(vec3 noiseCoord, 22) -IN(highp vec4 projectionCoord, 23) -IN(vec3 eyeDir, 24) -IN(vec3 oNormal, 25) +IN(highp vec4 projectionCoord, TEXCOORD4) +IN(f32vec3 positionWS, TEXCOORD7) MAIN_DECLARATION { -// vec4 t0 = texture2D(NormalMap, bumpCoord0) * 2.0 - 1.0; -// vec4 t1 = texture2D(NormalMap, bumpCoord1) * 2.0 - 1.0; -// vec4 t2 = texture2D(NormalMap, bumpCoord2) * 2.0 - 1.0; - vec4 t0 = normalize(vec4(0.1, 1, 0, 1)); - vec4 t1 = normalize(vec4(0, 1, 0.1, 1)); - vec4 t2 = normalize(vec4(-0.1, 1, 0.1, 1)); - // Do the tex projection manually so we can distort _after_ - vec2 final = projectionCoord.xy / projectionCoord.w; - - // Noise - vec3 noiseNormal = (texture2D(noiseMap, (noiseCoord.xy / 5.0)).rgb - 0.5).rbg * noiseScale; - final += noiseNormal.xz; - -// final.x = clamp(1.0 + final.x - floor(1.0 + final.x), 0.0, 1.0); -// float m = 0.2; -// final.y = final.y * (1.0 - m) + m * 0.5; -// final.y = clamp(1.0 + final.y - floor(1.0 + final.y), 0.0, 1.0); - - vec3 N = t0.xyz + t1.xyz + t2.xyz; - N = normalize(rotMatrix * N); - vec3 E = normalize(eyeVector); - vec3 R = reflect(E, N); - R.z = -R.z; - // vec4 reflection = vec4(0.4, 0.4, 0.8, 1.0); - // vec4 reflection = textureCube(EnvironmentMap, R, reflectionBlur); - // Reflection / refraction - - vec4 reflectionColour = texture2D(reflectMap, final); - vec4 refractionColour = texture2D(refractMap, final) + tintColour; - reflectionColour.rgb *= (reflectionColour.r + reflectionColour.g + reflectionColour.b) * hdrMultiplier; - float facing = 1.0 - dot(-E, N); - - // float fresnel = clamp(fresnelBias + pow(facing, fresnelPower), 0.0, 1.0); - float fresnel = clamp(fresnelBias + fresnelScale * pow(1.0 + dot(eyeDir, oNormal), fresnelPower), 0.0, 1.0); - vec4 waterColor = mix(shallowColor, deepColor, facing) * waterAmount; - vec4 reflection = mix(waterColor, reflectionColour, fresnel) * reflectionAmount; - // reflection = mix(waterColor, reflection * reflectionColor, fresnel) * reflectionAmount; - // gl_FragColor = mix(waterColor, reflectionColour, reflectionAmount); - vec4 r = mix(refractionColour, reflectionColour, fresnel) * reflectionAmount; - gl_FragColor = waterColor + r; - //gl_FragColor = waterColor + mix(refractionColour, reflection, fresnel); - //gl_FragColor = refractionColour; - //gl_FragColor = reflectionColour; - //gl_FragColor = ambient * diffuse; + vec2 screenUV = gl_FragCoord.xy / viewportSize.xy; + screenUV.y = 1.0 - screenUV.y * 0.6 - 0.2; + // vec2 final = projectionCoord.xy / projectionCoord.w; + float depth = saturate(length(positionWS - cameraPosition.xyz) * 0.01); + vec4 reflectionColour = texture2D(reflectMap, screenUV); + vec4 refractionColour = texture2D(refractMap, screenUV); + vec4 result = mix(mix(reflectionColour, refractionColour, 0.5), vec4(0.0, 1.0, 1.0, 1.0), depth); + result.a = 1.0; + gl_FragColor = result; } diff --git a/water/water.h b/water/water.h index a8f0b3b..89e7031 100644 --- a/water/water.h +++ b/water/water.h @@ -4,15 +4,35 @@ class App; class Water : public Ogre::FrameListener, Ogre::RenderTargetListener { Ogre::SceneManager *mScnMgr; + Ogre::RenderWindow * mWindow; Ogre::SceneNode *mWaterNode, *mCameraNode; Ogre::Vector3 mCameraPosition; Ogre::Camera *mCamera; - Ogre::Plane mWaterPlane; + Ogre::Plane mWaterPlane, + mReflectionPlane, + mReflectionClipPlaneAbove, + mReflectionClipPlaneBelow, + mRefractionClipPlaneAbove, + mRefractionClipPlaneBelow; + bool mAbove; + std::vector mWaterMeshes; + // Reflection + Ogre::RenderTexture * mReflectionTexture; + Ogre::Camera * mReflectionCamera; + // Refraction + Ogre::RenderTexture * mRefractionTexture; + Ogre::Camera * mRefractionCamera; + bool mInRefTexUpdate; + Ogre::Timer mtexture_dump; + void create_cameras(); public: Water(); virtual ~Water(); - void createWater(Ogre::Camera *camera); + void create_textures(); + void dump_textures(); + void createWater(Ogre::RenderWindow * window, Ogre::Camera *camera); + void init(); void updateWater(float delta); bool frameEnded(const Ogre::FrameEvent &evt) override; bool frameRenderingQueued(const Ogre::FrameEvent &evt) override; @@ -22,4 +42,4 @@ public: void add_submerged_entity(Ogre::Entity *ent); void add_surface_entity(Ogre::Entity *ent); }; -#endif \ No newline at end of file +#endif diff --git a/water/water.material b/water/water.material index 57de75d..942af4a 100644 --- a/water/water.material +++ b/water/water.material @@ -20,7 +20,7 @@ fragment_program Examples/FresnelRefractReflectFP glsl glsles glslang hlsl */ -material Water +material Water/Above { technique { @@ -51,12 +51,13 @@ material Water param_named noiseScale float 0.05 } */ - vertex_program_ref water_vp + vertex_program_ref Water/water_vp { } - fragment_program_ref water_fp + fragment_program_ref Water/water_fp { } +/* // Noise texture_unit { @@ -90,8 +91,96 @@ material Water } tex_address_mode mirror } +*/ + texture_unit + { + texture ReflectionTexture + tex_address_mode mirror + } + texture_unit + { + texture RefractionTexture + tex_address_mode mirror + } + } + } +} + +material Water/Below +{ + technique + { + pass + { + ambient 1.0 1.0 1.0 1.0 + diffuse 0.0 0.2 0.5 1.0 + cull_hardware none + cull_software none + vertex_program_ref Water/water_vp + { + } + fragment_program_ref Water/water_fp + { + } +/* + // Noise + texture_unit + { + // Perlin noise volume + texture waves2.png + // min / mag filtering, no mip + filtering linear linear none + tex_address_mode mirror + } + // Reflection + texture_unit + { + content_type compositor Fresnel reflection + tex_address_mode mirror + } + // Refraction + texture_unit + { + content_type compositor Fresnel refraction + tex_address_mode mirror + } +*/ + texture_unit + { + texture ReflectionTexture + tex_address_mode mirror + } + texture_unit + { + texture RefractionTexture + tex_address_mode mirror + } } } } +/* + +material Water/Depth +{ + technique + { + pass + { + cull_hardware none + alpha_rejection greater_equal 0.5 + vertex_program_ref Water/depth_vp + { + param_named_auto world world_matrix + param_named_auto worldViewProj worldviewproj_matrix + } + fragment_program_ref Water/depth_fp + { + param_named_auto cameraPosition camera_position + } + } + } +} +*/ + diff --git a/water/water.program b/water/water.program index d165975..3b1d667 100644 --- a/water/water.program +++ b/water/water.program @@ -1,10 +1,31 @@ -fragment_program water_fp glsl glsles glslang hlsl +vertex_program Water/depth_vp glsl glsles glslang hlsl +{ + source depth.vert + default_params + { + param_named_auto world world_matrix + param_named_auto worldViewProj worldviewproj_matrix + } +} + +fragment_program Water/depth_fp glsl glsles glslang hlsl +{ + source depth.frag + default_params + { + param_named_auto cameraPosition camera_position + } +} + +fragment_program Water/water_fp glsl glsles glslang hlsl { source water.frag default_params { + param_named_auto cameraPosition camera_position param_named_auto ambient surface_ambient_colour param_named_auto diffuse surface_diffuse_colour + param_named_auto viewportSize viewport_size param_named_auto time time // param_named NormalMap int 0 // param_named EnvironmentMap int 1 @@ -25,17 +46,18 @@ fragment_program water_fp glsl glsles glslang hlsl param_named hdrMultiplier float 0.471 param_named tintColour float4 0 0.05 0.05 1 param_named noiseScale float 0.03 - param_named noiseMap int 0 - param_named reflectMap int 1 - param_named refractMap int 2 +// param_named noiseMap int 0 + param_named reflectMap int 0 + param_named refractMap int 1 } } -vertex_program water_vp glsl glsles glslang hlsl +vertex_program Water/water_vp glsl glsles glslang hlsl { source water.vert default_params { + param_named_auto world world_matrix param_named_auto worldViewProj worldviewproj_matrix param_named_auto textureProjMatrix texture_worldviewproj_matrix 0 param_named_auto eyePosition camera_position_object_space diff --git a/water/water.vert b/water/water.vert index c45715f..e7b0916 100644 --- a/water/water.vert +++ b/water/water.vert @@ -31,6 +31,7 @@ uniform vec2 bumpSpeed; uniform highp float time; uniform float waveFreq; uniform float waveAmp; +uniform mat4 world; uniform mat4 worldViewProj; uniform mat4 textureProjMatrix; uniform mat3 normalMatrix; @@ -51,17 +52,17 @@ IN(vec4 vertex, POSITION) IN(vec3 normal, NORMAL) // IN(vec3 tangent, TANGENT) IN(vec3 uv0, TEXCOORD0) -OUT(mat3 rotMatrix, 17) -OUT(vec2 bumpCoord0, 18) -OUT(vec2 bumpCoord1, 19) -OUT(vec2 bumpCoord2, 20) -OUT(vec3 eyeVector, 21) -OUT(vec3 noiseCoord, 22) -OUT(highp vec4 projectionCoord, 23) -OUT(vec3 eyeDir, 24) -OUT(vec3 oNormal, 25) +OUT(mat3 rotMatrix, TEXCOORD0) +OUT(vec4 bumpCoordA, TEXCOORD1) +OUT(vec4 bumpCoordB, TEXCOORD2) +OUT(vec3 noiseCoord, TEXCOORD3) +OUT(highp vec4 projectionCoord, TEXCOORD4) +OUT(vec3 eyeDir, TEXCOORD5) +OUT(vec3 oNormal, TEXCOORD6) +OUT(f32vec3 positionWS, TEXCOORD7) MAIN_DECLARATION { +#if 1 #define NWAVES 4 Wave wave[NWAVES]; wave[0] = Wave( waveFreq, waveAmp, 0.5, vec2(-1.0, 0.0) ); @@ -98,11 +99,16 @@ MAIN_DECLARATION rotMatrix = mat3(T, B, N); gl_Position = P; // calculate texture coordinates for normal map lookup - bumpCoord0.xy = uv0.xy * textureScale + time * bumpSpeed; - bumpCoord1.xy = uv0.xy * textureScale * 2.0 + time * bumpSpeed * 4.0; - bumpCoord2.xy = uv0.xy * textureScale * 4.0 + time * bumpSpeed * 8.0; + bumpCoordA.xy = uv0.xy * textureScale + time * bumpSpeed; + bumpCoordA.zw = uv0.xy * textureScale * 2.0 + time * bumpSpeed * 4.0; + bumpCoordB.xy = uv0.xy * textureScale * 4.0 + time * bumpSpeed * 8.0; - eyeVector = R.xyz - eyePosition; // eye position in vertex space eyeDir = normalize(R.xyz - eyePosition); - oNormal = normal; + oNormal = normalize(normal + N); + positionWS = mul(world, vertex).xyz; +#else + gl_Position = worldViewProj * vertex; + projectionCoord = mul(textureProjMatrix, vertex); +#endif } +