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.
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.
I also like this example, and I decided to take it 2 steps further
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.
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
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.
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?
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.
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.
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.