Realistic water node

You are an experienced programmer and have a problem with the engine, shaders, or advanced effects? Here you'll get answers.
No questions about C++ programming or topics which are answered in the tutorials!
Vectrotek
Competition winner
Posts: 1087
Joined: Sat May 02, 2015 5:05 pm

Re: Realistic water node

Post by Vectrotek »

It's Half Past One in the morning here and I finally got what
resembles an "Underwater" effect.
Still very simple..

Above Water Plane..
Image

Below Water Plane..
Image

For the Underwater Post Processing I'm working on
"Radial Blur" with the "origin" at the sun position.
There is a lot still to be done..

Do I post an Incomplete project, chock full of inspiration and ideas
or do I wait until it is perfect, which it probably never will be..
(my lack in coding skill is starting to show)
Vectrotek
Competition winner
Posts: 1087
Joined: Sat May 02, 2015 5:05 pm

Re: Realistic water node

Post by Vectrotek »

When you have a water renderer it usually has TWO STATES, one for "Reflection" and one for Refraction.
This complicates things when you consider other objects touching the water in your world in that they (their shaders)
should know what state the water renderer is in to be rendered correctly themselves.
This is quite a ballsup, so I tried something like a "Smart Shader" class which manages
ALL shaders in the program in a way that The water renderer can "send" its "state" to
the shaders of all other world objects.
If you've had this sort of issue then you'd probably see what I tried with these two classes..
The "SmartShaderManager" contains instances of all "CShaderMaterial"s and allows them
to share certain things via "Global Integer Pointers" (should be bools) that you put in your code.

Here is only the Class Methods which seems to work fine..
Some should be "Templated" but that's for later..
(for the whole header check the link below)

Code: Select all

 
 
 //  "Smart Shader Management".. Vectrotek..
 //  Experimental..
 
 #ifndef SHADMAN_INCD
 #define SHADMAN_INCD
 
 #include <irrlicht.h>
 using namespace irr;
 using namespace core;
 using namespace scene;
 using namespace video;
 
 class CShaderMaterial : public video::IShaderConstantSetCallBack
  {public:
   // Constructor..
   CShaderMaterial(IrrlichtDevice* SetDevice);
   ~CShaderMaterial();
   virtual void OnSetConstants(video::IMaterialRendererServices* services, s32 userdata);
   u32 GenerateTheMaterialID();  // TheMaterialID 
   void        SetShaderLanguage (video::E_DRIVER_TYPE DriverType); // so we dont have to keep recalling the get funct..
   void        SetVertexProgramFileName     (const char* FileName);
   void        SetFragmentShaderFileName    (const char* FileName);
   const char* GetVertexShaderFileName      ();
   const char* GetFragmentShaderFileName    ();
   void        SetVertexEntryFunctionName   (const char* FuncName);
   void        SetFragmentEntryFunctionName (const char* FuncName);
   const char* GetVertexEntryFunctionName   ();
   const char* GetFragmentEntryFunctionName ();
   void        AddImageParameter            (const char* ParamName, u32 RegisterVal);
   u32 AddSpecialIntegerAlertPointer(int* AlertPtr);
   u32 AddSpecialIntegerAlertPointer(const char* ParamName, int* AlertPtr);
   void SetGlobalIntegerPointer(int* Ptr); // Redundant, test only..
 
   // SHOULD THESE RETURN THE INDICES AS GENERATED??? (Yes!!)
   u32         AddVertexIntegerParameter          (const char* ParamName, u32 InitialVal);
   u32         AddFragmentIntegerParameter        (const char* ParamName, u32 InitialVal);
   u32         AddVertexFloatParameter            (const char* ParamName, f32 InitialVal);
   u32         AddFragmentFloatParameter          (const char* ParamName, f32 InitialVal);
   u32         AddVertexMatrixParameter           (const char* ParamName, core::matrix4 InitialVal);
   u32         AddFragmentMatrixParameter         (const char* ParamName, core::matrix4 InitialVal);
   //  - ONLY FRAGMENT "Images" - 
   u32         AddFragmentImageNameAndLayerNo     (const char* ParamName, s32 InitialVal);
   s32         GetFragmentImageLayerNoByName      (const char* ParamName);
   s32         GetFragmentImageLayerNoByIndex     (u32 Index);
   const char* GetFragmentImageNameByLayerNo      (u32 LayerNo);
   const char* GetFragmentImageNameByIndex        (u32 Index);
   // Get Sizes..
   u32         GetVertexIntegerParameterCount     ();
   u32         GetFragmentIntegerParameterCount   ();
   u32         GetVertexFloatParameterCount       ();
   u32         GetFragmentFloatParameterCount     ();
   u32         GetVertexMatrixParameterCount      ();
   u32         GetFragmentMatrixParameterCOunt    ();
   u32         GetFragmentImageAndLayerCount      ();
 
   // The thing with arrays is that their SIZES MUST BE DECLARED in the shadercode itself, leaving
   // us with no freedom to change their sizes during runtime..
   // This means that the arrays as they are declared in the shaders MUST MATCH their counterparts in our User App Code..
   // Not used yet..
   u32         AddVertexFloatArrayParameter       (const char* ParamName, u32 ArraySize);
   u32         AddFragmentFloatArrayParameter     (const char* ParamName, u32 ArraySize);
   u32         AddVertexIntegerArrayParameter     (const char* ParamName, u32 ArraySize);
   u32         AddFragmentIntegerArrayParameter   (const char* ParamName, u32 ArraySize);
 
   const char*   GetVertexIntParamNameByIndex       (u32 Index);
   const char*   GetFragmentIntParamNameByIndex     (u32 Index);
   const char*   GetVertexFloatParamNameByIndex     (u32 Index);
   const char*   GetFragmentFloatParamNameByIndex   (u32 Index);
   const char*   GetVertexMatrixParamNameByIndex    (u32 Index);
   const char*   GetFragmentMatrixParamNameByIndex  (u32 Index);
   u32           GetVertexIntParamValueByIndex      (u32 Index);
   u32           GetFragmentIntParamValueByIndex    (u32 Index);
   f32           GetVertexFloatParamValueByIndex    (u32 Index);
   f32           GetFragmentFloatParamValueByIndex  (u32 Index);
   core::matrix4 GetVertexMatrixParamValueByIndex   (u32 Index);
   core::matrix4 GetFragmentMatrixParamValueByIndex (u32 Index);
   u32           GetVertexIntParamValueByName       (const char* Name);
   u32           GetFragmentIntParamValueByName     (const char* Name);
   f32           GetVertexFloatParamValueByName     (const char* Name);
   f32           GetFragmentFloatParamValueByName   (const char* Name);
   core::matrix4 GetVertexMatrixParamValueByName    (const char* Name);
   core::matrix4 GetFragmentMatrixParamValueByName  (const char* Name);
 
   void          SetVertexIntParamByIndex            (u32 ParamIndex, u32   Value);
   void          SetFragmentIntParamByIndex          (u32 ParamIndex, u32   Value);
   void          SetVertexFloatParamByIndex          (u32 ParamIndex, float Value);
   void          SetFragmentFloatParamByIndex        (u32 ParamIndex, float Value);
   void          SetVertexMatrixParamByIndex         (u32 ParamIndex, core::matrix4 Value);
   void          SetFragmentMatrixParamByIndex       (u32 ParamIndex, core::matrix4 Value);
   // Set Single Variables by Name (possible with Irr Arrays emulating the Map)..
   void          SetVertexIntParamByName             (const char* Name, int   Value);
   void          SetFragmentIntParamByName           (const char* Name, int   Value);
   void          SetVertexFloatParamByName           (const char* Name, float Value);
   void          SetFragmentFloatParamByName         (const char* Name, float Value);
   void          SetVertexMatrixParamByName          (const char* Name, core::matrix4 Value);
   void          SetFragmentMatrixParamByName        (const char* Name, core::matrix4 Value);
 
   void          SetVertexIntArrayParamByIndex      (u32 ParamIndex, u32 ArrayIndex, u32 Value);
   void          SetFragmentIntArrayParamByIndex    (u32 ParamIndex, u32 ArrayIndex, u32 Value);
   void          SetVertexFloatArrayParamByIndex    (u32 ParamIndex, u32 ArrayIndex, float Value);
   void          SetFragmentFloatArrayParamByIndex  (u32 ParamIndex, u32 ArrayIndex, float Value);
 
   // Set Arrays by Name..
   //   void  SetVertexIntArrayParamByName       (const char* ParamName, u32 ArrayIndex, u32 Value);
   //   void  SetFragmentIntArrayParamByName     (const char* ParamName, u32 ArrayIndex, u32 Value);
   //   void  SetVertexFloatArrayParamByName     (const char* ParamName, u32 ArrayIndex, float Value);
   //   void  SetFragmentFloatArrayParamByName   (const char* ParamName, u32 ArrayIndex, float Value);
   private:
   IrrlichtDevice*                 PassedIrrDevice;
   video::IVideoDriver*            AquiredVideoDriver;
   video::IGPUProgrammingServices* ThePrivateGPUServices;
 
   core::stringc TextureName[video::MATERIAL_MAX_TEXTURES]; // In the engine-recompile this is now 8??..
   core::stringc Name;        // Material id..
   video::SMaterial Material; // Material..
 
   u32 GeneratedShaderID;
   core::array <const char*> ImageNames;
   // The Indices into these arrays should remain parrallel throughout..
   core::array <u32>           VertexIntegerValues;
   core::array <f32>           VertexFloatValues;
   core::array <int>           FragmentIntegerValues;
   core::array <f32>           FragmentFloatValues;
   core::array <core::stringc> VertexIntParamNames;
   core::array <core::stringc> VertexFloatParamNames;
   core::array <core::stringc> VertexIntArrayParamNames;
   core::array <core::stringc> VertexFloatArrayParamNames;
   core::array <core::stringc> FragmentIntParamNames;
   core::array <core::stringc> FragmentFloatParamNames;
   core::array <core::stringc> FragmentIntArrayParamNames;
   core::array <core::stringc> FragmentFloatArrayParamNames;
   core::array <core::stringc> VertexMatrixParamNames;
   core::array <core::matrix4> VertexMatrixValues;
   core::array <core::stringc> FragmentMatrixParamNames;
   core::array <core::matrix4> FragmentMatrixValues;
   core::array <core::stringc> FragmentImageNames;
   core::array <s32> FragmentImageLayerNumbers;
   core::array <int*> IntegerAlertsArray; // Special Pointers to make "Inter Shader Comms Possible"..
   core::array <core::stringc> IntegerAlertsNames;
 
   // Just a test for "Inter Shader Comms"..
   int* GlobalIntegerPointer;
 
   core::stringc VERTProgFileName;
   core::stringc FRAGProgFileName;
   core::stringc VERTEntryFuncName;
   core::stringc FRAGEntryFuncName;
 
   // Haveing these values as stand alone variables may be faster than 
   // aquireing them with .size() each time they are needed.??
 
   u32 VertexInCount;
   u32 VertexFloatCount;
   u32 FragmentIntCount;
   u32 FragmentFloatCount;
   u32 VertexMatrixCount;
   u32 FragmentMatrixCount;
   u32 FragmentImageCount;
   u32 IntAlertPointerCount;
 
   u32 TheMaterialID;
   core::matrix4                   M01World;
   core::matrix4                   M05WorldViewProjection;
   core::matrix4                   M17WorldInverseTranspose;
   video::E_DRIVER_TYPE            SelDriverType;
  };
 
 
 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 
 // This object is a representation of a shader in such a way that multiple shaders can be managed  
 // in a more modular way than simply referring to shader filenames and callbacks..
 // Among other things it allows handling different "families" of shaders in a modular and standardised way..
 // It ensures that we need only one callback for different types of human-readable ascii based shaders..
 
 //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
 class SmartShaderManager
  {public:
   SmartShaderManager();
   ~SmartShaderManager();
   void         AddShader (char* VertFilename, char* FragFilename);
   u32          GetShaderCount ();
   void         SetDevice(IrrlichtDevice* SetDevice);
   u32          GenerateMaterialID (u32 ShaderIndex);
   CShaderMaterial* AccessShader(u32 Index);
   private:
   core::array <CShaderMaterial*> ShaderMaterials;
   IrrlichtDevice*                 PassedIrrDevice;
   video::IVideoDriver*            AquiredVideoDriver;
   video::IGPUProgrammingServices* ThePrivateGPUServices;
  };
 
 // Method definition code you can see in the file posted in the link below..
 
 #endif
 
 
Vectrotek
Competition winner
Posts: 1087
Joined: Sat May 02, 2015 5:05 pm

Re: Realistic water node

Post by Vectrotek »

Vectrotek
Competition winner
Posts: 1087
Joined: Sat May 02, 2015 5:05 pm

Re: Realistic water node

Post by Vectrotek »

Here is an example of usage in your code:


Code: Select all

 
    SmartShaderCollection.AddShader ("Shaders/GL_0002_VERT_STANDARD.glsl",
                                     "Shaders/GL_0004_FRAG_STANDARD_2T_COORD.glsl"
                                    );
    SmartShaderCollection.AccessShader (RunningIndex)-> SetShaderLanguage (EDT_OPENGL);
    SmartShaderCollection.AccessShader (RunningIndex)-> SetVertexEntryFunctionName      ("main");
    SmartShaderCollection.AccessShader (RunningIndex)-> SetFragmentEntryFunctionName    ("main");
    SmartShaderCollection.AccessShader (RunningIndex)-> AddVertexMatrixParameter        ("M01World", M01World);
    SmartShaderCollection.AccessShader (RunningIndex)-> AddFragmentIntegerParameter     ("UnderWaterStatus", 0);
    SmartShaderCollection.AccessShader (RunningIndex)-> AddFragmentImageNameAndLayerNo  ("Image001", 0);
    SmartShaderCollection.AccessShader (RunningIndex)-> AddFragmentImageNameAndLayerNo  ("Image002", 1);
 
    // NEW SPECIAL ALERT POINTERS WITH NAMES..
    // The Reason for having names here is sothat we DONT HAVE TO ENSURE THEY ARE ORDERED IN THE SHADER..
    // But, when you release your product, the name issue will be replaced by FAST AND HARD methods..
    // This, however allows you to experiment with shaders and intercommunication between them more easily..
    SmartShaderCollection.AccessShader (RunningIndex)-> AddSpecialIntegerAlertPointer("ClipAboveOrBelow",&GlobalPlaneDirAlert);
    SmartShaderCollection.AccessShader (RunningIndex)-> AddSpecialIntegerAlertPointer("DepthRender",&GlobalDepthAlert);
 
The main reason for this is that some objects have multiple drawAll() calls..
It is within the drawAll() calls that this does its work.
An example would be a "render" function in the water renderer that can set states which shoudl be "visible" to
other parts of the program..

Example..

Code: Select all

 
 void RealisticWaterSceneNode::render() // Called as an abstraction..
  {core::vector3df CheckPos = PrivateSceneManager->getActiveCamera()->getPosition();
   if (CheckPos.Y >= 0.0) {AboveOrBelowWaterPlane = true;}
   if (CheckPos.Y < 0.0)  {AboveOrBelowWaterPlane = false;}
   // The rest of the world shoudl know what these are at the
   // moment of ALL DRAW CALLS!!
   // ...other code...
  )
 
Vectrotek
Competition winner
Posts: 1087
Joined: Sat May 02, 2015 5:05 pm

Re: Realistic water node

Post by Vectrotek »

Here is an example of an "Other World" object that
should be rendered "in tune" with the water parameters (depth related darkness)..
Image

Here is the one of the "Render Modes" in which such
an object could be rendered..
The main issue is to have ALL Draw Calls of ALL objects
"synchronized" which can be complicated with MANY Draw Calls
by MANY different "Custom Nodes".
Image
Two Forty AM.. Time to sleep..
Vectrotek
Competition winner
Posts: 1087
Joined: Sat May 02, 2015 5:05 pm

Re: Realistic water node

Post by Vectrotek »

The reflection works O.K-ish.
From below the plane is a simpler process as I don't really
have to worry about edges like when camera point of view is above the plane.
(below the plane will be blurred a lot, so edges...)

Image
Vectrotek
Competition winner
Posts: 1087
Joined: Sat May 02, 2015 5:05 pm

Re: Realistic water node

Post by Vectrotek »

The problem is a "Smart Shaders" idea integrated to the
Water node. The Node uses "onSetConstants()" and "onAnimate()"
which complicates things plus it is related to Callbacks which don't like
containing pointers to "IrrlichtDevice" for some reason which we need to get
Smart Shaders working..
"onAnimate()" is not called at every DrawCall, but "onSetConstants()" is..
It's all about Clipping at the right time, Colouring at the right time,
Rendering to the right buffer at the right time etc etc..

Image
Vectrotek
Competition winner
Posts: 1087
Joined: Sat May 02, 2015 5:05 pm

Re: Realistic water node

Post by Vectrotek »

Maybe just handle Water Node as a completely stand alone
module which handles its own shaders.
Things can still be communicated to the world via global pointers
so it should be all right.
The Project is not presentable nor postable, yet..

Image
Vectrotek
Competition winner
Posts: 1087
Joined: Sat May 02, 2015 5:05 pm

Re: Realistic water node

Post by Vectrotek »

Intercommunication between shaders work fine but
it is un-elegant getting Water Shaders to cooperate
if they are not also in the Smart Shader collection class.
The TWO Cameras needed to render to Refraction and Reflection
also complicates any Smart Shader idea.

Image

Cheers!
Last edited by Vectrotek on Thu Aug 25, 2016 8:17 pm, edited 2 times in total.
Vectrotek
Competition winner
Posts: 1087
Joined: Sat May 02, 2015 5:05 pm

Re: Realistic water node

Post by Vectrotek »

Image
Vectrotek
Competition winner
Posts: 1087
Joined: Sat May 02, 2015 5:05 pm

Re: Realistic water node

Post by Vectrotek »

This is better for handling Matrices..

Code: Select all

 
   void CShaderMaterial::NameVertexWORLDMatrix                   (const char* Name)
    { VertexWORLDMatrixUsedFlag = true;
      VertexWORLDMatrixName = Name;
    }
   void CShaderMaterial::NameVertexWORLDVIEWPROJECTIONMatrix     (const char* Name)
    { VertexWORLDVIEWPROJECTIONMatrixUsedFlag = true;
      VertexWORLDVIEWPROJECTIONMatrixName = Name;
    }
   void CShaderMaterial::NameVertexWORLDINVERSETRANSPOSEMatrix   (const char* Name)
    { VertexWORLDINVERSETRANSPOSEMatrixUsedFlag = true;
      VertexWORLDINVERSETRANSPOSEMatrixName = Name;
    }
   void CShaderMaterial::NameVertexWORLDVIEWPROJECTIONREFLECTEDMatrix(const char* Name)
    { VertexWORLDVIEWPROJECTIONREFLECTEDMatrixUsedFlag = true;
      VertexWORLDVIEWPROJECTIONREFLECTEDMatrixName = Name;
    }
   void CShaderMaterial::NameFragmentWORLDMatrix                 (const char* Name)
    { FragmentWORLDMatrixUsedFlag = true;
      FragmentWORLDMatrixName = Name;
    }
   void CShaderMaterial::NameFragmentWORLDVIEWPROJECTIONMatrix   (const char* Name)
    { FragmentWORLDVIEWPROJECTIONMatrixUsedFlag = true;
      FragmentWORLDVIEWPROJECTIONMatrixName = Name;
    }
   void CShaderMaterial::NameFragmentWORLDINVERSETRANSPOSEMatrix (const char* Name)
    { FragmentWORLDINVERSETRANSPOSEMatrixUsedFlag = true;
      FragmentWORLDINVERSETRANSPOSEMatrixName = Name;
    }
   void CShaderMaterial::NameFragmentWORLDVIEWPROJECTIONREFLECTEDMatrix(const char* Name)
    { FragmentWORLDVIEWPROJECTIONREFLECTEDMatrixUsedFlag = true;
      FragmentWORLDVIEWPROJECTIONREFLECTEDMatrixName = Name;  // Ummm...
    }
Because the Callback includes..

Code: Select all

 
     if (VertexWORLDMatrixUsedFlag == true)
      {M01World = TheDriver->getTransform(video::ETS_WORLD); // For GLSL this is all we need for Physically Based Lighting!
       TheMATRENDServices->setVertexShaderConstant("M01World", M01World.pointer(), 16);
      } 
     if (VertexWORLDVIEWPROJECTIONMatrixUsedFlag == true)
      {M05WorldViewProjection =   TheDriver->getTransform(video::ETS_PROJECTION);
       M05WorldViewProjection *=  TheDriver->getTransform(video::ETS_VIEW);
       M05WorldViewProjection *=  TheDriver->getTransform(video::ETS_WORLD); // order? 
       TheMATRENDServices->setVertexShaderConstant("M05WorldViewProjection", M05WorldViewProjection.pointer(), 16);
      } 
      if (VertexWORLDINVERSETRANSPOSEMatrixUsedFlag == true)
      {M01World = TheDriver->getTransform(video::ETS_WORLD);
       M17WorldInverseTranspose = M01World.getTransposed();
       TheMATRENDServices->setVertexShaderConstant("M17WorldInverseTranspose", M17WorldInverseTranspose.pointer(), 16);
      } 
     // etc etc..
 
I think..
Vectrotek
Competition winner
Posts: 1087
Joined: Sat May 02, 2015 5:05 pm

Re: Realistic water node

Post by Vectrotek »

Rendering water "Above" and "Below" gets really-really complicated!
I wondered how to get a better handle on "what happens when",
so I "printed" to the "Console" each time something important happens.
This really helped polish the chronologies nicely..
There is still no "Smart Shader" for Water but that is
really better for it to be a truly stand alone module..

Image

I'll post the project ev-e-e-e-ntually. :)
Vectrotek
Competition winner
Posts: 1087
Joined: Sat May 02, 2015 5:05 pm

Re: Realistic water node

Post by Vectrotek »

Finally..
Image
Last edited by Vectrotek on Tue Sep 20, 2016 4:50 pm, edited 1 time in total.
Vectrotek
Competition winner
Posts: 1087
Joined: Sat May 02, 2015 5:05 pm

Re: Realistic water node

Post by Vectrotek »

Controls:

Key: Action:

G Toggle Music On or Off.. (to hear water above and below noise)
0 Toggle Post Processing Mode (On by default)

1 Shift Pass# 1 Post Processing Effect Up.
2 Shift Pass# 2 PP Effect Up.
3 Shift Pass# 3 PP Fx Up.
4 Shift Pass# 4 PP Up.
5 Shift Pass# 4 PP Up.
6 Shift Pass# 4 PP Up.
7 Shift Pass# 4 PP Up.
8 Shift Pass# 4 PP Up.
Shift & 1 Reset PostProcessing for Pass 1 to "Bypass" (does nothing).
Shift & 2 Reset PostProcessing for Pass 2 to "Bypass" (does nothing).
Shift & 3 Reset PostProcessing for Pass 3 to "Bypass" (does nothing).
Shift & 4 Reset PostProcessing for Pass 4 to "Bypass" (does nothing).
Shift & 5 Reset PostProcessing for Pass 5 to "Bypass" (does nothing).
Shift & 6 Reset PostProcessing for Pass 6 to "Bypass" (does nothing).
Shift & 7 Reset PostProcessing for Pass 7 to "Bypass" (does nothing).
Shift & 8 Reset PostProcessing for Pass 8 to "Bypass" (does nothing).
9 Reset ALL Passes PP to "Bypass".
W,A,S,D Camera Movement..
Arrows Camera Movement..
T Randomize FIRST Four Passes Effects.
Y Randomize LAST Four Passes Effects.



NOTE: THESE ARE THE SETTINGS YOU PLAY WITH TO GET THE RIGHT EFFECT.
TIP: WHEN IN GREY SCALE PP MODE THE WATER SHOULD NEVER BE LIGHTER THAN THE REST (use as a test)..
ALSO AS OPACITY DECREASES COLOUR APPEARS BRIGHTER SO DARKEN COLOUR WITH INCREASE OPACITY.
ALWAYS CHECK IN GREYSCALE MODE FOR LIGHTNESS.

These are the MAIN WATER RENDERER CONTROLS ..
Takes getting to know, but this is how different waters are simulated..
E Increase "Water Murk"
R Decrease "Water Murk"
Shift & E Decrease Water Colour Scale.
Shift & R Increase Water Colour Scale.
F Increase Liquid Opacity.
C Decrease Liquid Opacity.
M Randomize Water Colour.

U Speed Up Cloud Movement
H Slow Down Cloud Movement
I Scale Cload Layer A Smaller. (make appear further)
J Scale Cload Layer A Larger. (make appear closer)
O Scale Cload Layer B Smaller. (make appear further)
K Scale Cload Layer B Larger. (make appear closer)
P Scale Cload Layer B Smaller. (make appear further)
L Scale Cload Layer B Larger. (make appear closer)

V Toggle Debug Text Display.
B Toggle Water Renderer Debug Images Display.

Put on your earphones..
Last edited by Vectrotek on Mon Sep 19, 2016 9:12 pm, edited 1 time in total.
Vectrotek
Competition winner
Posts: 1087
Joined: Sat May 02, 2015 5:05 pm

Re: Realistic water node

Post by Vectrotek »

O.K.

First, If you see what looks like your code in here, then it probably is.
So, to all those guys who shared their code (of whom there are too many to thank individually)..
Thanks a big pile! (specially to Cute Alien, Elvman, Devsh and tbw)..

It started off as an experiment in Deferred Rendering but then quickly evolved
into a Water Renderer.
I then added Three Layers of Animated Clouds and Lensflares from a Synthetic Sun.

I added a few Screen Quad Post Processing Passes (eight of em) for Both GL's GLSL and DX's HLSL. (they both work)
(most notably NVIDIA's FXAA T.L. for BOTH GLSL & HLSL)

One night I paged through some old stuff and found a little layer I wrote
for the "Audiere" Sound System to make using it a bit easier. (there was an undocumented issue somewhere)
I pasted it in to see how it would work and.. Now we've got sound! Cool!
(for compiling I had included the "*.lib" and header for your IDE, but get the whole thing yourself)
The sound system plays "Wave Samples" like water splashes in Ogg Vorbis Format
and plays "Sequenced" Track Music like "*.it", "*.mod", "s3m" and the rest.
I think it worked quite well! Audierre is very powerful and often overlooked.
Clever controlling of the "Pan" (balance) versus Sound Source Position could even give
you "3D Directional Sound". (definitely something I'm looking into later)
I also tried changing the "mood" between above water and below water using different music
triggered by a single frame flag in "Enter Water" or "Exit Water" state..
The noise of the water above differs from the water flow below..

The Water renderer which is actualy what this is all about does some unique things.
For depth, plane calculations were dropped in favor of fragment distance from the ZERO Point
on the Y axis.. Planes are cool but for this world where water is at X Y Z Zero with Normal at Y: 1,
distance on Y will do.
This distance is split into RGB for different parts which act on different attributes of the water
like Normal Damping, Colour Intensity and Murk.
Opacity is lerped into the render near the end of the Water Shader.
Opacity is a new thing that could be explained as the difference between blue spirits
and matte blue paint. They are both the same colour but have different ways in which light is
allowed to pass through.
Water is a really complex thing and comes in many different colours, opacities and murkiness.
An example would be a pool into which chlorine was thrown. First the green water looks
"milky blue green" then slowly turns clear low saturation blue.
The water in a river, just after rain is a Matte Brown colour but still reflects under Fresnel rules.

Play around with the settings using the relevant keyboard controls and you'll soon see that you
can emulate almost any kind of liquid.

I implemented "Global Alert Pointers", something that would allow the water renderer to share it's
"states" with the rest of the world so that objects that touch the water would have
their shaders be aware of the state in which the water renderer is in at the moment of rendering
these world objects.
Darkening via gradient of surfaces that are underwater is an example.

Now, the project is ongoing and obviously will be improved but I don't have time right now
and I'm still a bit of an Irrlicht noob.
It might look big and ugly, but it is reasonably modular for you to try your own Things on.
Smart Shaders haven't been incorporated into the PP system yet, but you can see it working on the
two static objects. PP Shaders still acts independently.
The start of this conversion process was left in the code so continuing shouldn't be too hard..
This is no quick lesson like you'd find in the examples package, so if you like it hold on to it
and look at it when you've got time. ("Tiny Upload" holds material for 90 days before deleting it)

Smart shaders simply lets you "add" shaders and their feed variables so that the Callback automatically
knows what variables to send. It also avoids D3D bombarding your console with warnings when you
send a variable that is not in your shader code. (glsl doesn't have this issue)

The main reason I posted this is so that people can let me know if there are
any serious problems in the coding.
Id really appreciate critique, so let me have it..
Feel free to use any of the code in your own stuff!

Software used: Irrlicht, Blender, ModPlugTracker, Audacity, Cool Edit, Coolspeech, ZBrush (wavenormals) and Photoshop..

At some point I had to stop beautifying the code, sorry..
Put on your earphones..

Here is the full project: http://s000.tinyupload.com/?file_id=053 ... 2700644252
Enjoy..
Post Reply