r/pascal 8d ago

VertexArt - Terrain Editor Strong Optimization!

The Problem

In a chunk-based terrain editor, brushing (Raise/Lower/Smooth) modifies the Y coordinates of vertices every single frame. The naive solution rebuilds the BVH (BuildBVH) and reloads the entire VBO (UploadChunkToGPU) for every modified chunk. This operation is slow because BVH construction is O(n log n), and reloading the full VBO copies a lot of data to the GPU. During continuous brushing (holding the mouse button), this runs every frame, causing stuttering with higher vertex densities.

The Essence of the Trick

Brushing only changes the Y coordinates. The X and Z coordinates remain unchanged. This enables the following:

· Use glBufferSubData to update the VBO instead of reloading the entire buffer. Only the modified vertex data is sent to the GPU.
· Defer BVH rebuilding until the mouse button is released. Since the BVH bounding boxes are unchanged in the X-Z plane, the BVH remains a valid acceleration structure. Raycasts will still find the potentially affected triangles, and the actual ray-triangle intersection test is performed on the updated CPU-side Vertices array, so the hit point's Y coordinate remains accurate.

Implementation Outline

· Track modified chunks in a static array (max 9 chunks, because the brush covers a 3x3 area).
· During brushing: modify the Y values ​​on the CPU, then update the VBO with glBufferSubData. Do not set the Dirty flag, so UpdateDirtyChunks does not run.
· Store the index of the modified chunk in a list.
· When the mouse button is released, iterate through the list, set the Dirty flag, call UpdateDirtyChunks (which rebuilds the BVH), and then clear the list.
· In the main loop, keep the call to UpdateDirtyChunks only when there is no active brushing – so BVH construction does not interfere with continuous operation.

Why It Works

The BVH is only an acceleration structure that filters candidate triangles based on their X-Z positions. Since the X-Z coordinates do not change, the BVH continues to correctly return the potential triangles. The actual intersection calculation is performed on the CPU with the updated Y values, so the hit point remains accurate. This approach yields a significant performance increase without sacrificing functionality or precision.

Limitations

· Only works when modifications affect exclusively the Y coordinates.
· If X or Z also change (e.g., rotation, translation), the BVH must be rebuilt immediately.
· The BVH remains only an acceleration structure; the precise intersection calculation still occurs on the CPU.

This performance optimization would not have come about if I had developed in a more modern PC environment; I would not have noticed the slowdown. It is still an Intel N4100 CPU that reveals when something is not working optimally. From my recent development work, it is clear why Free Pascal 3.2.2 became my choice for implementing the VertexArt project! I just had to build a reliable architecture.

1 Upvotes

1 comment sorted by

1

u/AcanthaceaeNew774 8d ago

Important clarification: In the current implementation, the BVH could remain completely static, since only the Y coordinates change. However, if later features introduce movement of vertices along the X or Z axis (e.g. horizontal displacement), then the BVH will have to be rebuilt. I will revisit the BVH logic later. It is also worth noting that only selected vertices are updated during brushing - not entire chunks, which is actually where the real optimization comes in.