OpenGL ES 2.0 中的立方体不绘制给定的纹理

Cube in OpenGL ES 2.0 does not draw the given textures

通常我不会用我的问题打扰你,但这次我很绝望。

首先,我是 OpenGL 的新手,所以如果我犯了一些新手错误,请不要批评我。我已经看过一些示例了,但是有些示例代码对我来说是无法理解的。

其次,我知道这个问题之前已经在堆栈中被问过,但是给出的答案不是我的案例的解决方案。他们说应该调整图像的大小,使其成为 2 的幂,所以我做了,但没有效果。他们还说它可能是png的透明元素,所以我在fragmentShader中更改了gl_FragColor(不止一次),但没有效果。

您可以在下面找到我用来绘制立方体并旋转它的代码。所以一切正常,除此之外它也应该显示纹理但它没有。能帮我解决这个问题的是大神!

这是创建表面视图并设置自定义渲染器的activity

package --------------------;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ConfigurationInfo;
import android.opengl.GLSurfaceView;
import android.os.Bundle;

public class MyGLSurfaceView extends Activity {
    private GLSurfaceView mGLSurfaceView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mGLSurfaceView = new GLSurfaceView(this);

        final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
        final ConfigurationInfo configurationInfo =  activityManager.getDeviceConfigurationInfo();
        final boolean supportsEs2 = configurationInfo.reqGlEsVersion >=  0x20000;

        if (supportsEs2) {
            mGLSurfaceView.setEGLContextClientVersion(2);
            mGLSurfaceView.setRenderer(new MyOpenGLESRenderer(this));
        } else {
            return;
        }

        setContentView(mGLSurfaceView);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mGLSurfaceView.onResume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mGLSurfaceView.onPause();
    }
}

这是渲染器

package ----------------------;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.GLUtils;
import android.opengl.Matrix;
import android.util.DisplayMetrics;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

public class MyOpenGLESRenderer implements GLSurfaceView.Renderer {
    private final Context context;

    private Cube cube;

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

    private int programHandle;
    private int textureDataHandle1;
    private int textureDataHandle2;
    private int textureDataHandle3;
    private int textureDataHandle4;
    private int textureDataHandle5;
    private int textureDataHandle6;

    private int[] textureHandles = {
            textureDataHandle1,
            textureDataHandle2,
            textureDataHandle3,
            textureDataHandle4,
            textureDataHandle5,
            textureDataHandle6
    };

    int deviceWidth;
    int deviceHeight;

    public MyOpenGLESRenderer(final Context context) {
        this.context = context;

        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
        deviceWidth = displayMetrics.widthPixels;
        deviceHeight = displayMetrics.heightPixels;
    }

    @Override
    public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
        GLES20.glClearColor(0.3f, 1.0f, 0.3f, 0.0f);
        GLES20.glEnable(GLES20.GL_TEXTURE_2D);
        GLES20.glEnable(GLES20.GL_CULL_FACE);
        GLES20.glEnable(GLES20.GL_DEPTH_TEST);

        final float eyeX = 0.0f;
        final float eyeY = 0.0f;
        final float eyeZ = -0.5f;

        final float lookX = 0.0f;
        final float lookY = 0.0f;
        final float lookZ = -5.0f;

        final float upX = 0.0f;
        final float upY = 1.0f;
        final float upZ = 0.0f;

        Matrix.setLookAtM(viewMatrix, 0, eyeX, eyeY, eyeZ, lookX, lookY, lookZ, upX, upY, upZ);

        final String vertexShader =
            "uniform mat4 u_MVPMatrix;      \n"        // A constant representing the combined model/view/projection matrix.

                    + "attribute vec4 a_Position;     \n"        // Per-vertex position information we will pass in.
                    + "attribute vec4 a_Color;        \n"        // Per-vertex color information we will pass in.
                    + "attribute vec2 a_TexCoordinate;\n"
                    + "varying vec2 v_TexCoordinate;  \n"
                    + "varying vec4 v_Color;          \n"        // This will be passed into the fragment shader.

                    + "void main()                    \n"        // The entry point for our vertex shader.
                    + "{                              \n"
                    + "   v_Color = a_Color;          \n"        // Pass the color through to the fragment shader.
                    + "v_TexCoordinate = a_TexCoordinate;\n"                                                                     // It will be interpolated across the triangle.
                    + "   gl_Position = u_MVPMatrix   \n"    // gl_Position is a special variable used to store the final position.
                    + "               * a_Position;   \n"     // Multiply the vertex by the matrix to get the final point in
                    + "}                              \n";    // normalized screen coordinates.

        final String fragmentShader =
            "precision mediump float;       \n"        // Set the default precision to medium. We don't need as high of a
                    // precision in the fragment shader.
                    + "varying vec4 v_Color;          \n"        // This is the color from the vertex shader interpolated across the
                    + "uniform sampler2D u_Texture;   \n"
                    + "varying vec2 v_TexCoordinate;   \n"// triangle per fragment.
                    + "void main()                    \n"        // The entry point for our fragment shader.
                    + "{                              \n"
                    + " gl_FragColor = (v_Color * texture2D(u_Texture, v_TexCoordinate));     \n"        // Pass the color directly through the pipeline.
                    + "}                              \n";

        final int vertexShaderHandle = loadShader(vertexShader, GLES20.GL_VERTEX_SHADER);
        final int fragmentShaderHandle = loadShader(fragmentShader, GLES20.GL_FRAGMENT_SHADER);

        programHandle = createAndLinkProgram(vertexShaderHandle, fragmentShaderHandle,
            new String[]{"a_Position", "a_Color", "a_TexCoordinate"});

    }

    @Override
    public void onSurfaceChanged(GL10 glUnused, int width, int height) {
        GLES20.glViewport(0, 0, width, height);

        final float ratio = (float) width / height;
        final float left = -ratio;
        final float right = ratio;
        final float bottom = -1.0f;
        final float top = 1.0f;
        final float near = 1.0f;
        final float far = 10.0f;

        Matrix.frustumM(projectionMatrix, 0, left, right, bottom, top, near, far);
    }

    @Override
    public void onDrawFrame(GL10 glUnused) {
        cube = new Cube(deviceWidth, deviceHeight);
        cube.onDraw(programHandle, textureHandles, viewMatrix, projectionMatrix);
    }

    private int loadShader(final String shader, final int glShader) {
        int shaderHandle = GLES20.glCreateShader(glShader);

        if (shaderHandle != 0) {
            GLES20.glShaderSource(shaderHandle, shader);
            GLES20.glCompileShader(shaderHandle);

            final int[] compileStatus = new int[1];
            GLES20.glGetShaderiv(shaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);

            if (compileStatus[0] == 0) {
                GLES20.glDeleteShader(shaderHandle);
                shaderHandle = 0;
            }
        }
        if (shaderHandle == 0) {
            throw new RuntimeException("Error creating shader.");
        }
        return shaderHandle;
    }

    private int createAndLinkProgram(final int vertexShaderHandle, final int fragmentShaderHandle, final String[] attributes) {
        programHandle = GLES20.glCreateProgram();

        if (programHandle != 0) {
            GLES20.glAttachShader(programHandle, vertexShaderHandle);
            GLES20.glAttachShader(programHandle, fragmentShaderHandle);

            if (attributes != null) {
                final int size = attributes.length;
                for (int i = 0; i < size; i++) {
                    GLES20.glBindAttribLocation(programHandle, i, attributes[i]);
                }
            }

            GLES20.glLinkProgram(programHandle);
            textureDataHandle1 = loadTexture(R.drawable.diceface1);
            textureDataHandle2 = loadTexture(R.drawable.diceface4);
            textureDataHandle3 = loadTexture(R.drawable.diceface6);
            textureDataHandle4 = loadTexture(R.drawable.diceface3);
            textureDataHandle5 = loadTexture(R.drawable.diceface5);
            textureDataHandle6 = loadTexture(R.drawable.diceface2);

            final int[] linkStatus = new int[1];
            GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);

            if (linkStatus[0] == 0) {
                GLES20.glDeleteProgram(programHandle);
                programHandle = 0;
            }
        }
        if (programHandle == 0) {
            throw new RuntimeException("Error creating program.");
        }
        return programHandle;
    }

    private int loadTexture(final int resourceId) {
        final int[] textureHandle = new int[1];

        GLES20.glGenTextures(1, textureHandle, 0);

        if (textureHandle[0] != 0) {
            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inScaled = false;   // No pre-scaling

            final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);

            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);

            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);

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

            bitmap.recycle();
        }

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

        return textureHandle[0];
     }
}

这是需要渲染的对象:

package ---------------;

import android.opengl.GLES20;
import android.opengl.Matrix;
import android.os.SystemClock;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

public class Cube {

    private float X = 0, Y = 0;

    private final FloatBuffer cubeVertices;
    private final FloatBuffer cubeColors;
    private final FloatBuffer cubeTextureCoordinates;

    private float[] modelMatrix = new float[16];
    private float[] viewMatrix = new float[16];
    private float[] projectionMatrix = new float[16];

    private float[] MVPMatrix = new float[16];

    private int MVPMatrixHandle;
    private int MVMatrixHandle;
    private int textureUniformHandle;
    private int positionHandle;
    private int colorHandle;
    private int textureCoordinateHandle;

    private final int positionDataSize = 3;
    private final int colorDataSize = 4;
    private final int textureCoordinateDataSize = 2;

    private final int bytesPerFloat = 4;

    private boolean upX = true;
    private boolean upY = true;
    private float counterX = 0.0f;
    private float counterY = 0.0f;

    private int deviceWidth;
    private int deviceHeight;

    private final float[] verticesData = {
            -0.6f, 0.6f, 0.6f,
            -0.6f, -0.6f, 0.6f,
            0.6f, 0.6f, 0.6f,
            -0.6f, -0.6f, 0.6f,
            0.6f, -0.6f, 0.6f,
            0.6f, 0.6f, 0.6f,

            0.6f, 0.6f, 0.6f,
            0.6f, -0.6f, 0.6f,
            0.6f, 0.6f, -0.6f,
            0.6f, -0.6f, 0.6f,
            0.6f, -0.6f, -0.6f,
            0.6f, 0.6f, -0.6f,

            0.6f, 0.6f, -0.6f,
            0.6f, -0.6f, -0.6f,
            -0.6f, 0.6f, -0.6f,
            0.6f, -0.6f, -0.6f,
            -0.6f, -0.6f, -0.6f,
            -0.6f, 0.6f, -0.6f,

            -0.6f, 0.6f, -0.6f,
            -0.6f, -0.6f, -0.6f,
            -0.6f, 0.6f, 0.6f,
            -0.6f, -0.6f, -0.6f,
            -0.6f, -0.6f, 0.6f,
            -0.6f, 0.6f, 0.6f,

            -0.6f, 0.6f, -0.6f,
            -0.6f, 0.6f, 0.6f,
            0.6f, 0.6f, -0.6f,
            -0.6f, 0.6f, 0.6f,
            0.6f, 0.6f, 0.6f,
            0.6f, 0.6f, -0.6f,

            0.6f, -0.6f, -0.6f,
            0.6f, -0.6f, 0.6f,
            -0.6f, -0.6f, -0.6f,
            0.6f, -0.6f, 0.6f,
            -0.6f, -0.6f, 0.6f,
            -0.6f, -0.6f, -0.6f,
    };

    private final float[] cubeColorData = {
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,

            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,

            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,

            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,

            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,

            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f,
            1.0f, 1.0f, 1.0f, 1.0f
    };

    private final float[] cubeTextureCoordinateData = {
            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,
            1.0f, 0.0f,

            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,
            1.0f, 0.0f,

            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,
            1.0f, 0.0f,

            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,
            1.0f, 0.0f,

            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,
            1.0f, 0.0f,

            0.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 0.0f,
            0.0f, 1.0f,
            1.0f, 1.0f,
            1.0f, 0.0f
    };

    public Cube(int deviceWidth, int deviceHeight) {
        this.deviceWidth = deviceWidth;
        this.deviceHeight = deviceHeight;

        cubeVertices = ByteBuffer.allocateDirect(verticesData.length *     bytesPerFloat)
            .order(ByteOrder.nativeOrder()).asFloatBuffer();
        cubeVertices.put(verticesData).position(0);

        cubeColors = ByteBuffer.allocateDirect(cubeColorData.length * bytesPerFloat)
            .order(ByteOrder.nativeOrder()).asFloatBuffer();
        cubeColors.put(cubeColorData).position(0);

        cubeTextureCoordinates = ByteBuffer.allocateDirect(cubeTextureCoordinateData.length * bytesPerFloat)
            .order(ByteOrder.nativeOrder()).asFloatBuffer();
        cubeTextureCoordinates.put(cubeTextureCoordinateData).position(0);
    }

    public void onDraw(int programHandle, int[] textureDataHandles, float[] viewMatrix, float[] projectionMatrix) {
        this.viewMatrix = viewMatrix;
        this.projectionMatrix = projectionMatrix;

        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        long time = SystemClock.uptimeMillis() % 10000L;
        float angleInDegrees = (360.0f / 10000.0f) * ((int) time);

        GLES20.glUseProgram(programHandle);

        MVPMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_MVPMatrix");
        MVMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_MVMatrix");
        textureUniformHandle = GLES20.glGetUniformLocation(programHandle, "u_Texture");
        positionHandle = GLES20.glGetAttribLocation(programHandle, "a_Position");
        colorHandle = GLES20.glGetAttribLocation(programHandle, "a_Color");
        textureCoordinateHandle = GLES20.glGetAttribLocation(programHandle, "a_TexCoordinate");

        Matrix.setIdentityM(modelMatrix, 0);

        //Matrix.translateM(modelMatrix, 0, 3.0f, 5.5f, -7.0f);

        //zie kladblok!!!!!!!!!!
        Matrix.translateM(modelMatrix, 0, X, Y, -7.0f);

        Matrix.rotateM(modelMatrix, 0, angleInDegrees, 1.0f, 0.0f, 0.0f);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureDataHandles[0]);
        GLES20.glUniform1i(textureUniformHandle, 0);
        drawCube(0);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureDataHandles[1]);
        GLES20.glUniform1i(textureUniformHandle, 1);
        drawCube(1);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE2);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureDataHandles[2]);
        GLES20.glUniform1i(textureUniformHandle, 2);
        drawCube(2);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE3);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureDataHandles[3]);
        GLES20.glUniform1i(textureUniformHandle, 3);
        drawCube(3);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE4);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureDataHandles[4]);
        GLES20.glUniform1i(textureUniformHandle, 4);
        drawCube(4);

        GLES20.glActiveTexture(GLES20.GL_TEXTURE5);
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureDataHandles[5]);
        GLES20.glUniform1i(textureUniformHandle, 5);
        drawCube(5);
    }

    private void drawCube(final int i) {
        cubeVertices.position(18 * i);
        GLES20.glVertexAttribPointer(positionHandle, positionDataSize, GLES20.GL_FLOAT, false,
            0, cubeVertices);
        GLES20.glEnableVertexAttribArray(positionHandle);

        cubeColors.position(24 * i);
        GLES20.glVertexAttribPointer(colorHandle, colorDataSize, GLES20.GL_FLOAT, false,
            0, cubeColors);
        GLES20.glEnableVertexAttribArray(colorHandle);

        cubeTextureCoordinates.position(12 * i);
        GLES20.glVertexAttribPointer(textureCoordinateHandle, textureCoordinateDataSize, GLES20.GL_FLOAT, false,
            0, cubeTextureCoordinates);
        GLES20.glEnableVertexAttribArray(textureCoordinateHandle);

        Matrix.multiplyMM(MVPMatrix, 0, viewMatrix, 0, modelMatrix, 0);
        GLES20.glUniformMatrix4fv(MVMatrixHandle, 1, false, MVPMatrix, 0);
        Matrix.multiplyMM(MVPMatrix, 0, projectionMatrix, 0, MVPMatrix, 0);
        GLES20.glUniformMatrix4fv(MVPMatrixHandle, 1, false, MVPMatrix, 0);

        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
    }
}

我认为我不需要提供更多文件(如清单),但如果您确实需要,请询问。

备注:使用记录器会很困难,因为不知何故我无法运行 来自android.

的Trancer 程序

您的纹理句柄似乎也有一些可疑的变量设置。您将各个句柄声明为整数,然后还声明一个包含 6 个值的数组。这里的 6 个值是 "int" 基本类型,而不是对象,因此数组将采用值的副本而不是引用。在代码后面的一个地方,您通过非数组版本设置,并通过数组版本绑定,这将不起作用,因为您实际上正在查看两个完全不同的变量。我建议删除数组之外的版本,只使用数组作为 6 个纹理句柄的唯一存储。

更一般地说,某些东西看起来 "off" 在您的纹理设置中。您在着色器中只设置了一个纹理采样器,并且您正试图将 6 个不同的纹理绑定到它。着色器如何知道将哪个纹理应用于哪个三角形?它不能。如果您解决了上述关于如何管理手柄的问题,您当前的着色器将只显示所有 6 个面上的最后一个绑定纹理。

如果你想在立方体的每个面上显示像骰子这样的东西,有 6 个不同的图像,那么你通常需要将所有 6 个面的纹理数据打包到一个纹理图像中,然后给每个面的顶点不同的纹理坐标,以便它映射图像的正确子区域。

HTH, 皮特