簡體   English   中英

OpenGL ES紋理無法正確渲染

[英]OpenGL ES Texture not rendering correctly

我正在使用openglES 3.0開發一個Android應用,我想創建一個obj loader系統並顯示帶有其紋理的3D模型。 我的代碼正確顯示了沒有紋理的3D網格。 如果嘗試添加紋理,它將顯示該紋理,並且該紋理的某些部分將是空三角形。

范例:

我的網狀紋理

我的網狀obj文件

我的紋理png文件

我找不到問題所在。

我的片段着色器

precision mediump float;
uniform vec4 vColor;
uniform sampler2D uTexture;
varying vec2 oTexCoordinate;

void main() {
    gl_FragColor = texture2D(uTexture, oTexCoordinate);
    //gl_FragColor = vec4(1, 0.5, 0, 1.0);

}

我的頂點着色器

attribute vec4 position;
uniform mat4 matrix;

attribute vec2 vTexCoordinate;
varying vec2 oTexCoordinate;


void main() {
    oTexCoordinate = vTexCoordinate;
    gl_Position = matrix * position;

}

提前致謝。


更新:

謝謝。

我已經更改了代碼以適合您的想法,我激活了臉部剔除並為法線添加了緩沖區,我暫時不使用它。 我把我的新代碼放在下面。 但是問題並未完全解決,請參見下圖。

我想我需要將常規信息傳遞給着色器,但是我不確定如何正確執行此信息,或者不確定這是否是解決方案。

public class MeshLoader {

    private int program;

    private List<String> facesVertexList;
    private List<String> facesTextureList;
    private List<String> facesNormalList;

    private List<String> verticesList;
    private List<String> textureList;
    private List<String> normalList;

    private FloatBuffer verticesBuffer;
    private FloatBuffer verticesBufferTemp;

    private FloatBuffer facesVertexBuffer;
    private FloatBuffer facesTextureBuffer;
    private FloatBuffer facesNormalBuffer;

    private FloatBuffer textureBuffer;
    private FloatBuffer textureBufferTemp;

    private FloatBuffer normalBuffer;
    private FloatBuffer normalBufferTemp;

    private Context contextMeshLoader;
    final int[] textureHandle = new int[1];


    public MeshLoader(Context context) {
        contextMeshLoader = context;
        textureList = new LinkedList<>();
        verticesList = new LinkedList<>();
        normalList = new LinkedList<>();
        facesVertexList = new LinkedList<>();
        facesTextureList = new LinkedList<>();
        facesNormalList = new LinkedList<>();

        openObjFile(0);

        String vertexShaderCode = "";
        try{
            InputStream vertexShaderStream = context.getResources().openRawResource(R.raw.vertex_shader);
            vertexShaderCode = IOUtils.toString(vertexShaderStream, Charset.defaultCharset());
            vertexShaderStream.close();
        }
        catch (Exception e){
            Log.e("MeshReaderActivity", "Error reading vertex shader", e);
        }

        String fragmentShaderCode = "";
        try{
            InputStream fragmentShaderStream = context.getResources().openRawResource(R.raw.fragment_shader);
            fragmentShaderCode = IOUtils.toString(fragmentShaderStream, Charset.defaultCharset());
            fragmentShaderStream.close();
        }
        catch(Exception e){
            Log.e("MeshReaderActivity", "Error reading fragment shader", e);
        }

        int vertexShader = GLES30.glCreateShader(GLES30.GL_VERTEX_SHADER);
        GLES30.glShaderSource(vertexShader, vertexShaderCode);

        int fragmentShader = GLES30.glCreateShader(GLES30.GL_FRAGMENT_SHADER);
        GLES30.glShaderSource(fragmentShader, fragmentShaderCode);


        GLES30.glCompileShader(vertexShader);
        GLES30.glCompileShader(fragmentShader);


        program = GLES30.glCreateProgram();
        GLES30.glAttachShader(program, vertexShader);
        GLES30.glAttachShader(program, fragmentShader);
        GLES30.glLinkProgram(program);
        GLES30.glUseProgram(program);

    }

    public void openObjFile(int value)
    {
        InputStream is;
        value = 0;
        if(value == 0)
           is  = contextMeshLoader.getResources().openRawResource(R.raw.objface);
        else
            is = contextMeshLoader.getResources().openRawResource(R.raw.objship);

        if(verticesBufferTemp != null)
            verticesBufferTemp.clear();
        if(facesVertexBuffer != null)
            facesVertexBuffer.clear();
        if(textureBuffer != null)
            textureBuffer.clear();
        if(verticesList != null)
            verticesList.clear();
        if(facesVertexList != null)
            facesVertexList.clear();
        if(textureList != null)
            textureList.clear();

        try{
            byte[] buffer = new byte[is.available()];
            is.read(buffer);
            String data = new String(buffer);

            parseData(data);



            ByteBuffer buffer2 = ByteBuffer.allocateDirect(facesVertexList.size() * 3 * 4);
            buffer2.order(ByteOrder.nativeOrder());
            facesVertexBuffer = buffer2.asFloatBuffer();

            ByteBuffer buffer3 = ByteBuffer.allocateDirect(facesTextureList.size() * 3 * 4);
            buffer3.order(ByteOrder.nativeOrder());
            facesTextureBuffer = buffer3.asFloatBuffer();

            ByteBuffer buffer6 = ByteBuffer.allocateDirect(facesTextureList.size() * 3 * 4);
            buffer6.order(ByteOrder.nativeOrder());
            facesNormalBuffer = buffer6.asFloatBuffer();


            for(String face: facesVertexList) {
                String vertexIndices[] = face.split("\\s+");
                float vertex1 = Float.parseFloat(vertexIndices[1]);
                float vertex2 = Float.parseFloat(vertexIndices[2]);
                float vertex3 = Float.parseFloat(vertexIndices[3]);
                facesVertexBuffer.put((vertex1 - 1));
                facesVertexBuffer.put((vertex2 - 1));
                facesVertexBuffer.put((vertex3 - 1));
            }
            facesVertexBuffer.position(0);


            for(String texture: facesTextureList){
                String textureIndice[] = texture.split("\\s+");
                float texture1 = Float.parseFloat(textureIndice[1]);
                float texture2 = Float.parseFloat(textureIndice[2]);
                float texture3 = Float.parseFloat(textureIndice[3]);
                facesTextureBuffer.put((texture1 - 1));
                facesTextureBuffer.put((texture2 - 1));
                facesTextureBuffer.put((texture3 - 1));
            }
            facesTextureBuffer.position(0);

            for(String normal: facesNormalList) {
                String normalIndice[] = normal.split("\\s+");
                float normal1 = Float.parseFloat(normalIndice[1]);
                float normal2 = Float.parseFloat(normalIndice[2]);
                float normal3 = Float.parseFloat(normalIndice[3]);
                facesNormalBuffer.put((normal1 - 1));
                facesNormalBuffer.put((normal2 - 1));
                facesNormalBuffer.put((normal3 - 1));
            }
            facesNormalBuffer.position(0);


            ByteBuffer buffer1 = ByteBuffer.allocateDirect(verticesList.size() * 3 * 4);
            buffer1.order(ByteOrder.nativeOrder());
            verticesBufferTemp = buffer1.asFloatBuffer();

            ByteBuffer buffer5 = ByteBuffer.allocateDirect(textureList.size() * 2 * 4);
            buffer5.order(ByteOrder.nativeOrder());
            textureBufferTemp = buffer5.asFloatBuffer();

            ByteBuffer buffer7 = ByteBuffer.allocateDirect(textureList.size() * 3 * 4);
            buffer7.order(ByteOrder.nativeOrder());
            normalBufferTemp = buffer7.asFloatBuffer();

            for(String vertex: verticesList) {
                String coords[] = vertex.split("\\s+");
                float x = Float.parseFloat(coords[1]);
                float y = Float.parseFloat(coords[2]);
                float z = Float.parseFloat(coords[3]);
                verticesBufferTemp.put(x);
                verticesBufferTemp.put(y);
                verticesBufferTemp.put(z);
            }
            verticesBufferTemp.position(0);

            for (String texture:textureList)
            {
                String textureIndices[] = texture.split("\\s+");
                float texture1 = Float.parseFloat(textureIndices[1]);
                float texture2 = Float.parseFloat(textureIndices[2]);
                textureBufferTemp.put(texture1);
                textureBufferTemp.put(texture2);
            }
            textureBufferTemp.position(0);

            for (String normal:normalList)
            {
                String normalIndices[] = normal.split("\\s+");
                float normal1 = Float.parseFloat(normalIndices[1]);
                float normal2 = Float.parseFloat(normalIndices[2]);
                normalBufferTemp.put(normal1);
                normalBufferTemp.put(normal2);
            }
            normalBufferTemp.position(0);


            System.out.println("size remaining " + facesVertexBuffer.remaining());

            ByteBuffer bufferV = ByteBuffer.allocateDirect(facesVertexBuffer.remaining() * 3 * 4);
            bufferV.order(ByteOrder.nativeOrder());
            verticesBuffer = bufferV.asFloatBuffer();

            ByteBuffer bufferT = ByteBuffer.allocateDirect(facesVertexBuffer.remaining() * 2 * 4);
            bufferT.order(ByteOrder.nativeOrder());
            textureBuffer = bufferT.asFloatBuffer();

            ByteBuffer bufferN = ByteBuffer.allocateDirect(facesVertexBuffer.remaining() * 3 * 4);
            bufferN.order(ByteOrder.nativeOrder());
            normalBuffer = bufferN.asFloatBuffer();

            int size = facesVertexBuffer.remaining();

            for(int i = 0; i < size;i++)
            {
                int faceVertex = Math.round(facesVertexBuffer.get(i)) ;
                int faceTexture = Math.round(facesTextureBuffer.get(i));
                int faceNormal = Math.round(facesNormalBuffer.get(i));

                float x = verticesBufferTemp.get((faceVertex)*3);
                float y = verticesBufferTemp.get(((faceVertex)*3)+1);
                float z = verticesBufferTemp.get(((faceVertex)*3)+2);
                verticesBuffer.put( i*3,   x);
                verticesBuffer.put( (i*3)+1, y);
                verticesBuffer.put( (i*3)+2, z);

                float u = textureBufferTemp.get((faceTexture)*2);
                float v = -textureBufferTemp.get(((faceTexture)*2)+1);
                textureBuffer.put( i*2,   u);
                textureBuffer.put( (i*2)+1, v);

                float xn = normalBufferTemp.get((faceNormal*3));
                float yn = normalBufferTemp.get((faceNormal*3)+1);
                float zn = normalBufferTemp.get((faceNormal*3)+2);
                normalBuffer.put(i*3,xn);
                normalBuffer.put((i*3)+1,yn);
                normalBuffer.put((i*3)+2,zn);

            }
            verticesBuffer.position(0);
            textureBuffer.position(0);
            normalBuffer.position(0);

            is.close();
            loadTexture();
        }
        catch (Exception e) {
            Log.e("MeshReaderActivity", "Error reading objfile", e);
        }
    }

    public void parseData(String dataToParse)
    {
        Log.i("parse data method", "parse data method");
        String[] data = dataToParse.split("\n");
        for (int i = 0;i < data.length;i++)
        {
            String line = data[i];
            if(line.startsWith("v "))
            {
                // Add vertex line to list of vertices
                verticesList.add(line);
            }
            else if(line.startsWith("vt "))
            {
                textureList.add(line);
            }
            else if(line.startsWith("vn "))
            {
                normalList.add(line);
            }
            else if(line.startsWith("f "))
            {
                // Add face line to faces list
                triangulate(line);
            }
        }

    }

    public void triangulate(String lineToTriangulate)
    {
        String lineSplit[] = lineToTriangulate.split("\\s+");
        if(lineSplit.length > 4)
        {
            String line1="";
            String line2="";
            if (lineToTriangulate.contains("/"))
            {
                line1 = lineSplit[0] + " " + lineSplit[1].split("/")[0] + " " + lineSplit[2].split("/")[0] + " " + lineSplit[3].split("/")[0];
                line2 = lineSplit[0] + " " + lineSplit[1].split("/")[0] + " " + lineSplit[2].split("/")[0] + " " + lineSplit[4].split("/")[0];
            }
            else
            {
                line1 = lineSplit[0] + " " + lineSplit[1] + " " + lineSplit[2] + " " + lineSplit[3];
                line2 = lineSplit[0] + " " + lineSplit[1] + " " + lineSplit[2] + " " + lineSplit[4];
            }
            facesVertexList.add(line1);
            facesVertexList.add(line2);
        }
        else
        {
            if(lineToTriangulate.contains("/"))
            {
                String[] splitElement1 = lineSplit[1].split("/");
                String[] splitElement2 = lineSplit[2].split("/");
                String[] splitElement3 = lineSplit[3].split("/");
                String line = lineSplit[0] + " " + splitElement1[0] + " " + splitElement2[0] + " " + splitElement3[0];
                facesVertexList.add(line);
                line = lineSplit[0] + " " + splitElement1[1] + " " + splitElement2[1] + " " + splitElement3[1];
                facesTextureList.add(line);
                line =  lineSplit[0] + " " + splitElement1[2] + " " + splitElement2[2] + " " + splitElement3[2];
                facesNormalList.add(line);

            }
            else
            {
                facesVertexList.add(lineToTriangulate);
            }
        }
    }


    public void draw(float scratch[],float zoom){


        int position = GLES30.glGetAttribLocation(program, "position");
        GLES30.glEnableVertexAttribArray(position);
        GLES30.glVertexAttribPointer(position, 3, GLES30.GL_FLOAT, false, 3 * 4, verticesBuffer);


        int mTextureUniformHandle = GLES30.glGetUniformLocation(program, "uTexture");
        int mTextureCoordinateHandle = GLES30.glGetAttribLocation(program, "vTexCoordinate");

        GLES30.glActiveTexture(GLES30.GL_TEXTURE0);
        GLES30.glUniform1i(mTextureUniformHandle, 0);
        GLES30.glEnableVertexAttribArray(mTextureCoordinateHandle);
        GLES30.glVertexAttribPointer(mTextureCoordinateHandle, 2, GLES30.GL_FLOAT, false, 2*4, textureBuffer);

        int normalHandle = GLES30.glGetAttribLocation(program,"normal");
        GLES30.glEnableVertexAttribArray(normalHandle);
        GLES30.glVertexAttribPointer(normalHandle,3,GLES30.GL_FLOAT,false,3*4,normalBuffer);

        float[] projectionMatrix = new float[16];
        float[] viewMatrix = new float[16];
        float[] productMatrix = new float[16];

        Matrix.frustumM(projectionMatrix, 0,
                -1, 1,
                -1, 1,
                1, 11);
        Matrix.setLookAtM(viewMatrix, 0,
                0, 0, zoom,
                0, 0, 0,
                0, 1, 0);
        Matrix.multiplyMM(productMatrix, 0,
                projectionMatrix, 0,
                viewMatrix, 0);

        float[] finalMatrix = new float[16];

        Matrix.multiplyMM(finalMatrix, 0,
                productMatrix, 0,
                scratch, 0);

        Matrix.rotateM(finalMatrix, 0, 180, 0.0f, 1.0f, 0.0f);


        int matrix = GLES30.glGetUniformLocation(program, "matrix");
        GLES30.glUniform1i(matrix,0);
        //GLES30.glUniformMatrix4fv(matrix, 1, false, productMatrix, 0);
        GLES30.glUniformMatrix4fv(matrix, 1, false, finalMatrix, 0);


        int size = facesVertexBuffer.remaining();

        GLES30.glEnable(GLES30.GL_CULL_FACE);
        GLES30.glCullFace(GLES30.GL_BACK);


        GLES30.glDrawArrays(GLES30.GL_TRIANGLES,0,size);

        GLES30.glDisableVertexAttribArray(position);
        GLES30.glDisableVertexAttribArray(mTextureCoordinateHandle);
    }

    public void loadTexture()
    {

        GLES30.glGenTextures(1, textureHandle,0);

        if (textureHandle[0] == 0)
        {
            throw new RuntimeException("Error generating texture name.");
        }


        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inScaled = true;    // No pre-scaling

        Bitmap bitmap = BitmapFactory.decodeResource(contextMeshLoader.getResources(), R.raw.pngface, options);
        GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureHandle[0]);
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR);
        GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR);


        GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, bitmap, 0);

        bitmap.recycle();
    }

}

再次感謝。


更新資料

對於浮動,這是復制/粘貼的錯誤。 對於我的顯示問題,我找到了解決方案。 我只需要添加onDrawFrame方法。

GLES30.glEnable(GLES30.GL_DEPTH_TEST);

現在,“我的網格”及其紋理已正確顯示。

謝謝你的幫助。

您的假設是錯誤的。 相同的頂點坐標可以關聯到不同的紋理坐標。

在下面的代碼中,您將創建一個新的紋理坐標數組,該數組具有與頂點坐標數組一樣多的項目。 僅當每個頂點坐標與1個紋理坐標精確關聯時,該方法才有效。 該文件中有7536個紋理坐標和7366個頂點cooodinates。

 public void parseTexture() { int size = facesVertexBuffer.remaining(); System.out.println("size " + size); for(int i = 0; i < size;i++) { int faceVertex = facesVertexBuffer.get(i); int faceTexture = facesTextureBuffer.get(i); float a = textureBufferTemp.get((faceTexture)*2); float b = -textureBufferTemp.get(((faceTexture)*2)+1); textureBuffer.put((faceVertex*2),a); textureBuffer.put(((faceVertex)*2)+1,b); } textureBuffer.position(0); System.out.println("end parse texture"); } 

如果頂點坐標和紋理坐標的索引不同,則必須“復制”頂點位置。 頂點坐標及其屬性(如紋理坐標)形成數據記錄。 您可以將3D頂點坐標和2D紋理坐標想象為一個5D坐標。 請參見渲染具有多個索引的網格

每個頂點位置的頂點屬性形成一組數據。 這意味着您必須創建頂點坐標和紋理坐標的元組。

假設您有一個.obj文件,如下所示:

v -1 -1 -1
v  1 -1 -1
v -1  1 -1
v  1  1 -1
v -1 -1  1
v  1 -1  1
v -1  1  1
v  1  1  1

vt 0 0
vt 0 1
vt 1 0
vt 1 1

vn -1  0  0
vn  0 -1  0
vn  0  0 -1
vn  1  0  0
vn  0  1  0
vn  0  0  1

f 3/1/1 1/2/1 5/4/1 7/3/1
f 1/1/2 2/2/2 3/4/2 6/3/2
f 3/1/3 4/2/3 2/4/3 1/3/3
f 2/1/4 4/2/4 8/4/4 6/3/4
f 4/1/5 3/2/5 7/4/5 8/3/5
f 5/1/6 6/2/6 8/4/6 7/3/6

由此,您必須找到頂點規范,紋理紋理坐標和法向矢量索引的所有組合,這些組合在面部規范中使用:

 0 : 3/1/1
 1 : 1/2/1
 2 : 5/4/1
 3 : 7/3/1
 4 : 1/1/2
 5 : 2/2/2
 6 : 3/4/2
 7 : 6/3/2
 8 : ...

然后,您必須創建與組合索引數組相對應的頂點坐標,紋理坐標和法線矢量數組。 頂點坐標及其屬性可以在一個數組中組合成數據集,或者在三個數組中組合成相等數量的屬性:

 index   vx vy vz     u v     nx ny nz
 0 :     -1  1 -1     0 0     -1  0  0
 1 :     -1 -1 -1     0 1     -1  0  0
 2 :     -1 -1  1     1 1     -1  0  0
 3 :     -1  1  1     1 0     -1  0  0
 4 :     -1 -1 -1     0 0      0 -1  0
 5 :      1 -1 -1     0 1      0 -1  0
 6 :     -1  1 -1     1 1      0 -1  0
 7 :      1 -1  1     1 0      0 -1  0
 8 : ...

還要注意,用於應用程序中索引的數據類型short的范圍為[-32768,32767]。 對於該模型,這足夠大,但是較大模型的索引數將超過此限制。


最簡單的解決方法是創建一個三角形基元數組。 完全跳過索引緩沖區,並使用GLES30.glDrawArrays()繪制網格。

在臨時緩沖區中將頂點坐標和紋理坐標變為紅色。

ByteBuffer bufferVTemp = ByteBuffer.allocateDirect(verticesList.size() * 2 * 4);
bufferVTemp.order(ByteOrder.nativeOrder());
verticesBufferTemp = bufferVTemp.asFloatBuffer();

ByteBuffer bufferTTemp = ByteBuffer.allocateDirect(textureList.size() * 2 * 4);
bufferTTemp.order(ByteOrder.nativeOrder());
textureBufferTemp = bufferTTemp.asFloatBuffer();

for(String vertex: verticesList) {
    String coords[] = vertex.split(" "); // Split by space
    float x = Float.parseFloat(coords[1]);
    float y = Float.parseFloat(coords[2]);
    float z = Float.parseFloat(coords[3]);
    verticesBufferTemp.put(x);
    verticesBufferTemp.put(y);
    verticesBufferTemp.put(z);
}
verticesBufferTemp.position(0);

for (String texture: textureList)
{
    String textureIndices[] = texture.split("\\s+");
    float texture1 = Float.parseFloat(textureIndices[1]);
    float texture2 = Float.parseFloat(textureIndices[2]);
    textureBufferTemp.put(texture1);
    textureBufferTemp.put(texture2);
}
textureBufferTemp.position(0);

然后創建一個數組

ByteBuffer bufferV = ByteBuffer.allocateDirect(facesVertexBuffer.size() * 3 * 4);
bufferV.order(ByteOrder.nativeOrder());
verticesBuffer = bufferV.asFloatBuffer();

ByteBuffer bufferT = ByteBuffer.allocateDirect(facesVertexBuffer.size() * 2 * 4);
bufferT.order(ByteOrder.nativeOrder());
textureBuffer = bufferT.asFloatBuffer();

int size = facesVertexBuffer.remaining();
System.out.println("size " + size);
for(int i = 0; i < size;i++)
{
    int faceVertex = facesVertexBuffer.get(i);
    int faceTexture = facesTextureBuffer.get(i);

    float x = verticesBufferTemp.get((faceVertex)*2);
    float y = verticesBufferTemp.get(((faceVertex)*2)+1);
    float z = verticesBufferTemp.get(((faceVertex)*2)+1);
    verticesBuffer.put( i*3,    x);
    verticesBuffer.put( i*3+1,  y);
    verticesBuffer.put( i*3+2), z);

    float u = textureBufferTemp.get((faceTexture)*2);
    float v = -textureBufferTemp.get(((faceTexture)*2)+1);
    textureBuffer.put( i*2,   u);
    textureBuffer.put( i*2+1, v);
}
verticesBuffer.position(0);
textureBuffer.position(0);

通過GLES30.glDrawArrays()繪制網格:

GLES30.glDrawElements(GLES30.GL_TRIANGLES, 0, facesVertexBuffer.size());

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM