How to efficiently change color of a polygon in a mesh

Hello,

I’ve built a 2D grid in OpenGL which has roughly 100 columns and 300 rows. Each “cell” in my grid is a different color. Each cell is also really just two triangles. Here’s how I construct my cell:
[ul]
[li]For each cell in my grid, I create 6 vertices – three for each triangle representing the rectangular cell, I stick these all in a single array called “vertices”[/li][li]I also create, in a separate array called “colors”, a set of colors for each vertex[/li][li]I then bind these two arrays to GL buffers (I’m doing this in WebGL, hence the syntax below):[/li]


function initVertexBuffers() {
    squareVerticesBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
}

function initColorBuffers() {
    squareVerticesColorBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesColorBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
}

[li] I then call glDrawArrays to render the polygons[/li][/ul]

This works fine. However, the current approach I’ve taken to change the color of a given cell is to update the appropriate index in my colors array, and then call initColorBuffers again. This takes many seconds, however, because of the size of the array. So I’m figuring there is a way to more efficiently update the color of a subset of vertices?

Rick

For what it’s worth, my two shaders are below:


// fragment shader
varying lowp vec4 vColor;
void main(void) {
    gl_FragColor = vColor;
}

// vertex shader
attribute vec3 aVertexPosition;
attribute vec4 aVertexColor;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying lowp vec4 vColor;
void main(void) {
    gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
    vColor = aVertexColor;
}

You use glBufferData right now to create a new buffer and fill it with values. You can use glBufferSubData instead to only upload parts of the buffer. I would recommend reading up on the differences between glBufferData and glBufferSubData to find out the pros and cons of either one.

  1. You don’t need to use floats for colours. Unsigned bytes are sufficient, and only need a quarter of the memory.

  2. If you use glDrawElements(), you only need 4 vertices per cell rather than 6 (the vertices on the shared diagonal don’t need to be duplicated).

  3. If all of the vertices for a cell are the same colour, you can store the colours in a texture rather than using vertex attributes. Then you only need to change a single colour for each cell rather than four or six. Vertices would then need texture coordinates, but you don’t need to change those.

  4. If you use a texture, then adjacent cells can share vertices, so the grid only needs to have 101x301 vertices rather than 100x300x4.

[QUOTE=GClements;1281561]1. You don’t need to use floats for colours. Unsigned bytes are sufficient, and only need a quarter of the memory.

  1. If you use glDrawElements(), you only need 4 vertices per cell rather than 6 (the vertices on the shared diagonal don’t need to be duplicated).

  2. If all of the vertices for a cell are the same colour, you can store the colours in a texture rather than using vertex attributes. Then you only need to change a single colour for each cell rather than four or six. Vertices would then need texture coordinates, but you don’t need to change those.

  3. If you use a texture, then adjacent cells can share vertices, so the grid only needs to have 101x301 vertices rather than 100x300x4.[/QUOTE]

Thank you both!

When I hear “texture” I think “image” – but these are ever-changing colors in each cell, so I want to be able to specify a texture programmatically. To create the texture, will I need to do something like render to a Canvas, and then create the texture from that Canvas “image” - or is there a way to specify a binary texture simply with R/G/B values?

You can replace a portion of an existing texture with glTexSubImage2D() or the entire texture (more precisely, an entire mipmap level, but you’d only be using the base level in this case) with glTexImage2D().

This is analogous to replacing a portion of an attribute array using glBufferSubData() or the entire array with glBufferData().