5
$\begingroup$

I am generating plane vertices where the y values are generated by a heightmap (noise) algorithm. This is how I produce my vertex array:

for (let row = 0; row < noise.length; row++) {
    for (let col = 0; col < noise[0].length; col++) {
        color = noise[row][col];
        positions.push(row, color, col);
    }
}

After that I generate index values like this (I know that there is a lot of optimization that can be done here):

const height = noise.length + 1;
const width = noise[0].length + 1;

for (let row = 0; row < height - 1; row++) {
    if (row % 2 === 0) {
        if (row === height - 2) break;
        for (let col = 0; col < width - 1; col++) {
            indices.push(col + row * (width));
            indices.push(col - 1 + (row + 1) * (width));
        }
    } else {
        for (let col = width - 2; col >= 0; col--) {
            indices.push(col - 2 + (row + 1) * (width));
            indices.push(col - 2 + row * (width));
        }
    }
}

indices.pop();

Finally I draw the plane using:

gl.drawElements(gl.TRIANGLE_STRIP, buffers.numIndices, gl.UNSIGNED_SHORT, 0);

So if I use POINTS as mode, the plane seem to look as it should:

enter image description here

Whereas if I am using TRINGLE_STRIP the result looks wrong:

enter image description here

First I thought wrong indices might be the reason but then I checked by scaling to a 3x3 grid/plane and the vertex and index output looked as I would have expected:

Vertices:

[-1, -43.89, -1, 
-1,  -82.27,  0, 
-1,  -23.06,  1, 
 0,  -43.43, -1, 
 0,  -54.85,  0, 
 0,  -66.27,  1, 
 1,  -61.89, -1, 
 1,  -27.43,  0, 
 1,  -59.89,  1]

Note:

The vertices might not exactly correspond to what you would have expected from above loop. That is because I am centering the mesh around origin after the loop.

Indices:

[0, 3, 1, 4, 2, 5, 8, 4, 7, 3, 6]

So my guess is that the problem is that I am pushing my triangles counterclockwise, that is why I tried to enable culling and depth testing but that did not help either:

gl.enable(gl.DEPTH_TEST);
gl.enable(gl.CULL_FACE);
gl.cullFace(gl.FRONT);

enter image description here

Any guess what might be the reason for wrong TRIANGLE_STRIP rendering?

Update 1:

According to @PaulHK's recommendation I changed my index creation loop to insert the last index of a single strip twice.

for (let row = 0; row < rows - 1; row++) {
    if (row % 2 === 0) {
        for (let col = 0; col < cols; col++) {
            indices.push(col + row * cols);
            indices.push(col + (row + 1) * cols);
        }
    } else {
        for (let col = cols - 1; col >= 0; col--) {
            indices.push(col + (row) * cols);
            indices.push(col + (row + 1) * cols);
        }
    }
}

For a 3x3 grid this produces:

Vertices:

[-1, -9.6, -1,
 -1, -64.6, 0,
 -1, -11.1, 1,
 0, -38.8, -1,
 0, -32.8, 0,
 0, -26.8, 1,
 1, -37.0, -1,
 1, -1, 0,
 1, -47.5, 1]

Indices:

[0, 3, 1, 4, 2, 5, 5, 8, 4, 7, 3, 6]

Unfortunately the rendered object still looks the same.

Update 2:

I use the Diamond-square algorithm to generate the mesh. This requires a grid of size (2^n) + 1. I.e.:

2, 3, 5, 9, 17, 33, 65, 129, 257, 513 ...

Maybe it's just a coincidence but it seems to me that the grid can be displayed correctly for sizes 3 - 129 with the procedure from Update 1. For a size of 257 and above the mesh has errors.

3x3 looks fine: enter image description here

129x129 looks fine: enter image description here

257x257 seems wrong: enter image description here

$\endgroup$
  • 1
    $\begingroup$ Are you trying to draw it as a single strip? You should be drawing it as a series of strips. This can still be done in 1 draw call but you will need to insert a degenerate triangle (duplicate the last vertex) at the end of each strip column. $\endgroup$ – PaulHK Aug 29 '18 at 5:09
  • $\begingroup$ @PaulHK For a 3x3 plane that would be [0, 3, 1, 4, 2, 5, 5, 8, 4, 7, 3, 6], right? But it still does not seem to work properly. $\endgroup$ – チーズパン Aug 29 '18 at 17:15
  • $\begingroup$ It should be [Col(n), Col(n)+1, Col(n+1), Col(n+1)+1, Col(n+2), Col(n+2)+1, .... Col(n+8)+1, Col(n+8)+1] .. So for every pair of indices we take a vertex for the current column and one from its neighbour, this is the same as your strip. At the end we insert a duplicate vertex which will create a degenerate triangle. This will cause the next set of strip indices to start a new strip without any connecting triangles to the last column. $\endgroup$ – PaulHK Aug 30 '18 at 2:13
  • $\begingroup$ computergraphics.stackexchange.com/questions/3746/… $\endgroup$ – PaulHK Aug 30 '18 at 3:19
  • 3
    $\begingroup$ Ok, interesting the 3x3 version works and the 257x257 doesn't. Are you using 16bit indices by any chance? Because you can only address up to 256x256 using 16bit indices. For your case you need to use 32bit indices. $\endgroup$ – PaulHK Sep 6 '18 at 2:06
3
+50
$\begingroup$

This looks like a case of 16bit truncation in your indice buffer. For a 257x257 grid you will be addressing more than 65536 vertices so you will need to use a 32bit indice buffer.

gl.drawElements(gl.TRIANGLE_STRIP, buffers.numIndices, gl.UNSIGNED_SHORT, 0);

change to :

gl.drawElements(gl.TRIANGLE_STRIP, buffers.numIndices, gl.UNSIGNED_INT, 0);

Also change your buffer allocation code to match this type (Uint16Array -> Uint32Array for Javascript).

$\endgroup$
  • $\begingroup$ You might want to mention that in JavaScript/WebGL the array containing the indices has to be a Uint32Array instead of Uint16Array. $\endgroup$ – indexoutofbounds Sep 10 '18 at 9:19
  • $\begingroup$ Thanks for the suggestion, I've ammended my answer. I wanted to make the answer language agnostic as this can occur on any GL implementation. $\endgroup$ – PaulHK Sep 11 '18 at 2:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.