Android OBJ加载程序、纹理绑定和纹理缓冲区

Android OBJ加载程序、纹理绑定和纹理缓冲区,android,opengl-es,3d,Android,Opengl Es,3d,我目前正在Android上开发一个.obj文件加载器。我已经完成了基础工作,并且使用OpenGl正确绘制了3d网格。不幸的是,我在绑定纹理时遇到了问题。让我详细解释一下: .obj文件具有以下结构: v -0.751804 0.447968 -1.430558 v -0.751802 2.392585 -1.428428 ... etc list with all the vertices ... vt 0.033607 0.718905 vt 0.033607 0.718615 ... et

我目前正在Android上开发一个.obj文件加载器。我已经完成了基础工作,并且使用OpenGl正确绘制了3d网格。不幸的是,我在绑定纹理时遇到了问题。让我详细解释一下:

.obj文件具有以下结构:

v -0.751804 0.447968 -1.430558
v -0.751802 2.392585 -1.428428
... etc list with all the vertices ...

vt 0.033607 0.718905
vt 0.033607 0.718615
... etc list with all the texture coordinates ...

f 237/1 236/2 253/3 252/4
f 236/2 235/5 254/6 253/3
... etc list with all the faces ...
f行标识存储适当顶点和纹理坐标的索引,如

f vertex_index/texture_coord_index
所以我的节目

  • 解析顶点并将其存储在
    向量中
  • 解析纹理坐标并将其存储在
    向量中
  • 最后解析面并将每个顶点索引存储在
    向量中
    和每个纹理坐标索引存储在
    向量中
  • 完成所有这些代码后,我将创建适当的缓冲区:

    public void buildVertexBuffer(){
        ByteBuffer vBuf = ByteBuffer.allocateDirect(vertices.size() * 4);
        vBuf.order(ByteOrder.nativeOrder());
        vertexBuffer = vBuf.asFloatBuffer();
        vertexBuffer.put(toFloatArray(vertices));
        vertexBuffer.position(0);
    }
    
    其中
    顶点
    是存储浮动顶点的向量

    public void buildFaceBuffer(){
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(faces.size() * 2);
        byteBuffer.order(ByteOrder.nativeOrder());
        faceBuffer = byteBuffer.asShortBuffer();
        faceBuffer.put(toShortArray(faces));
        faceBuffer.position(0);
    }
    
    其中
    faces
    是存储索引和

    public void buildTextureBuffer(Vector<Float> textures){
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(texturePointers.size() * 4 * 2);
        byteBuffer.order(ByteOrder.nativeOrder());
        textureBuffer = byteBuffer.asFloatBuffer();
    
        for(int i=0; i<texturePointers.size(); i++){
            float u = textures.get(texturePointers.get(i) * 2);
            float v = textures.get(texturePointers.get(i) * 2 + 1);
    
            textureBuffer.put(u);
            textureBuffer.put(v);
        }
        textureBuffer.position(0);  
    }
    
    最后,我的网格的
    draw()
    方法如下所示

    public void draw(GL10 gl){
        if(bindedTextures != null){
            gl.glBindTexture(GL10.GL_TEXTURE_2D, bindedTextures[0]);
            gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
            gl.glFrontFace(GL10.GL_CW);
        }
    
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
    
        for(int i=0; i<parts.size(); i++){
            ModelPart modelPart = parts.get(i);
            Material material = modelPart.getMaterial();
    
            if(material != null){
                FloatBuffer a = material.getAmbientColorBuffer();
                FloatBuffer d = material.getDiffuseColorBuffer();
                FloatBuffer s = material.getSpecularColorBuffer();
                gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, a);
                gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, s);
                gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, d);
            }
    
            gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, modelPart.getTextureBuffer()); // returns the texture buffer created with the buildTextureBuffer() method
            gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
            gl.glNormalPointer(GL10.GL_FLOAT, 0, modelPart.getNormalBuffer());
            gl.glDrawElements(GL10.GL_TRIANGLES, modelPart.getFacesSize(), GL10.GL_UNSIGNED_SHORT, modelPart.getFaceBuffer());
            //gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
            //gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
            gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
            gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        }
    }
    
    公共作废提取(GL10 gl){
    if(bindedTextures!=null){
    gl.glBindTexture(GL10.gl_TEXTURE_2D,bindedtexture[0]);
    gl.glEnableClientState(GL10.gl_纹理_坐标_数组);
    gl.glFrontFace(GL10.GLU CW);
    }
    gl.glEnableClientState(GL10.gl_顶点数组);
    gl.glVertexPointer(3,GL10.gl_FLOAT,0,vertexBuffer);
    
    对于(int i=0;i所以,在OpenGL中,顶点是描述模型上特定点的任何信息组合。您使用的是旧的固定管道,因此顶点是位置、一些纹理坐标、法线和颜色的一个或多个

    在OBJ中,a
    vt
    只是一个位置。映射到OpenGL顶点概念的东西是在a
    f
    之后给出的每个位置+纹理坐标对的唯一组合

    你需要一个映射,如果<代码> f>代码> 56/92,那么你可以查找56/92,并发现你认为它是,比如说顶点23,并且已经把合适的数组传送到OpenGL,使得在槽23中的位置值是Obj[1]给出的第五十六个东西,作为<代码> v>代码>,它给出的第九十二个东西是<代码> vt<代码> >

    换句话说,OBJ文件具有OpenGL所没有的额外间接级别


    在我看来,您并没有解决这个差异。一种常见的方法是使用从v/vt对到输出索引的
    HashMap
    ,在解析
    f

    时根据需要构建输出数组。如果没有对代码进行适当的全面检查,您似乎没有考虑OBJ坐标,将原点放在t左上角,OpenGL将其放在左下角。快速切换到
    float v=1.0f-textures.get(texturePainters.get(i)*2+1)
    修复任何问题?@Tommy感谢您的回答。不,这个更改似乎并不能解决我的问题。我不能只是粘贴所有代码,但我可以将其存储库提供给您Github如果我理解正确,此HashMap值必须指向存储所有内容(顶点、纹理坐标和法线)的唯一数组。我是OpenGl的新手。这个数组是如何构造的?哦,不,它可以是几个不同的数组,一个用于位置,一个用于纹理坐标,等等,只要索引相同。所以位置54有纹理坐标54,等等。你经常会看到它构建为单个数组,因为这有助于缓存,但这是可以实现的一旦这个部分开始工作,我将作为下一步。好的,我开始感觉到这里的工作方式。所以我必须利用HashMap创建这3个数组,然后,
    faceBuffer
    应该存储特定HashMap的值……下面是我对类似问题的一些回答,这些问题解释了更详细地讲,@Tommy在这里谈论的是:,。我认为
    HashMap
    方法是最自然的,但从技术上来说,你不必使用它。但是,是的,你要告诉OpenGL绘制一个顶点为8、9和10的三角形,然后OpenGL将检查你的顶点缓冲区、纹理缓冲区和法线缓冲区中的索引。所以顶点缓冲区中索引8处的对象最好是与纹理和法线缓冲区中索引8处的对象一起使用的位置。OBJ不会这样排列其数据,但使用
    HashMap
    是重新排列OBJ提供的内容的简单方法。
    public void draw(GL10 gl){
        if(bindedTextures != null){
            gl.glBindTexture(GL10.GL_TEXTURE_2D, bindedTextures[0]);
            gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
            gl.glFrontFace(GL10.GL_CW);
        }
    
        gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
    
        for(int i=0; i<parts.size(); i++){
            ModelPart modelPart = parts.get(i);
            Material material = modelPart.getMaterial();
    
            if(material != null){
                FloatBuffer a = material.getAmbientColorBuffer();
                FloatBuffer d = material.getDiffuseColorBuffer();
                FloatBuffer s = material.getSpecularColorBuffer();
                gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_AMBIENT, a);
                gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_SPECULAR, s);
                gl.glMaterialfv(GL10.GL_FRONT_AND_BACK, GL10.GL_DIFFUSE, d);
            }
    
            gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, modelPart.getTextureBuffer()); // returns the texture buffer created with the buildTextureBuffer() method
            gl.glEnableClientState(GL10.GL_NORMAL_ARRAY);
            gl.glNormalPointer(GL10.GL_FLOAT, 0, modelPart.getNormalBuffer());
            gl.glDrawElements(GL10.GL_TRIANGLES, modelPart.getFacesSize(), GL10.GL_UNSIGNED_SHORT, modelPart.getFaceBuffer());
            //gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
            //gl.glDisableClientState(GL10.GL_COLOR_ARRAY);
            gl.glDisableClientState(GL10.GL_NORMAL_ARRAY);
            gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
        }
    }