Adding / modifying textures on a plane primitive on the fly.

Started by davec64, November 28, 2013, 04:57:53 AM

Previous topic - Next topic

davec64

Hi
I Have manged to get most of my visual effects working. However I have once again become stuck on changing textures based on the deformed plane height. spent over 2 days trying to work this one out.
If I change them to different incremental textures at the retexture stage. I see similar to what I expect see image each polygon clearly visible. Although I am not 100% on the output except that there are 2 polys per square.

When I try to get a polygon and apply a new texture. all the textures go back to my default texture and no polygons are visible any more.
I am sure this is just a misunderstanding of how to change the texture.
Any help greatly appreciated.
this is from my vertexcontroller that sets the z value that is done in a loop outside of this snippet.
When this code is applied it seems to apply to all the the polygons ( as if  there is one poly per column).


if (polyindex < maxPolygonID) {
            int depthiD = TextureManager.getInstance().getTextureID("depth" + (int) data % 29);
            if (depthiD == -1) {
             depthiD =  TextureManager.getInstance().getTextureID("depth0");

            }
            Logger.log("texture id = " + depthiD + "data = " + (int) data + "polyindex ="
                + polyindex);
            int t1 = pm.getPolygonTexture(polyindex);
            uv0 = pm.getTextureUV(polyindex, 0);
            uv1 = pm.getTextureUV(polyindex, 1);
            uv2 = pm.getTextureUV(polyindex, 2);
            TextureInfo ti = new TextureInfo(t1, uv0.x, uv0.y, uv1.x, uv1.y, uv2.x, uv2.y);
            ti.add(depthiD, uv0.x, uv0.y, uv1.x, uv1.y, uv2.x, uv2.y, TextureInfo.MODE_MODULATE);
            pm.setPolygonTexture(polyindex++, ti);

            t1 = pm.getPolygonTexture(polyindex);
            uv0 = pm.getTextureUV(polyindex, 0);
            uv1 = pm.getTextureUV(polyindex, 1);
            uv2 = pm.getTextureUV(polyindex, 2);
            ti = new TextureInfo(t1, uv0.x, uv0.y, uv1.x, uv1.y, uv2.x, uv2.y);
           ti.add(depthiD, uv0.x, uv0.y, uv1.x, uv1.y, uv2.x, uv2.y, TextureInfo.MODE_MODULATE);
            pm.setPolygonTexture(polyindex++, ti);
          }

Second attachment is with this code. It seems to upset the whole texture.
https://www.dropbox.com/sh/0epa1c6jved3dxu/XGq4d9ItAu

EgonOlsen

When does this re-texturing happen? At runtime, i.e. after the plane has been build() and/or rendered at least once? In that case, you can't do it that way. An object's mesh gets compiled to be processed by the GPU. During that step, it will be split into groups of polygons that share a common render state. That means that all polygons with the same texture will be grouped into one structure which will then be transfered to and rendered by the GPU.
If you are changing textures after this process, you can change them only per group and not individually anymore.
What you could do is to use one texture that contains all others instead and only change the texture coordinates for each polygon. If you are going this way, you have to add an explicit call of Object3D.compile(true, false); and you have to call Object3D.touch(); after setting the new coordinates.

davec64

Hi Yes this is at run time.
So it will have to be by group.
So you are saying create a master texture that has in my case.
30 textures of different shades.
Then change the coords of each polygon to point to the correct shade.
can you give me a brief example of this.
ie i have a texture map of 1024*1024 and 4 shades in this map
so 0,0,512,512 would be one next would be 0,512,512,1024 not sure if thats correct but you know what I mean.
Thanks
Dave 

EgonOlsen

Yes, similar to that. However, i don't understand why a simple colored texture has to be 512 pixels in size each. Something like 16*16 or 32*32 should be sufficient IMHO. Maybe we should take one step back: What are you actually trying to achieve? To assign a different color based on the height?

davec64

Yes a different colored texture based on height. It does not have to be so large that was just so that I could visualize the texture tile as it where. this is to show the depth of a channel like a topography. 16 *16 could work.
no problems I think.

davec64

All Done and it works really well.
I have 64 32*32 sub textures in a single 256*256 texture.
selecting the depth sets up the correct texture based on depth.
I have put the code up as an idiots guide of how to change a texture on an object that has already been built.

You must do this first before you compile. (retexture method from advanced example modified)


PolygonManager pm = obj.getPolygonManager();
    int t2Id = TextureManager.getInstance().getTextureID(t2);
    int end = pm.getMaxPolygonID();
    Logger.log(end + "num of polygons");
    int t1 = pm.getPolygonTexture(0);
    for (int i = 0; i < end; i++) {

      uv0 = new SimpleVector(0, 0, 0);
      uv1 = new SimpleVector(0, SUBTEXTURE, 0);
      uv2 = new SimpleVector(SUBTEXTURE, 0, 0);

      ti = new TextureInfo(t1, uv0.x, uv0.y, uv1.x, uv1.y, uv2.x, uv2.y);
      ti.add(t2Id, uv0.x, uv0.y, uv1.x, uv1.y, uv2.x, uv2.y, TextureInfo.MODE_REPLACE);
      pm.setPolygonTexture(i++, ti);

      uv0 = new SimpleVector(0, SUBTEXTURE, 0);
      uv1 = new SimpleVector(SUBTEXTURE, SUBTEXTURE, 0);
      uv2 = new SimpleVector(SUBTEXTURE, 0, 0);

      ti = new TextureInfo(t1, uv0.x, uv0.y, uv1.x, uv1.y, uv2.x, uv2.y);
      ti.add(t2Id, uv0.x, uv0.y, uv1.x, uv1.y, uv2.x, uv2.y, TextureInfo.MODE_REPLACE);
      pm.setPolygonTexture(i, ti);

then in your vertex controller

  if (polyindex < maxPolygonID) {

            textureIndexX = VesselRenderer.SUBTEXTURE * (int) ((depth * 2) % 8);
            textureIndexY = VesselRenderer.SUBTEXTURE * (int) ((depth * 2) / 8);

            uv0 = new SimpleVector(textureIndexX, textureIndexY, 0);
            uv1 = new SimpleVector(textureIndexX,
                textureIndexY + VesselRenderer.INTERNALSUBTEXTURE, 0);
            uv2 = new SimpleVector(textureIndexX + VesselRenderer.INTERNALSUBTEXTURE,
                textureIndexY, 0);
            ti = new TextureInfo(t1, uv0.x, uv0.y, uv1.x, uv1.y, uv2.x, uv2.y);
            ti.add(t1, uv0.x, uv0.y, uv1.x, uv1.y, uv2.x, uv2.y, TextureInfo.MODE_REPLACE);
            pm.setPolygonTexture(polyindex++, ti);

            uv0 = new SimpleVector(textureIndexX + VesselRenderer.INTERNALSUBTEXTURE, textureIndexY
                + VesselRenderer.INTERNALSUBTEXTURE, 0);
            ti = new TextureInfo(t1, uv1.x, uv1.y, uv0.x, uv0.y, uv2.x, uv2.y);
            ti.add(t1, uv1.x, uv1.y, uv0.x, uv0.y, uv2.x, uv2.y, TextureInfo.MODE_REPLACE);
            pm.setPolygonTexture(polyindex++, ti);

          }



initialise using these methods

     obj.calcNormals();
      // make sure to attach the controller before calling build() or otherwise, the object will be
      // compiled to static geometry and won't reflect any changes to the mesh.
      obj.getMesh().setVertexController(m_channelController, false);
      obj.compile(true, false);
      obj.build();

davec64

Spoke to soon
I am having an issue with the textures. They are not tiling correctly. If I use a tile 32*32 the top left I set to 0,0 then to get set the texture from my 256*256. I use 1/256 * 32 0 depth tile which should give me the far edge of the first of my depth texture  tiles ??.
I am getting part of the next tile or some thing is alias ing the edge of the texture when it is displayed.
I think this may be something that I have not done. I have played around with the far edge but it always does the same thing unless it is a solid color and it covers at least 2 extra pixels around the 1st tile texture.
It basically looks like there are extremely thin lines or a shadow on the edge of each polygon.
Not the hypotenuse. Just the edges.
Dave

EgonOlsen

That's because the bilinear filtering takes adjacent pixels into account. You have two options: use other texture coordinates. If the sections are uni-color anyway, that shouldn't matter. Or disable bilinear filtering (Texture.setFiltering(false)).

davec64

I Turned off the filtering and it helped a bit however I still saw the thin lines generated in between the polygon edges as the plane went further into the foreground.
So I called Texture.setClamping(true); and that seems to have had the most beneficial effect.
I then changed the texture coords slightly so as not to get to close to the edge of the next line of pixels.
Now it seems to be working as expected.
I turned the filtering back on as well.
Thanks
Dave

Screek

Hello, davec64, could you maybe write a bit more about your solution? For example, what are the SUBTEXTURE and depth variables for? And how should the texture look like? Or maybe you could make a simple example if you have time? Sorry for so many questions but I'm trying to do something like that from a week, but I'm not good at 3D stuff.

davec64

I have modified the technique slightly see the new modified vertex controller code.
depth is just an index to which texture you want to apply to the polygon.
Each texture is 32*32 if you want to use more just reduce the multiplier to 16 to give 16*16 textures  or make the main 256*256 texture larger.

# 256 is the texture size
# 32 is the size of each subtexture
/**
   * this is the fraction of the texture that represents 1 sub texture
   */
  public static float SUBTEXTURE = (float) ((1.0 / 256.0) * 32);

/**
   * this is the fraction of the texture that represents the inside of sub texture take away half a
   * pixel from the edge of the texture
   */
  public static float INTERNALSUBTEXTURE = (float) ((1.0 / 256.0) * 32 - (1 / 256));

Screek

Thank you for explanation, everything works as expected :)