Changing Materials at run time question

Hello all,



I am trying to have a model transition from its normal textured color to red. I was going to try doing this by creating a new material and reapplying it to the model every frame. Seems kinda slow to do it that way, but Im not really sure of another way (im a new to this).



Anyways, I was trying it and I keep getting the following error:



SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]

java.lang.IllegalArgumentException: Material parameter is not defined: ColorMap

at com.jme3.material.Material.checkSetParam(Material.java:250)

at com.jme3.material.Material.setTextureParam(Material.java:281)

at com.jme3.material.Material.setTexture(Material.java:321)

at mygame.DogVisualization.Update(DogVisualization.java:66)

at mygame.Main.simpleUpdate(Main.java:69)

at com.jme3.app.SimpleApplication.update(SimpleApplication.java:208)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:144)

at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:141)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:198)

at java.lang.Thread.run(Thread.java:662)



The code that is running when I get this error is:



if(this.currentColor != this.changeToColor)

{

//must change color to next phase in colors.

Texture ninjaTexture = assetManager.loadTexture(“Models/Ninja/Ninja.jpg”);

//Material newMat = new Material(assetManager, “Models/Ninja/Ninja.material”);



Material newMat = new Material(assetManager, “Common/MatDefs/Misc/SimpleTextured.j3md”);

newMat.setTexture(“ColorMap”,ninjaTexture); <


line 66, the problem line
newMat.setColor("Color", new ColorRGBA(1.0f,0.0f,0.0f,0.5f));
this.currentColor = this.changeToColor;
}

Anybody know whats going wrong? Thanks for any advise. I would also be interested in more run-time friendly ways of doing this, than reloading the texture everytime, I was hoping there was a way to get the material from the model and then just set the color, and then reapply it without having to touch the assetManager.

Here is the code used for initially loading the model:
dogModel = assetManager.loadModel("Models/Ninja/Ninja.mesh.xml");
dogModel.scale(0.028f, 0.028f, 0.028f);
dogModel.rotate(0.0f, -3.0f, 0.0f);
dogModel.setLocalTranslation(0.0f, -2.5f, -2.0f);

THe ninja is just a stand in for now, to be replaced soon.

Thanks again,
~David

You can set material parameters while the app is running without having to reload the entire material and set it on the mesh.

I suggest you modify the SimpleTextured material (fragment shader) to take in a color and a multiplier value (0-100%) and then multiply the texture by that color. Then every frame you can pass in a new multiplier to the material and watch the texture change into that color.



As for your error, check the SimpleTextured.j3md file to see what parameters it takes. An older version of the materials had their parameters prepended with “m_”, new versions do not. So take a look at your j3md file and see what it requires.

Hi Sploreg,



Thanks for the tip. I am looking at SimpleTextured.j3md and SimpleTextured.frag and trying to decipher the changes needing to be made. I have never worked with a shader before or even understand half of whats happening in here. Is there a tutorial that I can take a walk through, or perhaps a blog, or documentation I can read through to see what needs to be done to get this right. I would really hate posting to these forums constantly for details that are readily available on public documentation.



As far as reapplying the texture, it was infact m_Color that needed to be used. I have run into a new issue of:

newMat.setColor(“Color”, new ColorRGBA(1.0f,0.0f,0.0f,0.5f)); <


this line here

Material parameter is not defined: Color

I was following the tutorial in the "Hello Materials" section to do this. The code is exactly as above except with m_ColorMap replacing ColorMap.

Im working both scenarios at the same time (the idea being even if the reapplication of the material works first, I at least have something that reflects decisions made by my data model)

Thanks again for any help,
~David

In Eclipse, hit Ctrl+Shift+R to open up the simpleTextured.j3md file; in NetBeans hit Alt+Shift+O to open it up.

You will want the jme source code in order to view the material.

ColoredTextured.j3md will sort of do what you want, but in a backwards sort of way (it will color the transparent parts of the texture).



The fragment shader I was talking about is SimpleTextured.frag.

thanks, I found that, I’m trying to understand it (I edited my earlier post so that I wasn’t needlessly bumping my post up to the top).



You mentioned parameters that it takes in. Im not really sure how to change it at run time either. Is there a way to do something such as the following:



Model X

Material Y



x.setMaterial(Y)

x.getMaterial().setColor(RED, 0.5f);



Sorry about all the questions, this isnt quite my forte yet,

~David



Also having trouble editing the file (it just beeps everytime I try to type something, but its not marked as read only)

Here is some code that will create a quad and set the color of it by passing in a parameter to the material:

[java]

Material mat = new Material(assetManager, "Common/MatDefs/Misc/ColoredTextured.j3md");

mat.setTexture("ColorMap", assetManager.loadTexture("Textures/ColoredTex/Monkey.png"));

mat.setColor("Color", ColorRGBA.Red);

quad.setMaterial(mat);

[/java]



The first parameter of the material is the material parameter. You can se what parameters the material takes by looking at the j3md file. For this example look at ColoredTextured.j3md.

The second parameter is the value you want to set for that parameter, in this case the color red.

Here, I created the material you will need and a sample program to go along with it. In the program in the simpleUpdate() method you can see that it updates the color every frame by setting the material parameter “mat.setColor(“Color”, currentColor);”

You will need the following 3 material files, and the last file is the example program:



MyColoredTextured.j3md

[java]MaterialDef Colored Textured {



MaterialParameters {

Texture2D Texture

Color Color

}



Technique {

VertexShader GLSL100: /MyColoredTextured.vert

FragmentShader GLSL100: /MyColoredTextured.frag



WorldParameters {

WorldViewProjectionMatrix

}

}



Technique FixedFunc {

}



}[/java]





MyColoredTextured.vert

[java]uniform mat4 g_WorldViewProjectionMatrix;



attribute vec3 inPosition;

attribute vec2 inTexCoord;



varying vec2 texCoord;



void main(){

gl_Position = g_WorldViewProjectionMatrix * vec4(inPosition, 1.0);

texCoord = inTexCoord;

}[/java]





MyColoredTextured.frag

[java]varying vec2 texCoord;



uniform sampler2D m_Texture;

uniform vec4 m_Color;



void main(){

vec4 texColor = texture2D(m_Texture, texCoord);

gl_FragColor = vec4(mix(texColor.rgb, m_Color.rgb, m_Color.a), 1.0);

}[/java]





TestColor.java

[java]public class TestColor extends SimpleApplication {



private float time = 0;

private boolean fadeToRed = true;

private ColorRGBA nextColor, prevColor;

private Material mat;



public static void main(String[] args){

TestColor app = new TestColor();

app.start();

}



@Override

public void simpleInitApp() {

Box quadMesh = new Box(1, 1, 1);

Geometry quad = new Geometry(“Box”, quadMesh);



mat = new Material(assetManager, “/MyColoredTextured.j3md”);

mat.setTexture(“Texture”, assetManager.loadTexture(“Textures/Terrain/splat/dirt.jpg”));

mat.setColor(“Color”, new ColorRGBA(1,0,0,0)); // transparent red

quad.setMaterial(mat);

rootNode.attachChild(quad);



prevColor = new ColorRGBA(1,0,0,0); // transparent red

nextColor = new ColorRGBA(1,0,0,1); // opaque red

}



@Override

public void simpleUpdate(float tpf){

time += tpf;

if (time > 1f){

time -= 1f;

fadeToRed = !fadeToRed;

if (fadeToRed) {

prevColor = new ColorRGBA(1,0,0,0); // transparent red

nextColor = new ColorRGBA(1,0,0,1); // opaque red

} else {

prevColor = new ColorRGBA(1,0,0,1); // opaque red

nextColor = new ColorRGBA(1,0,0,0); // transparent red

}



}

ColorRGBA currentColor = new ColorRGBA();

currentColor.interpolate(prevColor, nextColor, time);



mat.setColor(“Color”, currentColor);

}

}[/java]

1 Like

Hello Again,



Thanks alot, works like a charm, there were a few changes I had to make to the code you provided, mostly wild guesses that ended up working out. I had to rename a few of the parameters provided to m_ColorMap, or m_Color in the .frag file so that it matched with other files that used those definitions.



The one thing that I am noticing a bit different that I would like to fix, though I haven’t sat down to figure it out yet (I only get 10 hours per week to work in the lab due to University funding and restrictions etc etc) is the light source no longer seems to affect the model with the new shader.



I’ll probably look at the simpleTextured shader and see what it is doing, because that one when I was using it had my model being shaded by the light source. I did notice in the output that it said:



Ninja emmisive, not sure what that means yet, but Ill be hunting it down once I am able to access the lab either tomarrow or friday.



Thanks again

~David

Yes this material I posted does not use light sources. I leave that as an exercise for you to play with :slight_smile: