How to acheive transition between two textures on one mesh.[Solved]

im trying to make a mesh change its texture at run time.



one texture fades out, the other texture fades in. i searched the forum, but nothing helpful came out, so i guess i would just start a new post.



how do i do this?

or another possible solution to my problem would be make two meshes with two textures.



then fade out one of them at the same time fade in the other one.



but i cant seem to change the transparency of a mesh. for a quad i can do getDefaultColor().a = 0. but this doesnt work on mesh.

You could easily fade between two textures using GLSL shader, just pass in uniform time and mix() between two textures based on time.

lex said:

You could easily fade between two textures using GLSL shader, just pass in uniform time and mix() between two textures based on time.


im a total newbie on all the shader stuff....so can u plz give me more detail on how to do this?

thx~

an other way is to use multitexturing and alphastates instead of glsl shader

If you only want to fade between two textures, then there's no need for an AlphaState.

You can do this with by using texture combine environment:


        t2.setApply(Texture.AM_COMBINE);

        t2.setCombineFuncRGB(Texture.ACF_INTERPOLATE);

        t2.setCombineSrc0RGB(Texture.ACS_TEXTURE);
        t2.setCombineOp0RGB(Texture.ACO_SRC_COLOR);

        t2.setCombineSrc1RGB(Texture.ACS_PREVIOUS);
        t2.setCombineOp1RGB(Texture.ACO_SRC_COLOR);

        t2.setCombineSrc2RGB(Texture.ACS_CONSTANT);
        t2.setCombineOp2RGB(Texture.ACO_SRC_ALPHA);
       
        t2.setBlendColor(new ColorRGBA(1,1,1,0));
        
        // sets the new texture into unit 1 on the texture state
        ts.setTexture(t2,1);



Texture t2 is the texture to which the mesh should fade into. When you want to change the fade amount (every frame update) you must increment the constant color for t2:


// would fade in one second
t2.getBlendColor().a += tpf;
mesh.updateRenderState();



Once you're done fading (the alpha >= 1) you need to replace the original texture with the new texture:


// the default apply mode for textures
t2.setApply(Texture.AM_MODULATE);

ts.setTexture(t2,0);
ts.setTexture(null,1);



EDIT: Fixed mistake in code

ok :wink:

Well, I was working on a demo code, but Momoko beat me to it  :cry:



Here it is anyway (since it's written already):


import java.net.URISyntaxException;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingSphere;
import com.jme.image.Texture;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.shape.Box;
import com.jme.scene.state.TextureState;
import com.jme.util.TextureManager;
import com.jme.util.resource.ResourceLocatorTool;
import com.jme.util.resource.SimpleResourceLocator;

public class CombineExample extends SimpleGame {

   private ColorRGBA fadeColor = ColorRGBA.white.clone();
   private float fadeTime = 5; // in seconds
   private boolean fadingForward = true;// fading first texture to second
   
   @Override
   protected void simpleInitGame() {
      Box box = new Box("Monkey Box", Vector3f.ZERO.clone(), 5, 5, 5);
      box.setModelBound(new BoundingSphere());
      box.updateModelBound();
      
      Quaternion quat = new Quaternion();
      quat.fromAngles(FastMath.DEG_TO_RAD*30, FastMath.DEG_TO_RAD*30, 0);
      box.setLocalRotation(quat);
      
      try {
         ResourceLocatorTool.addResourceLocator(
               ResourceLocatorTool.TYPE_TEXTURE,
               new SimpleResourceLocator(
                     this.getClass().getClassLoader().getResource(
                           "jmetest/data/images/Monkey.jpg")));
      } catch (URISyntaxException e) {
         e.printStackTrace();
      }
      
      Texture monkey1 = TextureManager.loadTexture(
            "Monkey.jpg",
            Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR, 1.0f, true);
      
      Texture monkey2 = TextureManager.loadTexture(
            "Monkey.png",
            Texture.MM_LINEAR_LINEAR, Texture.FM_LINEAR, 1.0f, true);
      
      TextureState ts = display.getRenderer().createTextureState();
      ts.setTexture(monkey1);
      box.copyTextureCoords(0, 0, 1);
      ts.setTexture(monkey2, 1);
      box.setRenderState(ts);
      
      monkey2.setBlendColor(fadeColor);
      monkey2.setApply(Texture.AM_COMBINE);
      monkey2.setCombineFuncRGB(Texture.ACF_INTERPOLATE);
      monkey2.setCombineSrc0RGB(Texture.ACS_TEXTURE);
      monkey2.setCombineOp0RGB(Texture.ACO_SRC_COLOR);
      monkey2.setCombineSrc1RGB(Texture.ACS_PREVIOUS);
      monkey2.setCombineOp1RGB(Texture.ACO_SRC_COLOR);
      monkey2.setCombineSrc2RGB(Texture.ACS_CONSTANT);
      monkey2.setCombineOp2RGB(Texture.ACO_SRC_ALPHA);
      /*
      monkey2.setCombineFuncAlpha(Texture.ACF_INTERPOLATE);
      monkey2.setCombineSrc0Alpha(Texture.ACS_TEXTURE);
      monkey2.setCombineOp0Alpha(Texture.ACO_SRC_ALPHA);
      monkey2.setCombineSrc1Alpha(Texture.ACS_PREVIOUS);
      monkey2.setCombineOp1Alpha(Texture.ACO_SRC_ALPHA);
      monkey2.setCombineSrc2Alpha(Texture.ACS_CONSTANT);
      monkey2.setCombineOp2Alpha(Texture.ACO_SRC_ALPHA);
      */
      rootNode.attachChild(box);
      
      fadeColor.a = 0;
   }
   
   @Override
   protected void simpleUpdate() {
      if (fadingForward) {
         fadeColor.a += tpf/fadeTime;
      } else {
         fadeColor.a -= tpf/fadeTime;
      }
      
      if (fadeColor.a > 1) {
         fadeColor.a = 1;
         fadingForward = false;
      } else if (fadeColor.a < 0) {
         fadeColor.a = 0;
         fadingForward = true;
      }
   }
   
   protected void updateInput() {
      super.updateInput();
   }
   
   public static void main(String[] args) {
      Logger.getLogger("").setLevel(Level.WARNING);
      
      CombineExample game = new CombineExample();
      game.setDialogBehaviour(
            SimpleGame.ALWAYS_SHOW_PROPS_DIALOG);
      game.start();
   }

}

thank you guys sooooo much!



now i can fade one texture in ha.



but then the faded in texture doesnt get affected by the lighting. whats the problem?  :?

I always tend to forget about lighting…

If you want lighting, make the interpolation at unit 0 and then modulate it with lighting at unit 1:


        t.setApply(Texture.AM_COMBINE);

        t.setCombineFuncRGB(Texture.ACF_INTERPOLATE);

        t.setCombineSrc0RGB(Texture.ACS_TEXTURE1);
        t.setCombineOp0RGB(Texture.ACO_SRC_COLOR);

        t.setCombineSrc1RGB(Texture.ACS_TEXTURE);
        t.setCombineOp1RGB(Texture.ACO_SRC_COLOR);

        t.setCombineSrc2RGB(Texture.ACS_CONSTANT);
        t.setCombineOp2RGB(Texture.ACO_SRC_ALPHA);
      
        t.setBlendColor(new ColorRGBA(1,1,1,0));

        t2.setApply(Texture.AM_COMBINE);
       
        t2.setCombineFuncRGB(Texture.ACF_MODULATE);

        t2.setCombineSrc0RGB(Texture.ACS_PREVIOUS);
        t2.setCombineOp0RGB(Texture.ACO_SRC_COLOR);

        t2.setCombineSrc1RGB(Texture.ACS_PRIMARY_COLOR);
        t2.setCombineOp1RGB(Texture.ACO_SRC_COLOR);

i made the changes and it worked. but i still have some questions.



heres the code.


      TextureState texState = this.renderer.createTextureState();
      mesh.setRenderState(texState);
      this.fadingColor = new ColorRGBA(1, 1, 1, 0);
      texState.setTexture(defaultTexture, 0);
      texState.setTexture(fadeinTexture, 1);      
      defaultTexture.setApply(Texture.AM_COMBINE);
      defaultTexture.setCombineFuncRGB(Texture.ACF_INTERPOLATE);
      defaultTexture.setCombineSrc0RGB(Texture.ACS_TEXTURE1);
      defaultTexture.setCombineOp0RGB(Texture.ACO_SRC_COLOR);
      defaultTexture.setCombineSrc1RGB(Texture.ACS_TEXTURE);
      defaultTexture.setCombineOp1RGB(Texture.ACO_SRC_COLOR);
      defaultTexture.setCombineSrc2RGB(Texture.ACS_CONSTANT);
      defaultTexture.setCombineOp2RGB(Texture.ACO_SRC_ALPHA);
      defaultTexture.setBlendColor(this.fadingColor);
        fadeinTexture.setApply(Texture.AM_COMBINE);
        fadeinTexture.setCombineFuncRGB(Texture.ACF_MODULATE);
        fadeinTexture.setCombineSrc0RGB(Texture.ACS_PREVIOUS);
        fadeinTexture.setCombineOp0RGB(Texture.ACO_SRC_COLOR);
        fadeinTexture.setCombineSrc1RGB(Texture.ACS_PRIMARY_COLOR);
        fadeinTexture.setCombineOp1RGB(Texture.ACO_SRC_COLOR);
      mesh.copyTextureCoords(0, 0, 1);



1. how come the default texture has the blend color on it? doesnt that mean at the very beginning, the default texture has an alpha of 0?
2. what do all the combineSrc0RGB and CombineFucRGB mean? y r they set up in this way?

If you want to control alpha, there is a separate function to do so: setCombineFuncAlpha(). Then you set sources, operands and scaling for alpha the same way you did it for RGB (I have that piece commented out in my example).



Its hard to find a suitable tutorial on the net on how COMBINE mode works. Try one of the OpenGL books. This information should be in the latest "OpenGL Red Book, year 2006" and "OpenGL Super Bible, year 2007"… maybe older revisions of these books have the info as well, though the OpenGL Red Book for OpenGL 1.1 (this book is freely available on the net) doesnt have anything on COMBINE mode, because that mode was not available in OpenGL 1.1.

thx lex. i just bought the red book. time to learn ha :smiley:

hey there,



i ported the testcase above to jme 2.0 and it wont work. the whole screen is black but the statistics suggest that the box is there and being rendered.



EDIT: When i set the background color to gray i can see the black box



whats wrong with that code:



package jmetest.effects;

import java.net.URISyntaxException;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.jme.app.SimpleGame;
import com.jme.bounding.BoundingSphere;
import com.jme.image.Texture;
import com.jme.image.Texture.ApplyMode;
import com.jme.image.Texture.CombinerFunctionRGB;
import com.jme.image.Texture.CombinerOperandRGB;
import com.jme.image.Texture.CombinerSource;
import com.jme.math.FastMath;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.shape.Box;
import com.jme.scene.state.TextureState;
import com.jme.util.TextureManager;
import com.jme.util.resource.ResourceLocatorTool;
import com.jme.util.resource.SimpleResourceLocator;


public class CombineExample extends SimpleGame {

  private ColorRGBA fadeColor = ColorRGBA.white.clone();

  private float fadeTime = 5; // in seconds

  private boolean fadingForward = true;// fading first texture to second


  @Override
  protected void simpleInitGame() {
    Box box = new Box("Monkey Box", Vector3f.ZERO.clone(), 5, 5, 5);
    box.setModelBound(new BoundingSphere());
    box.updateModelBound();

    Quaternion quat = new Quaternion();
    quat.fromAngles(FastMath.DEG_TO_RAD * 30, FastMath.DEG_TO_RAD * 30, 0);
    box.setLocalRotation(quat);

    try {
      ResourceLocatorTool.addResourceLocator(ResourceLocatorTool.TYPE_TEXTURE, new SimpleResourceLocator(this
          .getClass().getClassLoader().getResource("jmetest/data/images/Monkey.jpg")));
    } catch(URISyntaxException e) {
      e.printStackTrace();
    }

    Texture monkey1 =
        TextureManager.loadTexture("Monkey.jpg", Texture.MinificationFilter.BilinearNoMipMaps,
            Texture.MagnificationFilter.Bilinear);

    Texture monkey2 =
        TextureManager.loadTexture("Monkey.png", Texture.MinificationFilter.BilinearNoMipMaps,
            Texture.MagnificationFilter.Bilinear);

    TextureState ts = display.getRenderer().createTextureState();
    ts.setTexture(monkey1);
    box.copyTextureCoordinates(0, 0, 1);
    ts.setTexture(monkey2, 1);
    box.setRenderState(ts);

    monkey2.setBlendColor(fadeColor);
    monkey2.setApply(ApplyMode.Combine);
    monkey2.setCombineFuncRGB(CombinerFunctionRGB.Interpolate);
    monkey2.setCombineSrc0RGB(CombinerSource.CurrentTexture);
    monkey2.setCombineOp0RGB(CombinerOperandRGB.SourceColor);
    monkey2.setCombineSrc1RGB(CombinerSource.Previous);
    monkey2.setCombineOp1RGB(CombinerOperandRGB.SourceColor);
    monkey2.setCombineSrc2RGB(CombinerSource.Constant);
    monkey2.setCombineOp2RGB(CombinerOperandRGB.SourceAlpha);
    rootNode.attachChild(box);
    /*
     * monkey2.setCombineFuncAlpha(Texture.ACF_INTERPOLATE); monkey2.setCombineSrc0Alpha(Texture.ACS_TEXTURE);
     * monkey2.setCombineOp0Alpha(Texture.ACO_SRC_ALPHA); monkey2.setCombineSrc1Alpha(Texture.ACS_PREVIOUS);
     * monkey2.setCombineOp1Alpha(Texture.ACO_SRC_ALPHA); monkey2.setCombineSrc2Alpha(Texture.ACS_CONSTANT);
     * monkey2.setCombineOp2Alpha(Texture.ACO_SRC_ALPHA);
     */
    rootNode.attachChild(box);

    fadeColor.a = 0;
  }


  @Override
  protected void simpleUpdate() {
    if (fadingForward) {
      fadeColor.a += tpf / fadeTime;
    } else {
      fadeColor.a -= tpf / fadeTime;
    }

    if (fadeColor.a > 1) {
      fadeColor.a = 1;
      fadingForward = false;
    } else if (fadeColor.a < 0) {
      fadeColor.a = 0;
      fadingForward = true;
    }
  }


  protected void updateInput() {
    super.updateInput();
  }


  public static void main(String[] args) {
    Logger.getLogger("").setLevel(Level.WARNING);

    CombineExample game = new CombineExample();
    game.setConfigShowMode(ConfigShowMode.AlwaysShow);
    game.start();
  }

}



im kind of in a hurry, plz help  ://

Here's one issue:


box.copyTextureCoordinates(0, 0, 1);



The API says:

copyTextureCoordinates(int fromIndex, int toIndex, float factor)

renanse said:

Here's one issue:

box.copyTextureCoordinates(0, 0, 1);


The API says:

copyTextureCoordinates(int fromIndex, int toIndex, float factor)




hey there,

Thanks so far but Im confused. box.copyTextureCoords(0, 0, 1); was used above with jme 1.0 as well and it worked. What parameters should I use instead? (0, 1, 1) will show only one texture of the two and nothing is fading there.

thx so far (and plz help  ;)).

k. found the answer to all my questrions: http://www.jmonkeyengine.com/jmeforum/index.php?topic=8250.0