Adding several images to achieve one diffuse map?

How would I go about making a Material Definition that would allow me to specify 3 or 4 diffuse maps, tint each one a different color, then add them together? I know how I’d make the MatDef file, it’s just the shader that would be harder. Each image has a clear background (alpha = 0) and they don’t overlap anywhere. If it helps, I’ll explain what I’m trying to achieve. I’m trying to make a way to customize the colors of a weapon in my game. There’s 3 different colors: Main, Secondary, and Extra. I want the players to be able to make these whatever color they want. My idea is to add each texture together, then overlay a detail map (like scratches, screws, basic details that are on all the weapons). So each base picture is just a chunk of the UV map that’s solid white. The tint would make the Main layer whatever color the player chooses. The shader would have to go something like:

get main texture
tint it (find all white pixels, make them the chosen color?)
get secondary texture
tint it
get extra texture
tint it
add main + secondary + extra
add detail map

The problem would be it probably contains a lot of overhead to be calculating per frame. I was thinking maybe rendering the textures during load time. Another approach I thought of would be making a class that contains each one, called WeaponMaterial or something like that. Have a Texture2D instance of each one. When a player customizes a color, it would update the WeaponMaterial, which would tint the Texture2D (would this be possible?) and add them back together (is it possible to just add Texture2Ds?) and output the final diffuse map.

It’s a pretty ambitious idea, and if it won’t work I won’t complain. I’m really inexperienced with GLSL (I plan to learn more sooner or later) and figured I could get some advice from people that know what they’re doing. Thanks in advance!

You would have to write the shader for that, with multiple texture slots etc. But I generally think you should probably pre-generate that instead of waste GPU cycles on this. Either on the CPU if you want to make it dynamically like in this case or while editing the model/level/whatever, using an image or 3d editor.

@normen that’s what I was thinking. Generate it in a WeaponMaterial class. I just messed with the Image.class file, and it has an addData(ByteBuffer data) method, and also a getData(int index) method. Would these do what I’m looking for? If so, how would I tint them? I more or less just want to change all white pixels in the texture to whatever the chosen color is. I don’t think it’d be too difficult, would it?

http://hub.jmonkeyengine.org/javadoc/com/jme3/texture/image/ImageRaster.html

@pspeed I just messed with FrameBuffer as well. Would I be able to use ImageRaster to tint them, then FrameBuffer to add them? Also, would I have to iterate over EVERY pixel in the image manually, check for it’s color, and tint it? I’ll be pre-calculating these during the level load time so that could make the load time get pretty huge.

Somebody will have to do all those pixels, it will not take long :wink: Theres a plugin to more conveniently draw to jme3 images (akin to swing Graphics2D) in the update center, called “Image Painter”.

@normen I’ll check it out. I’m writing some pseudo-code and I’ll test it out in a little. Thanks for the help!

@pspeed I’m having a problem with the ImageRaster. It’s reading the image, and it gets to the pixel (1, 150). It throws an IllegalArgumentException. The stack trace:

at java.nio.Buffer.position(Buffer.java:236)
at com.jme3.texture.image.ByteAlignedImageCodec.readPixelRaw(ByteAlignedImageCodec.java:30)
at com.jme3.texture.image.ByteAlignedImageCodec.readComponents(ByteAlignedImageCodec.java:82)
at com.jme3.texture.image.DefaultImageRaster.getPixel(DefaultImageRaster.java:76)
at com.jme3.texture.image.ImageRaster.getPixel(ImageRaster.java:138)
at com.vinex.lexicon.weapons.WeaponMaterial.setMainColor(WeaponMaterial.java:50)
at com.vinex.lexicon.test.WeaponMaterialCustomizerTest.simpleInitApp(WeaponMaterialCustomizerTest.java:30)
at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:225)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:130)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:207)
at java.lang.Thread.run(Thread.java:722)

Any idea what could be causing it?

PS: I looked at the image. the pixel at 1, 150 is black, just like every pixel it’s scanned before it. There’s nothing different about it. I really don’t know what could be causing this.

Are you sure it’s an IllegalArgumentException? I don’t have any idea really. I’ve never really looked into these classes but I have used them successfully a few times.

@pspeed I fixed that problem. Now I have the following problems:

  1. The method setPixel(int x, int y, ColorRGBA color) doesn’t seem to modify my image. Is there a step I’m missing? Is there a way to get edited pixels out of the ImageRaster and into the image?

  2. It takes a LONG time. The texture is 800x800 and it takes about 2 minutes. Though this could be because I’m outputting the coordinates of each pixel it tests. I’ll take that off and see how long it takes then.

@vinexgames said: @pspeed I fixed that problem. Now I have the following problems:
  1. The method setPixel(int x, int y, ColorRGBA color) doesn’t seem to modify my image. Is there a step I’m missing? Is there a way to get edited pixels out of the ImageRaster and into the image?

You don’t have to do anything else. Something else is at play… but I can’t see the code from here.

@vinexgames said: 2. It takes a LONG time. The texture is 800x800 and it takes about 2 minutes. Though this could be because I'm outputting the coordinates of each pixel it tests. I'll take that off and see how long it takes then.

800x800 should not take two minutes. It has to be the excessive logging.

I just remembered I wrote my code to replace black instead of white, which is why I didn’t see the result. I feel dumb. As for the excessive logging, I was using it to test where it was failing. I’ll fix it all soon, whenever I’m back on my work computer. Thanks for the tips!

Textures should be power of two really (512x512 or 1024x1024).
HeroDex draws loads of textures not much small than the one you just described and each one takes a fraction of a second.
You really should check out the ImagePainter plugin, it’s got a lot more high level tools like painting images, using blend modes, etc.

@zarch I’ve almost got it finished with the ImageRaster. It paints it all perfectly now, it’s just that the texture seems to be upside down and I can’t seem to find how to flip the texture in code. In the material editor there’s a little check box for it, and in the Material’s source file it just says "DiffuseMap: Flip ‘texture path’ " so I don’t know what to do there. Is it a boolean value? What is it called?

@vinexgames said: @zarch I've almost got it finished with the ImageRaster. It paints it all perfectly now, it's just that the texture seems to be upside down and I can't seem to find how to flip the texture in code. In the material editor there's a little check box for it, and in the Material's source file it just says "DiffuseMap: Flip 'texture path' " so I don't know what to do there. Is it a boolean value? What is it called?

What kind of geometry are you putting it on?

You have two real choices:

  1. paint the texture right side up in the first place.
  2. change the texture coordinates of the mesh.

@pspeed I figured it out. I just painted the textures “upside down” instead of “right-side up” and it’s working now. It seems like as soon as I give up and decide to ask for help I figure out the answer. xD thanks anyway!