We have a new example examples/viewport_and_scenes/mesh_update that may be quite useful to many developers. It shows two approaches to update a mesh at runtime. This has a lot applications — e.g. you may want to animate / deform the mesh following some algorithm or allow for some user interactions or game events to change the mesh.
Quoting from the example README:
This example demonstrates how to dynamically (as often as possible, to reflect e.g. time passing by) update the mesh of a 3D object, while still being efficient. There are 2 approaches:
- Call
TCoordinateNode.SetPoint
as often as you want, e.g. from view’sUpdate
method.In this example, every
TViewMain.Update
increasesTime
and then callsTViewMain.UpdateCoordinateNode
. TheTViewMain.UpdateCoordinateNode
updates the coordinates of the 3D object, theTime
affects the waves shape.The point here is that
TCoordinateNode.SetPoint
is very efficient. It only updates the necessary rendering resource (VBO contents in OpenGL) and doesn’t do any unnecessary work (doesn’t rebuild anything, doesn’t recreate any resource from scratch). -
Use shaders. You can use our shader effects to add a vertex shader that changes the position of each vertex right when it’s supposed to be displayed.
The advantage is that this is even faster because the Pascal code does almost nothing — we just pass the new
Time
value to the shader. The per-vertex calculation is done by GPU, and GPUs are ridiculously fast at this.On one test system:
- The first approach (TCoordinateNode.SetPoint) was able to handle 100 x 100 grid with 60 FPS. But once grid size increased to 200 x 200 it dropped to 18 FPS (in debug) or 38 FPS (in release).
Note that changing the height calculation (to avoid
Sin
in Pascal) does not significantly change these measurements. TheSin
, and in general how theH
is calculated in Pascal, is not a bottleneck. -
And the shader approach could handle 1000 x 1000 grid with 60 FPS. At 2000 x 2000 grid it dropped to 20 FPS. So, it’s 100x more performant, if you look at the number of triangles it can handle while still maintaining 60 FPS!
Note that changing the height calculation (to avoid
sin
in GLSL) does not significantly change this. Neither does debug vs release build (which makes sense, since the speed of Pascal code cannot be the bottleneck here).
Note: For stress-testing, consider setting initial
CheckboxShader.Checked
in design totrue
, to start with more performing version immediately.The disadvantage is that Castle Game Engine is not aware of the calculated vertex positions (they remain only on GPU). So e.g. any raycasts or other collision queries will treat this mesh as if it was in the original position (flat plane in this example).
An additional potential disadvantage is that you need to learn shading language, more specifically OpenGL Shading Language (GLSL). There’s a small piece of GLSL code in data/animate_mesh.vs.
- The first approach (TCoordinateNode.SetPoint) was able to handle 100 x 100 grid with 60 FPS. But once grid size increased to 200 x 200 it dropped to 18 FPS (in debug) or 38 FPS (in release).
I encourage you to experiment with this example and try to stress-test it. It should handle very large values of GridWidth
and GridHeight
.