Method to fix seams in tiled meshes

Attached you will find a method to corrects seams between squared meshes which will result by having different normals. Can be called after loading the mesh and ev. before you generate tangents. Works only on squared meshes in the x, z plane.



screenshot shows seams on the left (no fix) and no seams on the right (fix applied):



http://3d-inferno.com/Jme/tileseams.jpg





code (java button didn’t work for me):









/**

  • Fix the normals of vertices lying on the edge of a tile to face a direction ON the edge. The result will be
  • that two tiles corrected by this way will do not have seams on adjecant vertices.
  • The algorithm works by moving the normal x and z values to 0 if the vertex is on the corresponding border.
  • @param mesh The mesh, normals should be fixed
  • @param borderDistance The distance from the center to one border, asuming all 4 borders at same distance
  • @param borderTolerance The positive tolerance value for checks if a vertex is on the border. Anything vertex within that distance to a border will be fixed.

    */

    public static void fixTileNormals(Mesh mesh, float borderDistance, float borderTolerance){

    FloatBuffer vertexBuffer = (FloatBuffer) mesh.getBuffer(Type.Position).getData();

    FloatBuffer normalBuffer = (FloatBuffer) mesh.getBuffer(Type.Normal).getData();

    FloatBuffer normals = BufferUtils.createFloatBuffer(vertexBuffer.capacity());

    Vector3f v = new Vector3f();

    Vector3f n = new Vector3f();

    //just loop over all values, whatever type it is, a vertex has its normal at the corresponding index

    for (int i = 0; i < vertexBuffer.capacity()/3; i++) {

    populateFromBuffer(v, vertexBuffer, i);

    populateFromBuffer(n, normalBuffer, i);



    //on left or right border, the set x comp of normal to 0

    if(FastMath.abs(v.x+borderDistance) <=borderTolerance) n.x = 0f;

    else if(FastMath.abs(-v.x+borderDistance) <=borderTolerance) n.x = 0f;

    //on top or bottom border, the set z comp of normal to 0

    if(FastMath.abs(v.z+borderDistance) <=borderTolerance) n.z = 0f;

    else if(FastMath.abs(-v.z+borderDistance) <=borderTolerance) n.z = 0f;



    n.normalizeLocal();

    normals.put(n.x);

    normals.put(n.y);

    normals.put(n.z);

    }

    mesh.clearBuffer(Type.Normal);

    mesh.setBuffer(Type.Normal, 3, normals);

    }
3 Likes

Nice.

I don’t get the “Works only on squared meshes in the x, z plane.”?



Also you use it for meshes you generated yourself, right?

Usually if you are using a modeling software for your models, it can handle smoothing normals.

@nehon the algorithm is for ‘terrain’/area tiles. If your tiles are 128 units apart you would use 64f as borderDistance paramter. The algorithm asumes your tiles are centered on 0/0/0 and extends on -x/xx to -64f and +64f. the same goes for -z/z. hence it only works for meshes in the x/z plane. It is not intended for arbitrary meshes.

It works by checking if the vertex is on the ‘border’/bounds and them corrects the normal by moving the x, or z component of the normal back to 0 (n the border).



Smoothing will not help you in some modelling package. On exporting two object (tiles) each tile will have its normals computed based on the object only. So on the one side a normal can look inward and on the other tile it can also look inward. they are not the same, hence a seam is visible.

Some modelling softwares do display a nice result (smoothed), but do not export the displayed result.

You can check your software by creating two bumpy tiles, with neighboring vertices, and the turn on display normals on both tiles. If you see two normals on one vertex you need a fix for seams, otherwise your modelling software is seams aware.

ok i understand better

@Sploreg maybe we could integrate this to the terrain Normals calculation?

I haven’t noticed mis-matched normals or seams on the terrain, are there some?