0
votes

I'm trying to upgrade the release version of ThreeJS in my app. I'm showing some meshes on a 3D scene and allow the user to set their colour mappings. Meshes can be coloured in two ways, by vertices or by faces.

When creating the material of the mesh, I set up the vertexColors attribute to THREE.VertexColors or THREE.FaceColors, depending on the behaviour I want.

On rev71, I implemented the change of the colour like this :

var geometry = mesh.geometry;
/* For each face, change it's face colour or vertex colour */
for(var i = 0; i < geometry.faces.length; i++) {
    if (colourFace) {
        geometry.faces[i].color = myColorFace;
    } else {
        geometry.faces[i].vertexColors =
            [myColorVert1, myColorVert2, myColorVert3];
    }
}

Everytime I change the current mapping of the mesh, it is updated on the scene.

On rev73, ThreeJS seems to only update the first mapping change (just before the Mesh and it's Geometry have been pushed to the GPU). The only clue I got is these lines on WebGLGeometries :

/* ... */
} else if ( geometry instanceof THREE.Geometry ) {
    if ( geometry._bufferGeometry === undefined ) {
        geometry._bufferGeometry =
            new THREE.BufferGeometry().setFromObject( object );
    }
    buffergeometry = geometry._bufferGeometry;
}
/* ... */

The buffergeometry attribute is then used by the WebGLRenderer to update WebGL array buffers (in my case, the color buffer). It seems that when updating the geometry from the mesh, it is never updated for the WebGLGeometry.

Does someone have a solution or should I post an issue or pull request to solve the problem?

2
Try r.74. Also instead of re-assigning colors with = use copy() or set().WestLangley
Still not working on rev73/74 after applying the changes, I took a quick look at ThreeJS code and it seems that after creating the BufferGeometry on WebGLGeometries in order to send it to the GPU, this BufferGeometry is never updated when it's associated geometry is modified.Ludovic Bailly
Did you set the necessary needsUpdate flags? Otherwise, provide a simple working example of your issue by editing this fiddle. Code fragments are not sufficient.WestLangley

2 Answers

0
votes

As I stated in my comment, you cannot reassign colors (using =), you must change the colors using copy() or set(). You also need to set the colorsNeedUpdate flag when the colors are changed.

Using your example, first create your geometry, and instantiate vertex colors arrays prior to rendering:

for (var i = 0; i < size; i++) {

    face = faces[i];
    var color = new THREE.Color( 1, 0, 1 );
    face.vertexColors = [ color, color, color ];

  }

After rendering, update the colors like so:

for (var i = 0; i < size; i++) {

    face = faces[i];
    var color = new THREE.Color().setHSL( (i / size) * 0.8, 1.0, 0.5 );
    // change colors
    face.vertexColors[ 0 ].copy( color );
    face.vertexColors[ 1 ].copy( color );
    face.vertexColors[ 2 ].copy( color );

}

mesh.geometry.colorsNeedUpdate = true;

fiddle: http://jsfiddle.net/akmcv7Lh/29/

three.js r.74

0
votes

Add/remove setTimeout to see changes : http://jsfiddle.net/akmcv7Lh/28/

setTimeout(function() {
  for (var i = 0; i < size; i++) {
    face = faces[i];
    var color = new THREE.Color().setHSL((i / size) * 0.8, 1.0, 0.5);
    face.vertexColors = [color, color, color];
  } 
}, 1000);

When you modify the colors before the next render call after adding the mesh (ie no timeout), it works.

When you modify the colors after the next render call, it's not working.

I digged a little bit into ThreeJS code and found that geometry is used to generate a DirectGeometry and then a BufferGeometry that is pushed to the GPU. There is no update of DirectGeometry after modifications of the geometry. Look at https://github.com/mrdoob/three.js/blob/master/src/core/BufferGeometry.js on line 333.

It seems that the BufferGeometry is correctly updated with the DirectGeometry, but the DirectGeometry is only created once and never updated. I succeeded to hack ThreeJS for testing purpose and by just updating the DirectGeometry when needed, everything works fine.

I think about sending a Pull Request but I'm not sure I will follow ThreeJS conception rules. There is at least 2-3 ways to fix the troubles, but maybe I'm not using the features correctly ;)