【问题标题】:How to handle index buffer in OpenGL ES 1.1如何在 OpenGL ES 1.1 中处理索引缓冲区
【发布时间】:2014-03-11 04:26:11
【问题描述】:

我想使用 OPENGL ES 1.1 for Android 渲染从 .obj 文件加载的模型。我有顶点、顶点法线和面。当我使用 GL10.GL_POINTS 渲染模型时,模型看起来很好:

当我使用 GL10.GL_TRIANGLES 时,我得到一堆这样的形状:

这是我的绘图方法。我尝试了 glDrawArrays 和 glDrawElements 但得到了相同的结果。

public void draw(GL10 gl){
    gl.glEnable(GL10.GL_CULL_FACE);
    gl.glFrontFace(GL10.GL_CCW);
    gl.glCullFace(GL10.GL_BACK);

    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glVertexPointer(COORDS_PER_VERTEX, GL10.GL_FLOAT, BYTES_PER_VERTEX, m_vertexBuffer);

    gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
    gl.glNormalPointer(COORDS_PER_VERTEX, BYTES_PER_VERTEX, m_normalBuffer);

    gl.glColor4f(m_color[0], m_color[1], m_color[2], m_color[3]);
    gl.glScalef(0.1f, 0.1f, 0.1f);

    // gl.glDrawArrays(GL10.GL_TRIANGLES, 0, m_numNormals);
    gl.glDrawElements(GL10.GL_TRIANGLES, m_numIndices, GL10.GL_UNSIGNED_SHORT, m_indexBuffer);

    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
    gl.glDisable(GL10.GL_CULL_FACE);
}

以下是 .obj 文件中的示例行:

v 1.012781 -1.591947 1.752353
...
vn 0.495193 0.342204 0.798517
...
# same indices within pairs
f 14978//14978 14977//14977 22659//22659
...
# different indices
f 34422//34418 34375//34371 34374//34370

面部线条的有趣之处在于,有时 v//vn 对包含相同的索引,有时则不包含。此外,总共有 4 条法线少于顶点。我怀疑这是导致问题的原因。但我将如何处理呢?当我使用 glDrawElements 时,我应该传递哪些索引?

这就是我初始化缓冲区的方式:

public void setVertices(float[] coordinates, int size){
    final ByteBuffer bb = ByteBuffer.allocateDirect(size * 4);
    bb.order(ByteOrder.nativeOrder());
    m_vertexBuffer = bb.asFloatBuffer();
    m_vertexBuffer.put(coordinates, 0, size);
    m_vertexBuffer.position(0);
    m_numVertices = size / COORDS_PER_VERTEX;
}

public void setNormals(float[] coordinates, int size){
    final ByteBuffer bb = ByteBuffer.allocateDirect(size * 4);
    bb.order(ByteOrder.nativeOrder());
    m_normalBuffer = bb.asFloatBuffer();
    m_normalBuffer.put(coordinates, 0, size);
    m_normalBuffer.position(0);
    m_numNormals = size / COORDS_PER_VERTEX;
}

// array contains vertices and normals in the order read from the .obj file
// ie every even index is a vertex, every odd index is a normal
public void setIndices(int[] array, int size){
    m_numIndices = size / 2;
    final ByteBuffer bb = ByteBuffer.allocateDirect(m_numIndices * 4);
    bb.order(ByteOrder.nativeOrder());
    m_indexBuffer = bb.asIntBuffer();
    for(int i = 0; i < size; i+=2)
        m_indexBuffer.put(array[i]);
    m_indexBuffer.position(0);
}

您能否给我一个提示如何初始化和使用索引缓冲区?

编辑:这是模型:bunny.obj

【问题讨论】:

  • 每次制作 obj 加载器时我设法忘记的一件事是面从 1 开始索引,而不是 0。最好的办法是获取一个仅用于立方体或四边形的 OBJ 来测试您的加载器.

标签: android opengl-es


【解决方案1】:

也许这会帮助你我用它来导入一个 .obj 文件,它与纹理和所有东西一起工作,你必须将它与你的项目相关的东西分开,它与所有这些其他类相关,比如实例GLGame 和 GLGraphics 用于文件输入和获取 GL10 实例,祝你好运,希望对你有帮助

对象加载器

public class ObjLoader {
    public static Vertices3 load(GLGame game, String file) {
        InputStream in = null;
        try {
            in = game.getFileIO().readAsset(file);
            List<String> lines = readLines(in);

            float[] vertices = new float[lines.size() * 3];
            float[] normals = new float[lines.size() * 3];
            float[] uv = new float[lines.size() * 2];

            int numVertices = 0;
            int numNormals = 0;
            int numUV = 0;
            int numFaces = 0;

            int[] facesVerts = new int[lines.size() * 3];
            int[] facesNormals = new int[lines.size() * 3];
            int[] facesUV = new int[lines.size() * 3];
            int vertexIndex = 0;
            int normalIndex = 0;
            int uvIndex = 0;
            int faceIndex = 0;

            for (int i = 0; i < lines.size(); i++) {
                String line = lines.get(i);
                if (line.startsWith("v ")) {
                    String[] tokens = line.split("[ ]+");
                    vertices[vertexIndex] = Float.parseFloat(tokens[1]);
                    vertices[vertexIndex + 1] = Float.parseFloat(tokens[2]);
                    vertices[vertexIndex + 2] = Float.parseFloat(tokens[3]);
                    vertexIndex += 3;
                    numVertices++;
                    continue;
                }

                if (line.startsWith("vn ")) {
                    String[] tokens = line.split("[ ]+");
                    normals[normalIndex] = Float.parseFloat(tokens[1]);
                    normals[normalIndex + 1] = Float.parseFloat(tokens[2]);
                    normals[normalIndex + 2] = Float.parseFloat(tokens[3]);
                    normalIndex += 3;
                    numNormals++;
                    continue;
                }

                if (line.startsWith("vt")) {
                    String[] tokens = line.split("[ ]+");
                    uv[uvIndex] = Float.parseFloat(tokens[1]);
                    uv[uvIndex + 1] = Float.parseFloat(tokens[2]);
                    uvIndex += 2;
                    numUV++;
                    continue;
                }

                if (line.startsWith("f ")) {
                    String[] tokens = line.split("[ ]+");

                    String[] parts = tokens[1].split("/");
                    facesVerts[faceIndex] = getIndex(parts[0], numVertices);
                    if (parts.length > 2)
                        facesNormals[faceIndex] = getIndex(parts[2], numNormals);
                    if (parts.length > 1)
                        facesUV[faceIndex] = getIndex(parts[1], numUV);
                    faceIndex++;

                    parts = tokens[2].split("/");
                    facesVerts[faceIndex] = getIndex(parts[0], numVertices);
                    if (parts.length > 2)
                        facesNormals[faceIndex] = getIndex(parts[2], numNormals);
                    if (parts.length > 1)
                        facesUV[faceIndex] = getIndex(parts[1], numUV);
                    faceIndex++;

                    parts = tokens[3].split("/");
                    facesVerts[faceIndex] = getIndex(parts[0], numVertices);
                    if (parts.length > 2)
                        facesNormals[faceIndex] = getIndex(parts[2], numNormals);
                    if (parts.length > 1)
                        facesUV[faceIndex] = getIndex(parts[1], numUV);
                    faceIndex++;
                    numFaces++;
                    continue;
                }
            }

            float[] verts = new float[(numFaces * 3)
                    * (3 + (numNormals > 0 ? 3 : 0) + (numUV > 0 ? 2 : 0))];

            for (int i = 0, vi = 0; i < numFaces * 3; i++) {
                int vertexIdx = facesVerts[i] * 3;
                verts[vi++] = vertices[vertexIdx];
                verts[vi++] = vertices[vertexIdx + 1];
                verts[vi++] = vertices[vertexIdx + 2];

                if (numUV > 0) {
                    int uvIdx = facesUV[i] * 2;
                    verts[vi++] = uv[uvIdx];
                    verts[vi++] = 1 - uv[uvIdx + 1];
                }

                if (numNormals > 0) {
                    int normalIdx = facesNormals[i] * 3;
                    verts[vi++] = normals[normalIdx];
                    verts[vi++] = normals[normalIdx + 1];
                    verts[vi++] = normals[normalIdx + 2];
                }
            }

            Vertices3 model = new Vertices3(game.getGLGraphics(), numFaces * 3,
                    0, false, numUV > 0, numNormals > 0);
            model.setVertices(verts, 0, verts.length);
            return model;
        } catch (Exception ex) {
            throw new RuntimeException("couldn't load '" + file + "'", ex);
        } finally {
            if (in != null)
                try {
                    in.close();
                } catch (Exception ex) {

                }
        }
    }

    static int getIndex(String index, int size) {
        int idx = Integer.parseInt(index);
        if (idx < 0)
            return size + idx;
        else
            return idx - 1;
    }

    static List<String> readLines(InputStream in) throws IOException {
        List<String> lines = new ArrayList<String>();

        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        String line = null;
        while ((line = reader.readLine()) != null)
            lines.add(line);
        return lines;
    }
}

顶点3

public class Vertices3 {
    final GLGraphics glGraphics;
    final boolean hasColor;
    final boolean hasTexCoords;
    final boolean hasNormals;
    final int vertexSize;
    final IntBuffer vertices;
    final int[] tmpBuffer;
    final ShortBuffer indices;

    public Vertices3(GLGraphics glGraphics, int maxVertices, int maxIndices,
            boolean hasColor, boolean hasTexCoords, boolean hasNormals) {
        this.glGraphics = glGraphics;
        this.hasColor = hasColor;
        this.hasTexCoords = hasTexCoords;
        this.hasNormals = hasNormals;
        this.vertexSize = (3 + (hasColor ? 4 : 0) + (hasTexCoords ? 2 : 0) + (hasNormals ? 3
                : 0)) * 4;
        this.tmpBuffer = new int[maxVertices * vertexSize / 4];

        ByteBuffer buffer = ByteBuffer.allocateDirect(maxVertices * vertexSize);
        buffer.order(ByteOrder.nativeOrder());
        vertices = buffer.asIntBuffer();

        if (maxIndices > 0) {
            buffer = ByteBuffer.allocateDirect(maxIndices * Short.SIZE / 8);
            buffer.order(ByteOrder.nativeOrder());
            indices = buffer.asShortBuffer();
        } else {
            indices = null;
        }
    }

    public void setVertices(float[] vertices, int offset, int length) {
        this.vertices.clear();
        int len = offset + length;
        for (int i = offset, j = 0; i < len; i++, j++)
            tmpBuffer[j] = Float.floatToRawIntBits(vertices[i]);
        this.vertices.put(tmpBuffer, 0, length);
        this.vertices.flip();
    }

    public void setIndices(short[] indices, int offset, int length) {
        this.indices.clear();
        this.indices.put(indices, offset, length);
        this.indices.flip();
    }

    public void bind() {
        GL10 gl = glGraphics.getGL();

        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        vertices.position(0);
        gl.glVertexPointer(3, GL10.GL_FLOAT, vertexSize, vertices);

        if (hasColor) {
            gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
            vertices.position(3);
            gl.glColorPointer(4, GL10.GL_FLOAT, vertexSize, vertices);
        }

        if (hasTexCoords) {
            gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
            vertices.position(hasColor ? 7 : 3);
            gl.glTexCoordPointer(2, GL10.GL_FLOAT, vertexSize, vertices);
        }

        if (hasNormals) {
            gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
            int offset = 3;
            if (hasColor)
                offset += 4;
            if (hasTexCoords)
                offset += 2;
            vertices.position(offset);
            gl.glNormalPointer(GL10.GL_FLOAT, vertexSize, vertices);
        }
    }

    public void draw(int primitiveType, int offset, int numVertices) {
        GL10 gl = glGraphics.getGL();

        if (indices != null) {
            indices.position(offset);
            gl.glDrawElements(primitiveType, numVertices,
                    GL10.GL_UNSIGNED_SHORT, indices);
        } else {
            gl.glDrawArrays(primitiveType, offset, numVertices);
        }
    }

    public void unbind() {
        GL10 gl = glGraphics.getGL();
        if (hasTexCoords)
            gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

        if (hasColor)
            gl.glDisableClientState(GL10.GL_COLOR_ARRAY);

        if (hasNormals)
            gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
    }

    public int getNumIndices() {
        return indices.limit();
    }

    public int getNumVertices() {
        return vertices.limit() / (vertexSize / 4);
    }
}

【讨论】:

  • 感谢您发布代码!它为我澄清了很多事情。现在我明白 NormalPointer 和 VertexPointer 都采用相同的缓冲区但具有不同的索引。然后使用步幅将每个指针推进正确的偏移量。但是仍然存在一个问题:正如我所写,我的模型的法线比位置少。 (但是,该模型仍然是正确的,因为我将它与使用 Desktop Java 和 lwjgl 渲染模型的完整教程一起复制。它已正确加载在那里。)您的代码可能也可以处理这种情况。我会在检查后立即报告。
  • 慢慢地,碎片拼凑在一起:) 我在你的加载方法中看到你构造了一个大的顶点数组'verts',你把obj文件中的所有数据按索引排序。从那时起,您再也不会使用索引了。我缺少最后一条信息:调用 Vertices3.draw() 时,您为 offset 和 numVertices 传递了哪些值?
  • 还有一个与我之前的评论相关的问题。如果我理解正确,您在 Vertex3 类中提供了 setIndices 方法,但从未调用它(至少在您提供的 load 方法中没有)。因此,在每次调用 Vertex3.draw() 时,indices==null,因此您总是调用 glDrawArrays()。你这样称呼它:myVertex3.draw(GL10.GL_TRIANGLES, 0, numVertices)?
  • 是的,首先你绑定纹理,然后使用 Vertices3.bind() 绑定模型,或者你知道如何绑定纹理,我可以为它编写代码,但是,在你完成之后然后你的矩阵改变与推或任何然后绘制 Vertices3.draw(GL10.GL_TRIANGLES, 0,shipModel.getNumVertices());我就是这样做的,它也适用于非常复杂的模型
  • 我认为我什至没有使用过索引方法,但如果你愿意的话,它们是可以乱用的
猜你喜欢
  • 1970-01-01
  • 2012-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多