Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
1.1.0:water [2023/10/24 15:47] – [Water Material] admin | 1.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, |
+ | 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, | ||
==== Refraction ==== | ==== Refraction ==== | ||
Line 27: | Line 34: | ||
FRefraction.IgnoreControl(FWaterPlane); | FRefraction.IgnoreControl(FWaterPlane); | ||
</ | </ | ||
+ | |||
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); | ||
+ | </ | ||
==== 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 |
</ | </ | ||
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 " | ||
+ | the " | ||
+ | |||
+ | 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 " | ||
+ | |||
+ | <file pascal> | ||
+ | FReflection.MirrorPosition.Point := TPoint3D(FWaterPlane.AbsolutePosition) + | ||
+ | Point3D(0, -FWaterMaterial.DisplIntensity, | ||
+ | | ||
+ | FRefraction.SurfacePosition.Point := TPoint3D(FWaterPlane.AbsolutePosition) + | ||
+ | Point3D(0, -FWaterMaterial.DisplIntensity, | ||
+ | </ | ||
==== Water Material ==== | ==== Water Material ==== | ||
Line 99: | Line 132: | ||
| ReflCorrection | By this value you can modify the color of reflection, default value: Vector3D(1.0, | | ReflCorrection | By this value you can modify the color of reflection, default value: Vector3D(1.0, | ||
| RefrCorrection | By this value you can modify the color of refraction on water surface, default value: Vector3D(1.1, | | RefrCorrection | By this value you can modify the color of refraction on water surface, default value: Vector3D(1.1, | ||
+ | |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; | ||
</ | </ | ||
+ | |||
+ | 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); | ||
+ | float l_RippleDist = distance(l_TransfVertexPos.xz, | ||
+ | float l_RippleTime = abs((_TimeInfo.x + l_Time) - _Ripples[i].w); | ||
+ | float l_TimeLimit = clamp(1.0 / (l_RippleTime / (_RippleProximity * _RippleDecay)), | ||
+ | |||
+ | 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.BaseColor.rgb += vec3(l_BoatTrail.rgb * l_TotalRippleEffect); | ||
+ | DATA.SumColor.rgb += vec3(l_BoatTrail.rgb * l_TotalRippleEffect); | ||
+ | } | ||
+ | } | ||
+ | '''; | ||
+ | |||
+ | FWaterMat.SurfaceShader := LStr; | ||
+ | finally | ||
+ | LStr.Free; | ||
+ | end; | ||
+ | </ | ||
+ | |||
+ | This snippet will render the water shore texture onto the ripples if they have a minimum size of 0.01. | ||
+ | ===== Tutorial ===== | ||
+ | |||
+ | {{youtube> | ||
+ | |||
===== Example ===== | ===== Example ===== | ||