Coloring Vertices of an object

Hey guys,

I am trying to color a geometry using vertex coloring based on a a file that has multiple colors see below:

Basically, I want to change the color of different objects with similar form (identical mesh) where they all use the same material. Instead of creating a material for each, I decided to just change the color of their meshes. After reading the documentation on advanced custom meshes I was able to write the code below. However, the code does not do where objects are not getting colored.

	public static void changeColor(Mesh mesh, AnimationUVMapping color){

		float[] texCoord = new float[mesh.getVertexCount() * 2];

		// color from file 
		float yTexel = color.getV();

		for(int i=0; i<texCoord.length; i++) {
			texCoord[i] = yTexel;
		} 

		// clear texture coordinates buffer
		mesh.clearBuffer(Type.TexCoord);

		// fill buffer with new texture coordinates from atlas file
		mesh.setBuffer(Type.Color, 2, BufferUtils.createFloatBuffer(texCoord));
		mesh.updateBound();
	}

For a buffer of Type.Color, you should pass color : float x 4 (rgba)

  • Why to set 2 ?
  • Why only set one float ?

There are a few things that we must assume because we can’t see the rest:

  1. we must assume that you have a custom shader because of course this won’t work with any of the default shaders. We can’t see that so it could be broken too.
  2. we must assume that the model is not sharing vertexes that would need different colors. Since we don’t know the source of the mesh this is also a pretty big assumption but if you are coloring whole objects then it should be ok. If you are trying to color just particular faces then it requires that those faces have their own vertexes (not shared by adjacent faces of different colors).

Also, since we don’t see the picture of what “wrong” looks like we must assume a lot from your description. It’s mildly humorous the number of times people go to great lengths to describe something on here where a picture would work fine. Though in your case, the description is straight forward it still leaves some room for interpretation. Seeing what you want next to what you get would be clearer if possible.

@pspeed you’re right I should have posted a picture, and I apologize for not being specific.

See below. The issue is that no colors are being assigned at all. @david_bernard_31 I tried different things including what you suggested with no luck.

I am using this material for all of them (and yes I am coloring - or attempting to color - the whole object)

      mat= new Material(assetManager,"Common/MatDefs/Light/Lighting.j3md");
      mat.setTexture("DiffuseMap", assetManager.loadTexture("/Materials/atlasColors.png"));
      mat.setFloat("Shininess", 5f);  
      mat.setColor("Specular", ColorRGBA.White); 

Below are the objects (cuboids) that I am trying to color using the same material.

Also, am I over complicating this? Is there a simpler way to color objects using the same material?

Thanks in advance

Yes you’re over complicating.
If you want to color the object with a single color :

ColorRGBA mycolor = ...
mat= new Material(assetManager,"Common/MatDefs/Light/Lighting.j3md");
mat.setColor("Diffuse", mycolor);
mat.setFloat("Shininess", 5f);
mat.setColor("Specular", ColorRGBA.White); 

PS to highlicode use ``` … ```

You should set the text coordinates to the texture coordinate buffer. Lighting.j3md has no idea what to do with your Color buffer that is actually texture coordinates.

@david_bernard_31 that is what I had initially but that also meant every time I called the changeColor() method it assigned a new material for the object. Since I have a large number of these objects, my plan was to use the same material for all of them but when I need to change the color I will just use that file I created to point to the right yTexel from it and change the color accordingly.

@pspeed did you mean something like this?


		float[] texCoord = new float[mesh.getVertexCount() * 2];

		// default pod color 
		float yTexel = color.getV();

		for(int i=0; i<texCoord.length; i++) {
			texCoord[i] = yTexel;
		} 

		// clear texture coordinates buffer
		mesh.clearBuffer(Type.TexCoord);

		// fill buffer with new texture coordinates from atlas file
		mesh.setBuffer(Type.TexCoord, 4, BufferUtils.createFloatBuffer(yTexel));
		mesh.updateBound();

I tried it and still didn’t work. Again I apologize if I am doing something stupid here, I went over the documentation again just to make sure, and for me it seems my code is correct (but obviously I am wrong)

About using a material per object :

You can have one material per object. they share the same material definition : Lighting.j3md (the “heavy” part)
your changeColor(), will use getMaterial().setColor(“Diffuse”, mycolor)

About your custom approach.

the error is in using your yTexel and filling color. It should be something like :

ColorRGBA mycolor = ...
float[] colors = new float[mesh.getVertexCount() * 4 ]
for(int i=0; i<colors.length; i+=4) {
  colors[i + 0] = mycolor.r;
  colors[i + 1] = mycolor.g;
  colors[i + 2] = mycolor.b;
  colors[i + 3] = mycolor.a;
}

in your sample the size and the content of the buffer is wrong.
And IMHO to set the same color everywhere, your custom approach will require more resources : to set the value on CPU and to transfert GPU, where it will use more memory (to store one color per vertex vs one color per mesh)

Oups I don’t see you switch to Type.TexCoord, in this case you should send 2 coord (U,V) with values between [0,1], and you send (V,V) if I understand correctly your code.

anyway use one material per object, it’s made for this : storing parameters of a MaterialDefinition.

if I choose one material per object the performance drops significantly. I tried 2 test cases one with all of them using one material and another case with each having its own material. SIGNIFICANT difference!

But it doesn’t work with one material, if I understand your question ;-).

Anyway, keep us inform of your progress, i’m intersting by the result (and metrics, next time you’ll do the test).

hmmmm my understanding is that it does work as a way of optimization.

I’ll keep digging and report back on my findings.

Thanks guys

that should have worked. Verify that your yTexel is valid values.

…and ignore david in this case as I don’t think he understands that you want to batch these together and therefore want just one material.

@pspeed I will double check,as you said my intent is to batch them together and then change the colors.

Out of curiosity is this possible if the objected were not batched? Can I assign one material to all the objects and change their colors without having them batched?

Thanks!

No, but if you already had separate objects then you might as well have separate materials. The slowness with multiple objects comes from having multiple objects not multiple materials.

1 Like

you can ignore me about using one material per object, but not about the issue in your way to fill Buffer (TexCoord or Color).

Can you share your latest version of changeColor() ?

Note: he’s indexing into a single column texture… so while it’s strange that he uses the same value for texCoord x and y, it’s not wrong in this case.

yes, but he set

mesh.setBuffer(Type.TexCoord, 4,…)

in first exemple he used Color with 2 and uv data
in second example he used TexCoord with 4 and uv data

Heheh… I see. Then why didn’t you say so. :smile:

Simple answer then. Change:

To:

…but even wrong it should only cause half of his objects to be black and the other half to be oddly interpolated.

Because I’m poor teacher/speaker :stuck_out_tongue: and my brain was lock on first example with vertex Color buffer.

Else like you, I would like to know the value of yTexel (iirc texel are in pixel units vs textCoord uv in [0,1])