在OpenGL中将具有转换矩阵的多个网格合并为单个网格

时间:2018-08-25 15:54:35

标签: java opengl 3d lwjgl matrix-multiplication

我尝试将具有转换矩阵的多个网格合并为一个网格。 每个网格具有4个数据集。

  1. 顶点
  2. 指数
  3. 纹理坐标
  4. 普通人

我试图做到的方式应该是懒惰的,并且不会花费那么多的CPU。 这是一个三步过程。

  1. 将每个顶点和法线与变换矩阵相乘。
  2. 将每个网格的顶点,纹理坐标和法线合并为3个大数组。
  3. 将每个网格的索引合并到单个数组中,但将先前网格的总和用作偏移量。例如:如果网格1具有800个索引,则必须将800添加到网格2的所有索引中。

此方法有两个大问题。

  1. 不共享重复的顶点
  2. 由于裁剪而看不见的部分不会被删除

但是可以,因为这应该是一种懒惰的方法,CPU使用率不高。为草和灌木丛创建网格已经是最佳选择。

我已经尝试过这种方法的实现,如下所示:

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;
            vertices[iv++] = vertex.y;
            vertices[iv++] = vertex.z;

            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;
}

最后,我实际上只有一个网格,并且变换的乘法也起作用....用于旋转和缩放,但是问题来了。

与转换相乘不适用于翻译。 我的将矩阵与向量相乘的方法如下:

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;
}

第二个问题是第二个网格的纹理有些偏离。

这是一张图片: Error

您可以看到第二个网格仅具有实际纹理的1/4。

我用来生成该网格的代码如下:

    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), 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);

我现在的问题是:我做错了什么?为什么纹理这么怪异,为什么转换后的乘法不能用于翻译?

如果您需要更多代码,请在这里找到带有Eclipse项目的GitHub存储库:https://github.com/RalleYTN/Heroica-Fabulis

1 个答案:

答案 0 :(得分:0)

由于@ Rabbid76,我离答案越来越近了,现在终于找到了问题所在。 平移不起作用的第一个问题是通过垂直而不是水平地乘以变换来解决的。再次感谢@ Rabidd76。

纹理之所以怪异的原因是因为我错误地合并了索引。我不应该将网格中所有索引的总和作为顶点的总和。

这是现在的工作方法:

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;
}