# Meshes zusammenfassen (LWJGL3)



## RalleYTN (24. Aug 2018)

Ein schwieriges Thema.
Ich möchte mehrere Meshes die aus 4 Daten-Sets bestehen miteinander verschmelzen.
Die vier Daten-Sets sind Vertices, Indices, Texture Coordinates und Normals.
Der Grund warum ich das machen möchte ist, dass das Spiel an dem ich arbeite sehr viel prozedual genrierten Content haben wird. Zum Beispiel wird ein Schwertgrif und eine Klinge zu einem kompletten Schwert-Mesh.
Diese Verschmelzung soll auch mit Transformationen arbeiten können.
Ungefähr so sollte die Methode am Ende aussehen:

```
public static final MeshData mergeMeshes(List<MeshData> meshes, List<Matrix4f> transformations) {
    float[] vertices;
    float[] texCoords;
    float[] normals;
    int[] indices;

    // DO STUFF

    MeshData data = new MeshData();
    data.setVertices(vertices);
    data.setIndices(indices);
    data.setNormals(indices);
    data.setTextureCoordinates(texCoords);
    return data;
}
```

Das was ich mir bisher überlegt habe ist:

Step 1:
Die Vertices und Normals aller Meshes mit der Transformation des Meshes zu multiplizieren. Die Methode zum multiplizieren sieht so aus:

```
public static final Vector3f multiply(Matrix4f matrix, float x, float y, float z) {
       
       Vector3f result = new Vector3f();
       result.x = x * matrix.m00 + y * matrix.m01 + z * matrix.m02;
       result.y = x * matrix.m10 + y * matrix.m11 + z * matrix.m12;
       result.z = x * matrix.m20 + y * matrix.m21 + z * matrix.m22;
       return result;
   }
```

Step 2:
Die Vertex-, TexCoord- und Normal-Arrays aller Meshes zusammenzuführen.
Also das heist das das Vertex-Array von Mesh 2 and das von Mesh 1 gehängt wird und so weiter.

Step 3:
Die Index-Arrays der Meshes zusammenführen nachdem die Summe der Meshes davor zum Index addiert wurde.
Also wenn Mesh 1 800 Indices hat dann müssen bei Mesh 2 natürlich alle Indices um 800 erhöht werden.

Hier gibt es jetzt jedoch das Problem.
Es kann vorkommen, dass Mesh 1 und 2 sich einen Vertex normalerweise teilen würden.
Mit meinen Schritten tun sie das aber nicht. Der Vertex wird einfach 2 Mal in den Speicher geladen.

Wie kann ich dieses Problem beheben?


----------



## RalleYTN (25. Aug 2018)

Also ich habe das jetzt ganz einfach mal so wie es ist umgesetzt, da es für Gras bereits optimal ist.
Hier ist die Methode:

```
public static final MeshData mergeLazy(List<MeshData> meshes, List<Matrix4f> transformations) {
       
       int lengthVertices = 0;
       int lengthNormals = 0;
       int lengthTexCoords = 0;
       int lengthIndices = 0;
       ArrayList<Integer> indexLengths = new ArrayList<>();
       
       for(MeshData mesh : meshes) {
           
           lengthVertices += mesh.getVertices().length;
           lengthNormals += mesh.getNormals().length;
           lengthTexCoords += mesh.getTextureCoordinates().length;
           int length = mesh.getIndices().length;
           lengthIndices += length;
           indexLengths.add(length);
       }
       
       float[] vertices = new float[lengthVertices];
       float[] texCoords = new float[lengthTexCoords];
       float[] normals = new float[lengthNormals];
       int[] indices = new int[lengthIndices];
       
       int iv = 0;
       int ivt = 0;
       int ivn = 0;
       int i = 0;
       int indexLength = 0;
       
       for(int im = 0; im < meshes.size(); im++) {
           
           MeshData mesh = meshes.get(im);
           float[] mVertices = mesh.getVertices();
           float[] mTexCoords = mesh.getTextureCoordinates();
           float[] mNormals = mesh.getNormals();
           int[] mIndices = mesh.getIndices();
           Matrix4f transformation = transformations.get(im);
           
           for(int index = 0; index < mVertices.length; index += 3) {
               
               Vector3f vertex = MatrixUtil.multiply(transformation, mVertices[index], mVertices[index + 1], mVertices[index + 2]);
               vertices[iv++] = vertex.x + transformation.m30;
               vertices[iv++] = vertex.y + transformation.m31;
               vertices[iv++] = vertex.z + transformation.m32;
               
               Vector3f normal = MatrixUtil.multiply(transformation, mNormals[index], mNormals[index + 1], mNormals[index + 2]);
               normals[ivn++] = normal.x;
               normals[ivn++] = normal.y;
               normals[ivn++] = normal.z;
           }
           
           for(int index = 0; index < mTexCoords.length; index++) {
               
               texCoords[ivt++] = mTexCoords[index];
           }
           
           for(int index = 0; index < mIndices.length; index++) {
               
               indices[i++] = indexLength + mIndices[index];
           }
           
           indexLength += indexLengths.get(im);
       }
       
       MeshData data = new MeshData();
       data.setIndices(indices);
       data.setNormals(normals);
       data.setTextureCoordinates(texCoords);
       data.setVertices(vertices);
       
       return data;
   }
```

Jedoch scheint das nicht ganz so zu funktionieren wie ich es mir erhofft habe.
Fehler 1: Bei der Transformation werden nur Rotation und Scale beachtet und nicht die Translation.
Fehler 2: Irgendwie ist bei Mesh Nummer 2 die Textur nur Teilweise vorhanden und das obwohl die Texture-Coordinates korrekt sind.

Hier ist auch einmal ein Bild wodurch besser klar wird warum diese Sachen ein Problem sind und auch der Code mit dem ich nun den entgültigen Mesh erstelle.

 


```
Material grassMaterial = new Material();
       grassMaterial.setMinBrightness(0.1F);
       grassMaterial.setColorMap(new Texture(new XImgTextureReader().read(new FileInputStream("res/textures/grass2.ximg"))));
       grassMaterial.setAffectedByLight(true);
       grassMaterial.setTransparent(true);
       grassMaterial.setUpwardsNormals(true);
       grassMaterial.setFog(fog);
       
       MeshData quad = Quad.generateMeshData(
           new Vector3f(0.0F, 1F, 0.0F),
           new Vector3f(0.0F, 0.0F, 0.0F),
           new Vector3f(1F, 0.0F, 0.0F),
           new Vector3f(1F, 1F, 0.0F)
       );
       
       StaticMesh grassMesh = new StaticMesh(MeshUtil.mergeLazy(Arrays.asList(quad, quad.copy()), Arrays.asList(
           MatrixUtil.createTransformationMatrx(
               new Vector3f(0.0F, 0.0F, 0.0F),
               new Vector3f(0.0F, 0.0F, 0.0F),
               new Vector3f(1.0F, 1.0F, 1.0F)
           ),
           MatrixUtil.createTransformationMatrx(
               new Vector3f(0F, 0.0F, -0F),
               new Vector3f(0.0F, 90.0F, 0.0F),
               new Vector3f(1.0F, 1.0F, 1.0F)
           )
       )));
       grassMesh.setCullMode(StaticMesh.CULLING_DISABLED);

       Entity grass = new Entity();
       grass.setShaderPipeline(shaderPipeline);
       grass.setMaterial(grassMaterial);
       grass.setMesh(grassMesh);
       grass.setTranslation(0, 0, 1);
```


----------



## RalleYTN (26. Aug 2018)

Nach langem rumprobieren habe ich die Antwort jetzt selbst gefunden.
Das Problem waren die Indices und die Art und Weise wie ich die Transformation mit dem Rest multipliziert habe.
Ich hätte nicht die Länge der Indices für das Offset nutzen sollen, sondern die Anzahl der Vertices / 3.
Un bei der Multiplizierung hätte ich nicht Horizontal sondern Vertikal arbeiten müssen.

Hier ist nun die funktionierende Methode:

```
public static final MeshData mergeLazy(List<MeshData> meshes, List<Matrix4f> transformations) {
       
       ArrayList<Float> vertices = new ArrayList<>();
       ArrayList<Float> texCoords = new ArrayList<>();
       ArrayList<Float> normals = new ArrayList<>();
       ArrayList<Integer> indices = new ArrayList<>();
       int offset = 0;
       int m = 0;
       
       for(MeshData mesh : meshes) {
           
           Matrix4f transformation = transformations.get(m);
           float[] mVertices = mesh.getVertices();
           float[] mNormals = mesh.getNormals();
           
           for(int index = 0; index < mesh.getVertices().length; index += 3) {
               
               Vector3f vertex = MatrixUtil.multiply(transformation, mVertices[index], mVertices[index + 1], mVertices[index + 2]);
               vertices.add(vertex.x);
               vertices.add(vertex.y);
               vertices.add(vertex.z);
               
               Vector3f normal = MatrixUtil.multiply(transformation, mNormals[index], mNormals[index + 1], mNormals[index + 2]);
               normals.add(normal.x);
               normals.add(normal.y);
               normals.add(normal.z);
           }
           
           ListUtil.addFloatArray(texCoords, mesh.getTextureCoordinates());
           int[] mIndices = mesh.getIndices();
           
           for(int index : mIndices) {
               
               indices.add(index + offset);
           }
           
           offset += mVertices.length / 3;
           m++;
       }
       
       MeshData mesh = new MeshData();
       mesh.setIndices(ListUtil.toPrimitiveIntArray(indices));
       mesh.setNormals(ListUtil.toPrimitiveFloatArray(normals));
       mesh.setTextureCoordinates(ListUtil.toPrimitiveFloatArray(texCoords));
       mesh.setVertices(ListUtil.toPrimitiveFloatArray(vertices));
       
       return mesh;
   }
```


----------

