Uniform texture on a surface made by triangles

Hi, I have a surface representing the floor. It is a spatial made out of triangles (as it could be any polygon). When I apply a texture material to it, instead of applying as it was one surface, it seems odd. The texture is like stretched or something, and it is applied differently on any triangle.

Each time I run the program, the texture is displayed different. Additionally, when I place a spatial on it, the aspect changes, but only with the first one. That is, it is diplayed one way with 0 additional spatials, and another way with 1+. If I remove the spatial, it is seen as before.

Let’s show it with images:

Before dropping the spatial:
before dropping the spatial

After dropping the spatial:
after dropping the spatial

We can’t see your mesh setup so we cannot properly comment on anything wrong. (I’m holding this piece of string, can you tell me how long it is?)

So I will throw random guesses out in the hopes that one sticks…

First, did you set texture coordinates?

That is odd. You don’t really give enough information for anyone to help you though.

How are you building the floor?

How are you creating your material?

This is the code where I form the Spatial. Take in account that I’m a n00b in 3D programming.


    /**
     * Creates a Spatial that corresponds to the surface object.
     * @param surface
     * @param material
     * @param doubleFaced if the object must be drawn in its two faces. Set to 
     * false if only one face is drawn (maybe useful for walls).
     * @return a  Spatial that corresponds to the surface object.
     */
    public Spatial createSurface(Surface surface, Material material, boolean doubleFaced) {
        Spatial result;
        Node node = new Node(surface.getId());
                
        List<SpatialLocation> corners = surface.getCorners();
        Set<Mesh> triangles = operator.getTriangles(corners, doubleFaced);
        
        for(Mesh triangle: triangles) {
            Geometry geom = new Geometry(triangle.toString(), triangle);
            
            node.attachChild(geom);
        }
        result = GeometryBatchFactory.optimize(node);
        result.setMaterial(material);
                    
        return result;
    }

operator is a member of an inner class that makes the triangulation. I wrote it several months ago, so I don’t remember it quite well


    /**
     * Helper class to calculate triangulation.
     * 
     * Uses java3d technology.
     */
    private class J3dOperator {
        
        private Set<Mesh> getTriangles(List<SpatialLocation> corners, boolean doubleFaced) {
            Set<Mesh> result = new HashSet<Mesh>();
            
            double[] vertexArray = new double[corners.size()*3];
            
            int i=0;
            
            /*
             * Insert corners in vertex array.
             * 
             * Coordinates components (x,y,z) are simply append one after 
             * another.
             */
            for(SpatialLocation corner: corners) {
                vertexArray[(i*3)] = corner.getX();
                vertexArray[(i*3)+1] = corner.getY();
                vertexArray[(i*3)+2] = corner.getZ();
                i++;
            }
            
            // Create polygon structure.
            GeometryInfo gi = new GeometryInfo(GeometryInfo.POLYGON_ARRAY);
            gi.setCoordinates( vertexArray );
            int[] stripCountArray = {corners.size()};
            int[] countourCountArray = {stripCountArray.length};
            gi.setContourCounts( countourCountArray );
            gi.setStripCounts( stripCountArray );
            //Forces triangulation
            gi.getGeometryArray();

            // Take the vertices of the polygon's triangles and build the vertex
            Point3f[] trianglesVertices = gi.getCoordinates();
            
            for( i=0; i<trianglesVertices.length; i+=3) {
                Mesh mesh = triangle2Mesh(trianglesVertices[i], 
                        trianglesVertices[i+1], trianglesVertices[i+2]);
                result.add(mesh);
                
                /* If the surface must be drawn in both faces, the inverse 
                 * triangle must be added.
                 */
                if(doubleFaced) {
                    mesh = triangle2Mesh(trianglesVertices[i+2], 
                            trianglesVertices[i+1], trianglesVertices[i]);
                    result.add(mesh);
                }
            }
            
            
            return result;
        }

        private Mesh triangle2Mesh(Point3f v1, Point3f v2, Point3f v3) {
            Mesh mesh = new Mesh();
            
            Vector3f[] vertices = new Vector3f[3];
            int i=0;
            
            if(v1!=null)
                vertices[i++] = new Vector3f( 
                        (float) v1.x,
                        (float) v1.y,
                        (float) v1.z
                );
            
            if(v2!=null)
                vertices[i++] = new Vector3f( 
                        (float) v2.x,
                        (float) v2.y,
                        (float) v2.z
                );
            
            if(v3!=null)
                vertices[i++] = new Vector3f( 
                        (float) v3.x,
                        (float) v3.y,
                        (float) v3.z
                );
            
            int[] indexes = {0, 1, 2 };
            
            mesh.setBuffer(Type.Position, 3, BufferUtils.createFloatBuffer(vertices));
            mesh.setBuffer(Type.Index, 1, BufferUtils.createIntBuffer(indexes));

            
            // TODO texture coordinates?
            // TODO indexes?
            
            mesh.updateBound();
            
            
            return mesh;
        }
    }

Copypasteing the code, I see I had a pair of TODO, one of them “TODO texture coordinates”. I don’t remember which tutorial may I be following and I don’t know exactly what “texture coordinates” are.

Here is the material. It is not written by me, but by a coworker who I cannot contact at the moment. I don’t know much about materials.


Material MyMaterial : Common/MatDefs/Light/Lighting.j3md {
    MaterialParameters {
        ParallaxHeight : 0.05
        Shininess : 64.0
        Minnaert : true
        DiffuseMap : Flip Repeat Textures/habitacion/suelo_1_dif.jpg
        NormalMap : Flip Repeat Textures/habitacion/suelo_1_bump.jpg
        VertexLighting : false
        UseVertexColor : false
        SteepParallax : false
        LightMap : Flip Repeat Textures/habitacion/suelo_1_spcu.jpg
    }
    AdditionalRenderState {
      FaceCull Back
      Wireframe Off
      DepthWrite On
      PolyOffset 0.0 0.0
      AlphaTestFalloff 0.0
      Blend Off
      PointSprite Off
      ColorWrite On
      DepthTest On
    }
}

:o

Wait.

You are taking a mesh made of triangles, splitting it into triangles then recombining it into a mesh???

Why???

I see swing buttons but no code to enqueue the calls to the right thread (the jme/opengl one). Seems like dangerous threading, if you don’t do that you can get all kinds of issues and especially changing results.

<cite>@zarch said:</cite> :o

Wait.

You are taking a mesh made of triangles, splitting it into triangles then recombining it into a mesh???

Why???

I don’t think I’m doing such a thing. Surface is a custom class. For what it matters, it contains the corners of the walls or the floor, but it doesn’t have the triangles. All these methods are for getting the mesh from this information. Were you referring to that, or where else I’m doing the double transformation?

<cite>@normen said:</cite> I see swing buttons but no code to enqueue the calls to the right thread (the jme/opengl one). Seems like dangerous threading, if you don't do that you can get all kinds of issues and especially changing results.

When (and only when) the gui introduces changes into the JME view, I make this way:


    void place(final Piece piece) {
        enqueue(new Callable() {

            @Override
            public Object call() throws Exception {
                addPiece(piece);
                return true;
            }
        });
    }

Is there anything wrong in that?

Side question: If I use “code” tags to enclose my source, why do I get such bad formatting? How should I paste code?

@jmonillo said:

When (and only when) the gui introduces changes into the JME view, I make this way:


    void place(final Piece piece) {
        enqueue(new Callable() {

            @Override
            public Object call() throws Exception {
                addPiece(piece);
                return true;
            }
        });
    }

Is there anything wrong in that?

Nope, thats cool. Just couldn’t see that from the previous post and its a common source for inconsistent problems.

<cite>@jmonillo said:</cite> I don't think I'm doing such a thing. Surface is a custom class. For what it matters, it contains the corners of the walls or the floor, but it doesn't have the triangles. All these methods are for getting the mesh from this information. Were you referring to that, or where else I'm doing the double transformation?

[java]`
public Spatial createSurface(Surface surface, Material material, boolean doubleFaced) {
Spatial result;
Node node = new Node(surface.getId());

    List&lt;SpatialLocation&gt; corners = surface.getCorners();
    Set&lt;Mesh&gt; triangles = operator.getTriangles(corners, doubleFaced);
    
    for(Mesh triangle: triangles) {
        Geometry geom = new Geometry(triangle.toString(), triangle);
        
        node.attachChild(geom);
    }
    result = GeometryBatchFactory.optimize(node);
    result.setMaterial(material);
                
    return result;
}

[/java]`

I could have miss-understood but at a glance this function looks weird to me. For every triangle create a new geometry for that triangle and attach it to a node then optimize the node?

What’s the purpose of this method, what is it trying to achieve?

@jmonillo said: Copypasteing the code, I see I had a pair of TODO, one of them "TODO texture coordinates". I don't remember which tutorial may I be following and I don't know exactly what "texture coordinates" are.

So, you have a bunch of vertexes hanging in space and you put a texture on it. Where should the texture go? Which texture/pixel (texel) should go at which vertex? JME/OpenGL can’t guess. You have to tell it… by giving each vertex a texture coordinate.

If you are using a material that is expecting texture coordinates then you may end up with random garbage in that buffer as you look around.

We don’t see enough of your material to know if that’s the case.

Edit: actually if your material is based on JME’s standard lighting material then you will for sure need texture buffers for your meshes.

<cite>@jmonillo said:</cite>

Side question: If I use “code” tags to enclose my source, why do I get such bad formatting? How should I paste code?

Put the word java in square brackets at the start and then backslash java in square brackets at the end.

There used to be buttons to add it but they seem to have vanished :s

Note: JME’s Quad class is a good example of setting up a simple mesh. Just look at the source if you need an example.

<cite>@zarch said:</cite>

I could have miss-understood but at a glance this function looks weird to me. For every triangle create a new geometry for that triangle and attach it to a node then optimize the node?

What’s the purpose of this method, what is it trying to achieve?

That’s they way I found on a tutorial to create a geometry with all the triangles. Create a node, attach all the triangles to it, and then optimize it to get a single geometry. As the triangles are meshes and not geometries, I cannot add directly to the node. Or so I think with my little knowledge.

<cite>@pspeed said:</cite> So, you have a bunch of vertexes hanging in space and you put a texture on it. Where should the texture go? Which texture/pixel (texel) should go at which vertex? JME/OpenGL can't guess. You have to tell it... by giving each vertex a texture coordinate.

I suspect that when I wrote this code from an example, I quite didn’t understand it and how to do the same on my own code, so I postponed it. As I was using materials without textures until now, all worked perfectly, so I forgot about it. I’m going to work on that, and see if I am capable now of understanding it a little better.

@jmonillo said: That's they way I found on a tutorial to create a geometry with all the triangles. Create a node, attach all the triangles to it, and then optimize it to get a single geometry. As the triangles are meshes and not geometries, I cannot add directly to the node. Or so I think with my little knowledge.

I suspect that when I wrote this code from an example, I quite didn’t understand it and how to do the same on my own code, so I postponed it. As I was using materials without textures until now, all worked perfectly, so I forgot about it. I’m going to work on that, and see if I am capable now of understanding it a little better.

http://code.google.com/p/jmonkeyengine/source/browse/trunk/engine/src/core/com/jme3/scene/shape/Quad.java

Also, in the long run if you are manually constructing the mesh anyway then it might be better to just bundle it at that time instead of making some large number of triangles and then forcing them into one mesh, ie: just make a mesh with all of the triangles in it. Once you get knowledgeable enough.

Thanks for pointing me again the Quad class. I had already looked at it (with the JME3 editor), but it’s hard for me to understand. Sorry for not mentioning it.

I also don’t understand very well your last paragraph. What do you mean with bundle it?

The problem is: I have a polygonal room of arbitrary dimensions and shape. The walls are always Quads, but the floor can be any polygon. After searching and reading a lot (and understanding only a few of what I read), I came to the conclusion that I should made the floor by triangulation.

I came with an example whose URL I have lost.

How should I do the mesh with all the triangles in it?

Anyway, I’m working on getting more knowleadgeable. My lack of knowledge is making hard even explaining my problem. I’ll investigate about texture coordinates and try to understand Quad code. I’ll also try to locate the example I used, to see if I better understand it now.

Many thanks for your help.

It sounds like you are trying to make a custom mesh, there is a full tutorial page here: https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:custom_meshes

@jmonillo said: Thanks for pointing me again the Quad class. I had already looked at it (with the JME3 editor), but it's hard for me to understand. Sorry for not mentioning it.

I also don’t understand very well your last paragraph. What do you mean with bundle it?

The problem is: I have a polygonal room of arbitrary dimensions and shape. The walls are always Quads, but the floor can be any polygon. After searching and reading a lot (and understanding only a few of what I read), I came to the conclusion that I should made the floor by triangulation.

I came with an example whose URL I have lost.

How should I do the mesh with all the triangles in it?

Anyway, I’m working on getting more knowleadgeable. My lack of knowledge is making hard even explaining my problem. I’ll investigate about texture coordinates and try to understand Quad code. I’ll also try to locate the example I used, to see if I better understand it now.

Many thanks for your help.

A mesh can have any number of triangles… just make bigger buffers. For example, quad has two triangles in it. They happen to share some vertexes but that is not a requirement (just a good idea).

You will want to learn enough that you can at least understand what Quad is doing and why. Hopefully the link Zarch provided is helpful, though you may have already seen it.

Yes I had. Now I remember that whatever I did in my code was following this (and possibly other sources). But I fail to understand the texture coordinates bit.

[java]
Vector2f[] texCoord = new Vector2f[4];
texCoord[0] = new Vector2f(0,0);
texCoord[1] = new Vector2f(1,0);
texCoord[2] = new Vector2f(0,1);
texCoord[3] = new Vector2f(1,1);
[/java]

I understand that they must be set in the same order than the vertex. But I don’t know why those numbers precisely, what’s the logic behind the coordinates assignation. As I don’t understand it, I don’t know what texture coordinates should I use building my mesh.

Each texture goes from 0 to 1 in x and y (u and v) directions.

So a texture co-ordinate of 1,1 is the upper right corner of the texture. 0,0 lower left corner.

Numbers outside that range get mapped according to the settings, for example they might wrap.

I fail to see it, I’m sorry. How would that be with, for instance, a pentagon?