Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
1.1.0:water [2023/10/24 15:47] – [Water Material] admin1.1.0:water [2024/01/23 08:23] (current) – [Example] admin
Line 3: Line 3:
 A water surface is not seldomly a popular game component. We do not provide directly a water surface component, but it is quite easy to setup one. A water surface is not seldomly a popular game component. We do not provide directly a water surface component, but it is quite easy to setup one.
  
-{{ :water-example.jpg |}}+The water shader generates the surface by using different textures: DUDV, Normal, Specular, Displacement, Foam and ShoreFoam. 
 +By those user specific textures you can control the look of your water. 
 + 
 +Besides texturing you'll need additional render pass computation for rendering depth, refraction and reflection. 
 + 
 +{{:1.1.0:g3d-water-new.png|}}
  
 Water rendering is based on: Water rendering is based on:
-  * a plane +  * TGorillaPlane (best results) 
-  * refraction computation +  * TGorillaWaterMaterialSource 
-  * reflection computation +  * TGorillaRenderPassReflection (Reflections) 
-  * and the water shader itself+  * TGorillaRenderPassRefraction (Depth + Refraction)
 ===== Components ===== ===== Components =====
  
Line 15: Line 20:
  
 The plane is a simple and opaque instance of TGorillaPlane or TPlane. It will be used as basis mesh to render water onto. The plane is a simple and opaque instance of TGorillaPlane or TPlane. It will be used as basis mesh to render water onto.
 +
 +Using a none planar object is not recommended, because reflection and refraction computation is based on plane models.
  
 ==== Refraction ==== ==== Refraction ====
Line 27: Line 34:
 FRefraction.IgnoreControl(FWaterPlane); FRefraction.IgnoreControl(FWaterPlane);
 </file> </file>
 +
 The water surface would be black, because it's image information will be computed in main render pass first. The water surface would be black, because it's image information will be computed in main render pass first.
 +
 +Because the refraction pass should render from a certain position, we have to adjust the surface position to the current water plane position everytime it changes:
 +<file pascal>
 +  // set the current position of the water plane as surface plane
 +  // this needs to be updated, if water plane moves
 +  FRefraction.SurfacePosition.Point := TPoint3D(FWaterPlane.AbsolutePosition);
 +</file>
  
 ==== Reflection ==== ==== Reflection ====
Line 47: Line 62:
   // set the current position of the water plane as mirror plane   // set the current position of the water plane as mirror plane
   // this needs to be updated, if water plane moves   // this needs to be updated, if water plane moves
-  FReflection.MirrorPosition := TPoint3D(FWaterPlane.AbsolutePosition);+  FReflection.MirrorPosition.Point := TPoint3D(FWaterPlane.AbsolutePosition);
 </file> </file>
  
 In case plane size or position changes, you have to update those values in reflection pass. In case plane size or position changes, you have to update those values in reflection pass.
  
 +==== Displacement ====
 +
 +Our water shader supports displacement mapping to render waves. This manipulates vertex position in the vertex shader.
 +To use displacement mapping, apply a tetxure to the "DisplacementMap" property and configure the intensity of waves by
 +the "DisplIntensity" property of your material source.
 +
 +When working with displacement mapping, vertices getting shifted. This leads to offsets in refraction and reflection, because
 +in those render passes we rendered with different information.
 +
 +Therefor you have to adjust the reflection mirror position and refraction surface position by the "DisplIntensity" value:
 +
 +<file pascal>
 +  FReflection.MirrorPosition.Point := TPoint3D(FWaterPlane.AbsolutePosition) + 
 +    Point3D(0, -FWaterMaterial.DisplIntensity, 0);
 +    
 +  FRefraction.SurfacePosition.Point := TPoint3D(FWaterPlane.AbsolutePosition) + 
 +    Point3D(0, -FWaterMaterial.DisplIntensity, 0);
 +</file>
 ==== Water Material ==== ==== Water Material ====
  
Line 99: Line 132:
 | ReflCorrection | By this value you can modify the color of reflection, default value: Vector3D(1.0, 1.0, 1.0, 1.0) | | ReflCorrection | By this value you can modify the color of reflection, default value: Vector3D(1.0, 1.0, 1.0, 1.0) |
 | RefrCorrection | By this value you can modify the color of refraction on water surface, default value: Vector3D(1.1, 1.1, 1.1, 1.0) | | RefrCorrection | By this value you can modify the color of refraction on water surface, default value: Vector3D(1.1, 1.1, 1.1, 1.0) |
 +|DepthIntensity|Control the depth map value intensity while computation. This influences the blending of edges and the mixture between refraction and reflection.| 
 +|DisplIntensity|Control displacement mapping intensity| 
 +|FoamIntensity|Control the color intensity of the applied foam texture.| 
 +|ShoreIntensity|Control the color intensity of the applied shore foam texture.| 
 +|ShoreWidth|Increase or decrease the size of the shore where the texture affects|
 ==== Ripples ==== ==== Ripples ====
  
Line 129: Line 166:
 end; end;
 </file> </file>
 +
 +Ripple computation in the vertex shader is embedded inside our water shader program.
 +In case you'll need additional handling in the fragment shader, you could a code snippet like that.
 +
 +<file Pascal>
 +var LStr := TStringList.Create();
 +try
 +  LStr.Text := 
 + '''
 +   void SurfaceShader(inout TLocals DATA){
 + float l_TotalRippleEffect = 0.0;
 + float l_Time = abs(_TimeInfo.w);
 + vec3 l_TransfVertexPos = DATA.TransfVertPos.xyz;
 +
 + for(int i = 0; i < int(_RippleCount); i++){
 +   float l_RippleDist = distance(l_TransfVertexPos.xz, _Ripples[i].xz);
 +   float l_RippleTime = abs((_TimeInfo.x + l_Time) - _Ripples[i].w);
 +   float l_TimeLimit = clamp(1.0 / (l_RippleTime / (_RippleProximity * _RippleDecay)), 0.0, 1.0);
 +
 +   float l_RippleEffect = (-_RippleAmplification * exp(_RippleDecay * - l_RippleDist));
 +   l_RippleEffect *= cos(_RippleProximity * (l_RippleDist - l_RippleTime));
 +   l_RippleEffect *= l_TimeLimit;
 +
 +   l_TotalRippleEffect += exp(-l_RippleDist) * sin(0.5 * l_RippleDist) * l_RippleEffect;
 + }
 +
 + if(l_TotalRippleEffect > 0.01){
 +   vec4 l_BoatTrail = tex2D(_WaterShore, DATA.TexCoord0.xy);
 +   DATA.BaseColor.rgb += vec3(l_BoatTrail.rgb * l_TotalRippleEffect);
 +   DATA.SumColor.rgb += vec3(l_BoatTrail.rgb * l_TotalRippleEffect);
 + }
 +   }
 + ''';
 +
 +  FWaterMat.SurfaceShader := LStr;
 +finally
 +  LStr.Free;
 +end;
 +</file>
 +
 +This snippet will render the water shore texture onto the ripples if they have a minimum size of 0.01.
 +===== Tutorial =====
 +
 +{{youtube>bIXeUcTrd58}}
 +
 ===== Example ===== ===== Example =====