How to disable color interpolation when using vertexColors?

Hi everyone,

I am trying my hand at some procedural terrain generation and I succeeded in creating a terrain, but I want each face of my plane to have its own color, in order to create a nice low poly look.

However, instead, I can see that there is some interpolation going on on the faces where the colors switch from one color to another. You can see it in this screenshot:

Notice that there’s a color gradient from green to blue (and vice versa). My question is how to disable this gradient and instead have a single color on each face.

I figured out a solution by converting the PlaneGeometry to a non-indexed version so I could assign a color to each vertex, but it seems like an inelegant solution. Is there are another way to disable this color interpolation and simply assign a color to each face?

This probably is the right solution – the graphics APIs like WebGL do not store per-face data. Data is stored by vertex, and so distinct colors (or UVs, or normals, …) for two adjacent triangles require distinct vertices. You could re-index the geometry after assigning the colors to remove unneeded duplicates.

A custom shader could also be used to clamp the colors, but that’s probably overkill for this.

2 Likes

Thanks @donmccurdy!

How would I go about re-indexing the geometry? Is there a function to call on the non-indexed object or is it trickier than that?

You can use BufferGeometryUtils.mergeVertices for this.

1 Like

Why do you need to RE-index it? Better maybe to keep that version around and create a soup for this type of presentation? I don’t think that a simple merge would make your indexes consistent.

Good question. Indexed versions seem to be easier to work with than the non-indexed ones. Any maybe there are performance reasons? (I’m not sure, I’m still quite new to all of this).

For example, if I have an array of different heights and I want to loop through all the vertices of a non-indexed geometry, I have to apply quite some logic to assign the right height to the right place in the non-indexed position array.

It’s all a trade off. Indexed versions you might have trouble addressing after a certain size, non indexed don’t have limits if I understand correctly.

Regarding your heights, it also depends. What kind of logic? Are you applying each height to a vertex? Then yes you might have to apply to severa vertices (all the faces containing that vertex). But this should be a simple operation. Instead of having a one to one relationship between a vertex and your transformation ( ie. applyHeightToVertex(index, vertices) ), you would have one more layer of relationship between the vertices and the triangles.

If starting from the indexed version just keep that around. When looping through your “soup” (vertices repeated into triangles) you simply look up the index array of the first version, and check if you have already computed it, then you retrieve it.

Some code:

const heights = [ 1,2,3,4 ] 

const indexedGeometry = new PlaneBufferGeometry(1,1,1,1)
const nonIndexedGeometry = toNonIndexed( indexedGeometry ) 

const soup = nonIndexedGeometry.getAttribute('position')
const transformedVertices = []
for ( let i = 0 ; i < soup.count ; i++) {
  // you can memoize here, in the soup, you will visit the same index mulitple times
  const vertexIndex = indexedGeometry.index.array[i]
  const height = heights[vertexIndex]
  const i3 = i * 3
  const newVertex = [ soup.array[i3], soup.array[i3+1], soup.array[i3+2] ]
  transformVertex(newVertex,height)
  //BUT you need to write even the memoized result at this `i`
  soup.setXYZ(i, newVertex[0], newVertex[1], newVertex[2])
}
1 Like

Thanks @dubois! I’ll check out the specifics of the code later but it already looks cleaner than what I have come up with so far. =p

1 Like

@dubois I see you use a function called transformVertex(). I can’t find this function in the documentation; which function is this?

Ah sorry, that was related to

A simple thing could be

newVertex[2] = height

Whatever you need to do to transform the vertex. Say the vertex start as a vertex of plane geometry, then they are all x,y,0 your transformation is probably to x,y,myHeight.

1 Like

Your code helped me streamline it a lot more; so thanks for that!

1 Like