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/25 08:00] – [Water] admin | 1.1.0:water [2024/01/23 08:23] (current) – [Example] admin | ||
---|---|---|---|
Line 2: | Line 2: | ||
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. | ||
+ | |||
The water shader generates the surface by using different textures: DUDV, Normal, Specular, Displacement, | 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. | 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. | ||
{{: | {{: | ||
Line 10: | Line 13: | ||
* TGorillaPlane (best results) | * TGorillaPlane (best results) | ||
* TGorillaWaterMaterialSource | * TGorillaWaterMaterialSource | ||
- | * TGorillaRenderPassReflection | + | * TGorillaRenderPassReflection |
- | * TGorillaRenderPassRefraction | + | * TGorillaRenderPassRefraction |
===== Components ===== | ===== Components ===== | ||
Line 17: | 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 29: | 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 49: | 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 135: | 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 ===== | ||