Example how to update mesh vertexes every frame — with or without shaders

Posted on

Update mesh example

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:

  1. Call TCoordinateNode.SetPoint as often as you want, e.g. from view’s Update method.

    In this example, every TViewMain.Update increases Time and then calls TViewMain.UpdateCoordinateNode. The TViewMain.UpdateCoordinateNode updates the coordinates of the 3D object, the Time 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).

  2. 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. The Sin, and in general how the H 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 to true, 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.

I encourage you to experiment with this example and try to stress-test it. It should handle very large values of GridWidth and GridHeight.

Start the discussion at Castle Game Engine Forum