Dynamic points in TIndexedTriangleStripSetNode?

If you build a TIndexedTriangleStripNode that you want to change every frame… can you replace the points and have it update without rebuilding the geometry? I am looking for a better way to implement my dynamic water.

My current way uses a circle at every point. It looks okay and is fast, but takes way too much memory if the water spreads too far. I use another thread to update the heights based on terrain and flow. So just updating the points in an area would be a quick thing to do if I don’t have to rebuild the whole geometry. I had tried using a castleterrain layer which looked good… but the full rebuild was too slow to happen every frame.

Yes, you can use TCoordinateNode.SetPoint to update the coordinates efficiently – underneath the necessary VBO will be updated, without destroying / creating new resources in OpenGL. I added an example with this, castle-engine/examples/viewport_and_scenes/mesh_update at master · castle-engine/castle-engine · GitHub , attaching also zip here.

mesh_update-0.1-src.zip (101.7 KB)

Note: Alternative approach (not shown in this example) for a mesh that changes every frame is to use a vertex shader, in which case the changes to vertex positions are only calculated on the GPU. See Shader Effects (Compositing Shaders) | Castle Game Engine about shaders with CGE.

1 Like

Perfect! Thanks.

I also like this example, and I decided to take it 2 steps further :slight_smile:

  1. The new version of examples/viewport_and_scenes/mesh_update showcases the alternative mesh updating option, that I mentioned previously: how to do the same using vertex shader.

    In this case, from the point of view of CGE data structures, the mesh stays constant (it is flat grid in case of this example). The vertexes only “move” when GPU processes each vertex for display. It requires to write a short piece of code using shading language (GLSL), castle-engine/examples/viewport_and_scenes/mesh_update/data/animate_mesh.vs at master · castle-engine/castle-engine · GitHub . The benefit is that this is even more efficient, since we “off-load” 100% of the processing to GPU. And GPU is ridiculously good at this – processing vertexes in parallel on hardware dedicated for this.

  2. To follow, I did small stress-testing.

    The 1st approach, with TCoodinateNode.SetPoint, is performant with 100x100 grid. FPS is 60. It gets worse at 200x200 grid, dropping to 18 FPS.

    The 2nd approach, with shaders, is performant with 1000x1000 grid (yeah, 2 million triangles) – that is, it still has 60 FPS. With 2000x2000, it degraded to 20 FPS on my system. So, looking at the number of triangles it can handle while maintaining 60 FPS, it is 100x more performing :slight_smile:

Hope you enjoy this :slight_smile: The code is committed to GitHub castle-engine/examples/viewport_and_scenes/mesh_update at master · castle-engine/castle-engine · GitHub , I also attach latest zip here for comfort. The README.md inside has more notes.

mesh_update-0.1-src.zip (235.4 KB)

1 Like

One more small update about castle-engine/examples/viewport_and_scenes/mesh_update at master · castle-engine/castle-engine · GitHub : I did some tests whether

  • removing Sin calculation during height calculation (in both variants – TCoordinateNode.SetPoint or shader) makes any speed difference. It does not. IOW the height calculation equation is not a bottleneck in this example, in both Pascal and GLSL.

  • changing the build type from “debug” to “release” changes things. Yes, it does actually, for TCoordinateNode.SetPoint. Grid 200x200 has 38 FPS instead of 18, so significant difference (but still not 60). So be aware that “release” build can squeeze a bit more performance that matters for TCoordinateNode.SetPoint.

    For shader approach, there’s no difference between debug / release builds, which makes sense – the speed of Pascal code cannot be a bottleneck there because Pascal doesn’t do much in this case per-frame.

1 Like

I don’t think the shader approach would work for me. Since this isn’t just a ripple effect, but is the flow of water calculated against the terrain. I wouldn’t be able to do all that on the gpu? Currently my terrain tiles are max resolution of 100x100 and then drop resolution as they go into the distance, the water will match the terrain. I will only calculate the update on the current tile every frame. The distant tiles can update less often. All the calculation of the water heights occurs in another thread, so the update will just have to set the height value for the vertices, without extra calculation. So I think the speed will still be good. It is good to know that release build will be faster.

My current water uses a circle (cylinder with only top) at each point. I adjust the color and the opacity depending on depth. This makes it easy to see how deep a lake is and makes the water look more realistic to me (opaque and dark when deep, light and transparent when shallow). Is it possible to accomplish the same thing using the trianglemesh? ie setting rgba at each point also? I don’t understand the x3d stuff enough yet to know (was hoping for that tutorial someone wanted to make). Perhaps a texture map of the different color and opacity values and then get the texture coordinates based on depth? But maybe that is overcomplicated?

1 Like

You can have a flat grid, and configure RGBA color (so, including transparency) at each vertex using TColorRgbaNode. This allows to specify different color for each vertex.

Updating these colors can also be done efficiently using TColorRgbaNode.SetColor that gets a color for each vertex. It is similarly optimized as TCoordinateNode.SetPoint.

We don’t have a Pascal example of using TColorRgbaNode yet. But you can check it works in X3D files in GitHub - castle-engine/demo-models: Demo 3D models (mostly in X3D and VRML formats) of view3dscene and Castle Game Engine , like this one: demo-models/x3d/elevation_grid_color_rgba.x3dv at master · castle-engine/demo-models · GitHub .

Depending on how you want to update these colors, alternative approaches are :

  • update the texture on the plane
  • update the colors in fragment shader

Let me know if these hints are useful and if an example how to follow one of above approaches would be good :slight_smile:

The water isn’t flat because it flows. I think having a palette of textures in one image to use based on depth is the way to go.

I have a prototype of my water working based on your dynamic point example. It is much much faster than my prior attempts to do water with a castle terrain layer. Currently it is just a set 50% transparent blue, but I will update it to use a palette of colors based on depth, as deep water currently looks the same as shallow. It uses a fixed amount of memory regardless of how much water. I still have issues to fix like seams between the terrain tiles that each have their own water… the seam still shows in the water as you can see in some ponds. This water is faster when there is more of it … and has a better sense of flow. There is a lot I could do to optimize.

1 Like

I now have the water texture dynamic with transparency and color based on depth. It looks really cool.

1 Like

Some tweaks to the palette to handle the snowline (which my water layer supports), and gives a nice whitish edge effect. I added a little randomness so the surface seems to shimmer in a realistic way.

This is what the palette image looks like… (with variable transparency)

1 Like