[SOLVED] Can you setMaterial or color different vertex groups in a model?

I am trying to color different parts of my .j3o “human” model (like an arm or a leg) dynamically when running the model, but I dont know if its possible? The different parts is defined by vertex groups in the initial gltf model, loaded in Blender.

Would it be possible to achieve this?

Its a material per geometry (the material is actually specifying a shader program to run for that geometry, so you can’t have more than one). That doesn’t mean you can’t do interesting things; as in the end you could write your own shader to do whatever you want, although I don’t think that’s necessary here.

Feels like what you want could be achieved by creating a texture in memory (perhaps based on slicing together several pngs you’ve created for each part) and then setting that as the material’s texture*.

BufferedImage bufferedImage = ....
AWTLoader loader=new AWTLoader();
Texture2D texture=new Texture2D(loader.load(bufferedImage , true));

Alternatively you could individually colour each vertex if you don’t want to use UV mapping, I’ve only done that when constructing meshes in memory (it feels like I construct everything in memory now that I think about it) but I’m sure a similar approach could work starting from a blender produced mesh. See Custom Mesh Shapes :: jMonkeyEngine Docs for working with buffers and meshes directly.

1 Like

IMO best way to achieve what you need is to use alphamaps in custom shader.

For example tatoos / eye color / scars / freckles / etc

all of this i just overlay specific overlay texture or alphamap texture with specific color (here for eye color or tatoo color i have alphamap only for part of it and shader color this area with specific color)

So yes, it is simple shader to make this.

If you want color dynamically in-game where you want, you just need calculate UV coords based on what vertex mouse is on(see raytracing) and paint on alphamap that use specific color. Or you can just paint on colorMap directly, but then you would need store history if you want user be able to revert it.

About vertex groups i dont remember if they were stored somewhere after import, but its possible, because morph shapes probably use some.

1 Like

Thanks! I think your idea would work perfectly. It makes sense to create an overlapping texture, only coloring the part I want.

I will try to look into how I can create that “simple” shader. I am new to JME, but I guess there is some similar examples in other threads. If you have a small example for e.g. tatoos / eye color / scars / freckles / etc it would be gratefully appreciated.

sending only “parts related”. You need see how to write shaders first anyway.

in frag (you can take rest from default JME shader)

    #ifdef SKINTATOO
        vec2 uvTatoo = newTexCoord;
        uvTatoo.x += m_skinTatooOffsetX;
        uvTatoo.y += m_skinTatooOffsetY;
        float tatooAlpha = texture2D(m_SkinTatoo, uvTatoo).a;
        if(tatooAlpha > 0.3) {
            albedo.rgb = mix(albedo.rgb, m_skinTatooColorValue.rgb, tatooAlpha-0.3);
        }
    #endif

matdef(same, take missing code from JME default one)

        Texture2D SkinTatoo
        Float SkinTatooOffsetX
        Float SkinTatooOffsetY
        Float SkinTatooIntensity : 1.0
        Color skinTatooColorValue (Color)
        Defines {         
            SKINTATOO : SkinTatoo

and default vert shader(for example same from PBR or lighting in JME)

ofc you need provide SkinTatoo texture(overlay alphamap texture) and other params like color in material. You can create one in Blender using Nodes there also creating overlay texture (myself i suggest PNG textures where you can use r,g,b,a data, while please note in this example we only need a, so rgb is useless(not needed memory usage) for a texture because we take rgb from color param )

1 Like

Thanks for the solution! I think it would work perfectly.

However, I found another and more simple solution for me. In Blender before exporting, I seperated the mesh from “Alpha_Surface” for each vertex group so I ended up with a seperate mesh for each bodypart.

In my app, I can now assign a unique material to the geometry of each mesh, like

Geometry geo = (Geometry) human.getChild("Arm_Mesh");
geo.setMaterial(material);
2 Likes

you dont even need separate mesh.

you can just apply different material, and JME will have it as separate mesh.

Anyway your soltion here is limited to vertex and is slower(because more geoms = more drawcalls that is bad - see geom batching). But yes, it is more simply.

1 Like

Ahhh okay, thanks. I get that it would be slower.