# Curved world effect shader for heterogeneous mesh faces

I have a voxel based game, similar to Minecraft and want to apply the "curved world effect" like described here.

As I was using a per 1x1 face quad renderer, applying the effect went well, but I implemented a greedy mesh optimization, that same faces are merged to one huge mesh.

Now the curved world shader seems to not work anymore, but most of the sources describe, that it should just work for all meshes (whatever "all" means).

I somehow understand that it should not work, as quadratic bending and linear fragment interpolation between two vertices is different, but I don't find any hint when it does not work.

That's the part of my vertex shader.

// offscreen.vert
// ..
vec3 diff = ubo.pos - inPosition;
diff.y = 0;

float dist = length(diff);
vec3 d = vec3(0.0, 0.005 * -dist * dist, 0.0);

vec3 p = inPosition + d;
gl_Position = ubo.proj * ubo.view * vec4(p, 1.0);
// ..


Do have any idea? Thanks for helping

I somehow understand that it should not work, as quadratic bending and linear fragment interpolation between two vertices is different,

Indeed. If you want to non-linearly distort a mesh object, then you have to sample the nonlinear function frequently to get a reasonable linear approximation to it — that is, you must not have very large or long triangles.

If that were the only problem, then your mesh would wobble weirdly but not be full of gaps. The gaps are a different, but related problem:

but I implemented a greedy mesh optimization, that same faces are merged to one huge mesh.

The greedy meshing algorithm is known to produce “T-junctions” — points where an edge of one quad (pair of triangles) meets the vertices of two (or more) others.

|         Quad 1         |
|                        |
|V1         V2           |V3
+-----------+------------+
|           |            |


Under ordinary circumstances, this merely produces a few pixel-sized specks in the rendering, because the rasterization of the edge of quad 1 doesn't quite line up with the rasterizations of the other two.

However, when you introduce a non-linear transformation, then those specks open up into big gaps, because the non-linear transformation moved vertex V2 so that it is not on the line between V1 and V2 at all. Those are the gaps you are seeing.

To avoid these gaps, you must generate a mesh which contains no T-junctions — every edge of every triangle must exactly meet (share two vertices with) a neighboring triangle. (This is true of most meshes created by 3D modeling software, except where an object is intentionally incomplete, such as leaving off the bottom of a tree's trunk.)

The simplest way to achieve this is to remove the greedy mesh optimization, and generate 2 triangles for every block face. Conveniently, this will also ensure that the visual effect of the distortion is consistently sampled.

If you still want to optimize the mesh, you will have to use a different algorithm, which avoids T-junctions — it cannot simply generate one quad for a large area and must instead take neighboring triangles into account. Once the algorithm has decided to put a vertex at a certain corner, all other surfaces meeting that corner must also have a vertex there too rather than an edge passing by. This is a nontrivial problem and I'm not aware of any articles describing a complete algorithm for it, nor do I have such an algorithm in code form. (Perhaps one day I'll write one.)

• Thanks for sharing! But, how can a greedy mesh optimization not produce T-junctions? As soon as two quads have the same edge it could be optimized as well, if they have the same material. I was also thinking about producing meta data for the distorted vertices and add correctly bended vertices in the tesselation stage? At current I have quite good results for not bend at all for near vertices and use a small curve factor. Jun 3, 2023 at 6:54
• @Aitch "how can a greedy mesh optimization not produce T-junctions" — The greedy mesh algorithm by definition does produce T-junctions. I'm saying you would have to write some different algorithm, and the algorithm must know that once you have decided to put a vertex at a certain corner, all surfaces meeting that corner must also have a vertex there too, which means it will produce more vertices, but still not as many as quad-per-block-face. As I said, this is a tricky problem and I don't have a solution handy — I just know that the result is possible. Jun 3, 2023 at 16:14