Vertex colors not visible on primitive models

I’m trying to add vertex colors to a primitive box model which uses a StandardMaterial. I’ve set the mesh’s normals, UVs and the colors using Float32Arrays as per the mesh docs. The UVs and the normals are being applied correctly, however the vertex colors are not visible on the model. I’m setting all vertex colors to red (255, 0 ,0, 1), however the model is rendered like this:

DiffuseMapVertexColor is set to true on the standard material. Removing the diffuseMap texture has no effect.
Screenshot (1)

Any advice would be appreciated.

Here is a link to a: barebones project

Here is my code:

ApplyTexture.prototype.initialize = function() {
    //We scale the UVs so the image texture isn't distorted as the model scales
    let scale = this.entity.localScale;
    let uvs = [];
    for (let i = 4; i < 6; i++) {
        //Left, Right
        uvs.push(0, scale.y);
        uvs.push(0, 0);
        uvs.push(scale.x, scale.y);
        uvs.push(scale.x, 0);
    }
    
    for (let i = 0; i < 2; i++) {
        //Top, Bottom
        uvs.push(0, scale.x);
        uvs.push(scale.z , scale.x);
        uvs.push(0, 0);
        uvs.push(scale.z , 0);
    }
    
    for (let i = 2; i < 4; i++) {
        //Front, Back
        uvs.push(0, scale.y);
        uvs.push(0, 0);
        uvs.push(scale.z , scale.y);
        uvs.push(scale.z , 0);
    }
    
    let normals = [
        //Left
        0, 0, 1,
        0, 0, 1,
        0, 0, 1,
        0, 0, 1,
        
        //Right
        0, 0, -1,
        0, 0, -1,
        0, 0, -1,
        0, 0, -1,
        
        //Top
        0, 1, 0,
        0, 1, 0,
        0, 1, 0,
        0, 1, 0,
        
        //Bottom
        0, -1, 0,
        0, -1, 0,
        0, -1, 0,
        0, -1, 0,
        
         //Front
        1, 0, 0,
        1, 0, 0,
        1, 0, 0,
        1, 0, 0,
        
        //Back
        -1, 0, 0,
        -1, 0, 0,
        -1, 0, 0,
        -1, 0, 0
    ];
    
    let colors = [];
    for (let v = 0; v < 24; v++) {
       colors.push(255, 0, 0, 1);
    }
    
    let mesh = this.entity.model.meshInstances[0].mesh;
    mesh.setUvs(0, new Float32Array(uvs));
    mesh.setNormals(new Float32Array(normals));
    mesh.setColors(new Float32Array(colors));
    mesh.update();
};

Hi @Devortel,

Hmm, that should work, not sure why it doesn’t. @mvaligursky any idea?

1 Like

This is not a solution but, I’ve found that vertex colors show up correctly if I create a mesh procedurally as shown in this post. It almost seems like the vertex colors become immutable once the mesh has been created.

1 Like

This is what is returned after running mesh.vertexBuffer.getFormat() Should we be seeing an element for the vertex colors here?

Also note that hasColor is false.

You use existing mesh, which you get like this:
let mesh = this.entity.model.meshInstances[0].mesh;

Which means you simply modify its vertex attributes. The mesh does not have vertex colors, so your colors are not applied to it.

If you need to modify the format, you need to call
mesh.clear();
before you set the attributes on it.

Note that in your case, when you call mesh.clear, it complains that there are no positions set. You can either generate them, or get them from original mesh using getPositions (before calling clear on it)

3 Likes

Unfortunately vertex colors are still not visible on the mesh. I’m still generating the UVs and colors myself, but based on your solution I’m now getting the positions, normals and indices from the original mesh and setting them after mesh.clear() is called.

In the mesh’s VertexFormat, there is now an element for Color and hasColor is now set to true. The mesh’s vertices, normals and UVs are all displaying correctly, just without the vertex colors.

I’ve updated the barebones project

And here is the updated code:

    let scale = this.entity.localScale;
    let uvs = [];
    for (let i = 4; i < 6; i++) {
        //Left, Right
        uvs.push(0, scale.y);
        uvs.push(0, 0);
        uvs.push(scale.x, scale.y);
        uvs.push(scale.x, 0);
    }
    
    for (let i = 0; i < 2; i++) {
        //Top, Bottom
        uvs.push(0, scale.x);
        uvs.push(scale.z , scale.x);
        uvs.push(0, 0);
        uvs.push(scale.z , 0);
    }
    
    for (let i = 2; i < 4; i++) {
        //Front, Back
        uvs.push(0, scale.y);
        uvs.push(0, 0);
        uvs.push(scale.z , scale.y);
        uvs.push(scale.z , 0);
    }

    let colors = [];
    for (let v = 0; v < 24; v++) {
       colors.push(255, 0, 0, 1);
    }
    
    let mesh = this.entity.model.meshInstances[0].mesh;
    
    let positions = [];
    mesh.getPositions(positions);
    
    let normals = [];
    mesh.getNormals(normals);
    
    let indices = [];
    mesh.getIndices(indices);
    
    mesh.clear();

    mesh.setUvs(0, new Float32Array(uvs));
    mesh.setPositions(new Float32Array(positions));
    mesh.setNormals(new Float32Array(normals));
    mesh.setIndices(new Float32Array(indices));
    mesh.setColors(new Float32Array(colors));
    mesh.update();

It likely won’t make a difference, but if you use setColors, expected values are float … so 0…1 range typically, not 255.
Alternatively, use SetColors32 and specify colors in 0…255 range (including alpha).

Regarding not rendering correctly - the typical approach would be to capture a frame using SpectorJS (install Chrome plugin), and inspect the shader for the mesh to see what happens with the vertex colors. It’s possible they’re ignored and material needs to be set up differently. (Sorry, I don’t have better answer without looking myself)

1 Like

I’ve corrected the colors Float32Array so it now uses values in the 0…1 range.

This is my first time inspecting the capture outputs, I’m looking at a drawElements call and there are attributes for the mesh’s vertex_position, vertex_normal and vertex_texCoord0 but nothing for its color.

This is the: raw JSON output from the capture

How do you recommend I set up the material differently?

1 Like

I think I see what the problem is. Mesh Instance caches some information about the mesh … such as info about vertex format. When you change the vertex format of the mesh, the mesh instance data is not updated to match.

What I would suggest to do:

  1. use render component, instead of model component, to create your cube.
  2. get mesh instance from render component, get mesh from it … and modify it as you do at the moment. also keep a material that mesh instance uses.
  3. create new mesh instances and assign them to render component. something like
    this.entity.render.meshInstances = [new MeshInstance(mesh, material)];
2 Likes

This works! I really appreciate your assistance.

Once again, I’ve updated the barebones project this time with the working solution. I hope this helps someone else!

3 Likes