Part two
Welcome to the series of articles about WebGL landscape rendering used in
Trigger Rally !
If you haven't had time yet, then read the
first part , in which I talk about the importance of minimizing data transfer between the processor and the video card, and also suggest storing static data about the height of each point of the landscape in the texture.
In this article I will talk about the data structure of the vertices, as well as about morphing.
')
From the translator: the article has many inarticulate and technical inaccuracies. Help fix them!
Rings
Geoclipmap rendring operates with square “rings” around the viewpoint, with each ring twice the size of the previous one, but half the resolution. Due to this, we see a gradual decrease in the number of vertices per unit plane, according to the principle: further - less. The inner ring is completely filled and has the highest resolution, becoming a simple square grid of triangles:
Repetitive geometry can be translated without particularly noticeable changes, but it will seem that the edges have moved slightly:
We can use this property to move the geometry relative to the camera.
Since each ring of triangles has its own size, and the distance for transfer depends on the size, we must move the rings independently of each other. Therefore, the vertex shader must know exactly which layer of vertices it moves to change it correctly.
In general, we need to know the following vertex parameters:
- X position
- Y position
- Layer number
In Trigger Rally, we use the [X, Y, Z] vector, and we also get the number of the layer where the vertex is located, according to its position along the Z axis.
Stitching holes
Each ring has its own scale, in addition, each ring is shifted by an amount depending on the scale. Thus, a problem may arise - one ring is translated, but the next one is not, and a gap is formed between them:
One of the ways to solve this problem is to build up an additional “skirt” on the edge of the ring. According to
this article , the skirt is assembled from a variety of small pieces; several vertex buffers and complex processor logic are used for this. But we don't want that at all!
When implementing the landscape in the Trigger Rally, I spent hours trying to find a productive and high-quality way to collect the skirt, but alas, to no avail.
But at the last WebGL Camp Europe, I met
Florian Bösch , and he offered to make the rings a little more, thus allowing them to intersect.
Now any more or less experienced graphics programmer will start yelling: “No! You can not allow the intersection of geometry! This is wasteful and
terrible artifacts can appear! ” But in fact, everything is not so bad - we really have to draw a little more, but if the geometry is well fitted, then this is really a great solution!
Morph
On the border of the rings, we have the geometry of one resolution, which is in contact with the geometry that is two times smaller. We need to make transition regions on the edge of each ring, in which the geometry will smoothly “flow” from high resolution to low, so that the edge of one ring strictly coincides with the edge of another.
So, each vertex should be moved to match the following ring:
We need to do this in the vertex shader. The easiest way is to include the morph vector in the vertex data structure, but again, Florian suggested something better - to use
modular arithmetic !
To show how this works, let's present the data as a table:
Thus, we can calculate the morph vector, having only the coordinates of the vertices, using the following GLSL code:
vec2 morphVector = mod(position.xy, 2.0) * (mod(position.xy, 4.0) - 2.0);
And this is all without additional properties in the vertex structure! (
comment of the lane.: I take off my hat before this Florian )
Next will be ...
In the next post, I will talk about how the height map is stored in Trigger Rally and how it is processed in the vertex shader. Then we will look at surface shading in the fragment shader, and finally, how to render the environment more effectively.
Thank you for reading!