java - OpenGL 2.0 glGetUniformLocation : glError 1282 in draw()

标签 java android opengl-es

我制作了一款游戏,可以正确绘制 openGL 形状以适应游戏的大部分屏幕。但出于某种原因,在游戏中随机出现 1282 glGetUniformLocation 错误。奇怪的是它运行了一段时间后就失效了?

这是堆栈跟踪

12-12 12:31:54.781: E/AndroidRuntime(2531): FATAL EXCEPTION: GLThread 86993
12-12 12:31:54.781: E/AndroidRuntime(2531): Process: com.laytonlabs.android.levelup, PID: 2531
12-12 12:31:54.781: E/AndroidRuntime(2531): java.lang.RuntimeException: glGetUniformLocation: glError 1282
12-12 12:31:54.781: E/AndroidRuntime(2531):     at com.laytonlabs.android.levelup.MyGLRenderer.checkGlError(MyGLRenderer.java:460)
12-12 12:31:54.781: E/AndroidRuntime(2531):     at com.laytonlabs.android.levelup.shapes.Shape.draw(Shape.java:240)
12-12 12:31:54.781: E/AndroidRuntime(2531):     at com.laytonlabs.android.levelup.MyGLRenderer.drawShapes(MyGLRenderer.java:350)
12-12 12:31:54.781: E/AndroidRuntime(2531):     at com.laytonlabs.android.levelup.MyGLRenderer.drawFixedShapes(MyGLRenderer.java:324)
12-12 12:31:54.781: E/AndroidRuntime(2531):     at com.laytonlabs.android.levelup.MyGLRenderer.onDrawFrame(MyGLRenderer.java:205)
12-12 12:31:54.781: E/AndroidRuntime(2531):     at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1531)
12-12 12:31:54.781: E/AndroidRuntime(2531):     at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1248)

这是在 Shape.java draw() 函数中产生错误的部分(我认为)。

Shape.java

mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
MyGLRenderer.checkGlError("glGetUniformLocation");

下面是错误堆栈中引用的java类的完整代码。

MyGLRenderer.java

package com.laytonlabs.android.levelup;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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

import com.laytonlabs.android.levelup.game.Cell;
import com.laytonlabs.android.levelup.game.CurrentAnswer;
import com.laytonlabs.android.levelup.game.Equation;
import com.laytonlabs.android.levelup.game.Game;
import com.laytonlabs.android.levelup.game.Level;
import com.laytonlabs.android.levelup.game.Score;
import com.laytonlabs.android.levelup.game.Stage;
import com.laytonlabs.android.levelup.game.Time;
import com.laytonlabs.android.levelup.shapes.Color;
import com.laytonlabs.android.levelup.shapes.EquationRectangle;
import com.laytonlabs.android.levelup.shapes.Hexagon;
import com.laytonlabs.android.levelup.shapes.InputSquare;
import com.laytonlabs.android.levelup.shapes.Shape;
import com.laytonlabs.android.levelup.shapes.StatsRectangle;

import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.util.Log;

public class MyGLRenderer implements GLSurfaceView.Renderer {

    private static final String TAG = "MyGLRenderer";
    private static StatsRectangle levelRectangle;
    private static StatsRectangle timeRectangle;
    private static StatsRectangle scoreRectangle;
    private static EquationRectangle equationRectangle;
    private static EquationRectangle answerRectangle;
    private ArrayList<Shape> gridShapes;
    private ArrayList<Shape> bottomRowShapes;
    private static ArrayList<Shape> inputShapes;

    // mMVPMatrix is an abbreviation for "Model View Projection Matrix"
    private final float[] mMVPMatrix = new float[16];
    private final float[] mMVPFixed = new float[16];
    private final float[] mProjectionMatrix = new float[16];
    private final float[] mViewMatrix = new float[16];
    private final float[] mGridModelMatrix = new float[16];
    private float[] mFixedModelMatrix = new float[16];
    private float[] mTempMatrix = new float[16];

    private float mMovementY;
    private float mBottomRowScale; 
    private static String mAnswerText = CurrentAnswer.getLabel();
    private boolean isCorrectGuess = false;
    private boolean renderCorrectGuess = false;
    private boolean isWrongGuess = false;
    private boolean renderOutput = false;

    //To limit the number of renders per second
    private long startTime;
    private long endTime;
    private long timeElapsed;
    private int currentFrame = 0;              // active frame
    private int outputCurrentFrame = 0;              // active frame
    private final int FPS = 33;                // Frames per second
    private final int FPS_ANIMATION_10 = 10;
    private final int FPS_ANIMATION_20 = 20;

    //Reducer values, these are used for animation scenes
    private float mFPSMovementY;
    private float mFPSBottomRowScale;

    private int gridLevel = 0; //The cell layout level in the grid.
    private int rowLevel = 1; //The current row in the grid user is selected.

    //Constants for grid presentation 
    private final float CELL_SCALE = 0.3f;
    private final float CELL_OFFSET_Y = 0.7f;

    @Override
    public void onSurfaceCreated(GL10 unused, EGLConfig config) {

        // Set the background frame color
        GLES20.glClearColor(Color.DARK_GREY[0], Color.DARK_GREY[1], Color.DARK_GREY[2], Color.DARK_GREY[3]);

        startTime = System.currentTimeMillis();

        //TODO Add code that sets current answer to whatever the current answer is.

        //Initialise fixed shapes
        equationRectangle = new EquationRectangle(-0.35f);
        answerRectangle = new EquationRectangle(-0.5f);

        equationRectangle.setShapes(0.2f, Equation.get());
        answerRectangle.setShapes(0.3f, mAnswerText);

        //TODO - Change the below calculations to be align_left, align_centre, align_right, etc.
        levelRectangle = new StatsRectangle(0 - (Screen.DEFAULT_WIDTH/3), Color.TURQUOISE, Color.TURQUOISE);
        timeRectangle = new StatsRectangle(0, Color.PURPLE, Color.PURPLE);
        scoreRectangle = new StatsRectangle(0 + (Screen.DEFAULT_WIDTH/3), Color.TURQUOISE, Color.TURQUOISE);

        levelRectangle.setShapes(-1f, Level.getLabel());
        scoreRectangle.setShapes(-1f, Score.getScoreLabel());
        timeRectangle.setShapes(-1f, Time.getTimeRemainingLabel());

        setGridShapes();
        //Complete the bottom row for inputting guesses
        bottomRowShapes = new ArrayList<Shape>();
        setBottomRowShapes();
        buildInputGrid();
        setBottomRowScale(1.0f);
        setFPSBottomRowScale(getBottomRowScale() / FPS_ANIMATION_20);
        setFPSMovementY((CELL_OFFSET_Y*CELL_SCALE) / FPS_ANIMATION_20);
    }

    private void buildInputGrid() {
        inputShapes = new ArrayList<Shape>();

        inputShapes.add(new InputSquare(0.16f, -3.0f, 1.15f, "1")); //1
        inputShapes.add(new InputSquare(0.16f, -1.8f, 1.15f, "2")); //2
        inputShapes.add(new InputSquare(0.16f, -0.6f, 1.15f, "3")); //3
        inputShapes.add(new InputSquare(0.16f,  0.6f, 1.15f, "4")); //4
        inputShapes.add(new InputSquare(0.16f,  1.8f, 1.15f, "5")); //5
        inputShapes.add(new InputSquare(0.16f,  3.0f, 1.15f, "6")); //6
        inputShapes.add(new InputSquare(0.16f, -2.4f,     0, "7")); //7
        inputShapes.add(new InputSquare(0.16f, -1.2f,     0, "8")); //8
        inputShapes.add(new InputSquare(0.16f,     0,     0, "9")); //9
        inputShapes.add(new InputSquare(0.16f,  1.2f,     0, "0")); //0
        inputShapes.add(new InputSquare(0.16f,  2.4f,     0, "x")); //X - This is to clear input
    }

    @Override
    public void onDrawFrame(GL10 unused) {

        //We dont need continuous rendering, only needed for animation and time switching
        endTime = System.currentTimeMillis();
        timeElapsed = endTime - startTime;
        if (timeElapsed < FPS) {
            try {
                Log.d(TAG, "Sleeping until "+FPS+" millsecs pass");
                Thread.sleep(FPS - timeElapsed);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        startTime = endTime;

        //Update the timers by deducting timeRemaining
        Time.update();

        Matrix.setIdentityM(mGridModelMatrix, 0); // initialize to identity matrix
        //Setup the equation display before we start moving the grid around
        Matrix.setIdentityM(mFixedModelMatrix, 0); // initialize to identity matrix

        // Draw background color
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        // Enable transparency options for colors.
        GLES20.glEnable(GLES20.GL_BLEND);
        GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);

        // Set the camera position (View matrix)
        Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

        // Calculate the projection and view transformation
        Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);

        //Clone this for use with fixed and grid MVPs
        mTempMatrix = mMVPMatrix.clone();

        // Create a rotation for the triangle

        // Use the following code to generate constant rotation.
        // Leave this code out when using TouchEvents.
        // long time = SystemClock.uptimeMillis() % 4000L;
        // float angle = 0.090f * ((int) time);

        drawGridShapes();

        drawFixedShapes();
    }

    private void drawGridShapes() {     
        //Start the grid drawing at bottom of screen.
        Matrix.translateM(mGridModelMatrix, 0, 0, -0.1f, 0);

        //Move the grid down or up the screen depending on touch events.
        Matrix.translateM(mGridModelMatrix, 0, 0, mMovementY, 0);

        // Combine the rotation matrix with the projection and camera view
        // Note that the mMVPMatrix factor *must be first* in order
        // for the matrix multiplication product to be correct.
        //Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);

        //Add the movement to the matrix
        Matrix.multiplyMM(mMVPMatrix, 0, mTempMatrix, 0, mGridModelMatrix, 0);

        if (isCorrectGuess()) {
            renderCorrectGuess = true; //This is to change the answer text to green inside drawFixedShapes
            currentFrame++;                    // step to next frame
            setMovementY(getMovementY() - getFPSMovementY());
            setBottomRowScale(getBottomRowScale() - getFPSBottomRowScale());
            if (currentFrame >= FPS_ANIMATION_20) {            // if end of sequence
                currentFrame = 0;               // restart sequence
                setBottomRowScale(1.0f);        // Reset the scale
                removeBottomRow();
                setCorrectGuess(false);         //Mark as false so animation stops and user can make new guess
            }
        }

        //Draw all grid shapes
        if (isCorrectGuess()) {
            drawAllShapesAndShrinkBottomRow(mMVPMatrix);
        } else {
            drawAllShapes(getGridShapes(), mMVPMatrix);
        }
    }

    private void drawAllShapes(ArrayList<Shape> shapes, float[] mMVPMatrix) {
        for (Shape shape : shapes) {
            Log.d(TAG, "Scale Hexagon ("+shape.toString()+") Aft ("+shape.getCentreX()+", "+shape.getCentreY()+")");
            drawShapes(shape, mMVPMatrix);
        }
    }

    private void drawAllShapesAndShrinkBottomRow(float[] mMVPMatrix) {
        float[] mMVPScaled = mMVPMatrix.clone();

        Matrix.scaleM(mMVPScaled, 0, getBottomRowScale(), getBottomRowScale(), 0);

        int lastCellIndex = getBottomRowLastCellIndex();

        //Apply scaling to the bottom row and just move the other rows.
        for (int i = 0; i < getGridShapes().size(); i++) {
            if (i <= lastCellIndex) {
                drawShapes(getGridShapes().get(i), mMVPScaled);
            } else {
                drawShapes(getGridShapes().get(i), mMVPMatrix);
            }
        }
    }

    private void drawFixedShapes() {

        Matrix.multiplyMM(mMVPFixed, 0, mTempMatrix, 0, mFixedModelMatrix, 0);

        if (isRenderOutput()) {
            //Show the equation using the values from the selected cell.
            equationRectangle.setShapes(0.2f, Equation.get());
            answerRectangle.setShapes(0.3f, mAnswerText);

            setRenderOutput(false);
        }

        //Update the time if time has changed
        if (!timeRectangle.toString().equals(Time.getTimeRemainingLabel())) {
            //If the time remaining is almost up then change text to red.
            if (Time.isTimeAlmostUp()) {
                timeRectangle.setShapes(-1f, Time.getTimeRemainingLabel(), Color.RED);
            } else {
                timeRectangle.setShapes(-1f, Time.getTimeRemainingLabel());
            }
        }

        //Animation for changing color of the text
        if (isWrongGuess()) {
            if (outputCurrentFrame == 0) {
                answerRectangle.setShapes(0.3f, mAnswerText, Color.RED);
            }
            outputCurrentFrame++;
            if (outputCurrentFrame >= FPS_ANIMATION_10) {
                outputCurrentFrame = 0;
                setAnswerText("");
                answerRectangle.setShapes(0.3f, mAnswerText);
                setWrongGuess(false);           
            }
        } else if (renderCorrectGuess) {
            if (outputCurrentFrame == 0) {
                answerRectangle.setShapes(0.3f, mAnswerText, Color.GREEN);
                levelRectangle.setShapes(-1f, Level.getLabel(), Color.YELLOW);
                scoreRectangle.setShapes(-1f, Score.getScoreLabel(), Color.YELLOW);
                timeRectangle.setShapes(-1f, Time.getTimeRemainingLabel(), Color.YELLOW);
            }
            outputCurrentFrame++;
            if (outputCurrentFrame >= FPS_ANIMATION_20) {
                outputCurrentFrame = 0;
                answerRectangle.setShapes(0.3f, mAnswerText);
                levelRectangle.setShapes(-1f, Level.getLabel());
                scoreRectangle.setShapes(-1f, Score.getScoreLabel());
                timeRectangle.setShapes(-1f, Time.getTimeRemainingLabel());
                setGridShapes();
                renderCorrectGuess = false;     
            }
        }

        drawShapes(answerRectangle, mMVPFixed);
        drawShapes(equationRectangle, mMVPFixed);
        drawShapes(levelRectangle, mMVPFixed);
        drawShapes(timeRectangle, mMVPFixed);
        drawShapes(scoreRectangle, mMVPFixed);

        //Draw all input grid shapess
        drawAllShapes(inputShapes, mMVPFixed);
    }

    public static void printStack() {
        Log.e(TAG,"Level: " + Level.getLabel());
        Log.e(TAG,"Score: " + Score.getScoreLabel());
        Log.e(TAG,"Time: " + Time.getTimeRemainingLabel());
        Log.e(TAG,"mAnswerText: " + mAnswerText);
        Log.e(TAG,"Equation: " + Equation.get());
        for (int i = 0; i < inputShapes.size(); i++) {
            Log.e(TAG,"inputShapes[" + i + "]: " + inputShapes.get(i).toString());
        }
    }

    private void drawShapes(Shape parentShape, float[] mMVPMatrix) {
        parentShape.draw(mMVPMatrix);

        if (parentShape.getShapes() == null) {
            return;
        }

        for (Shape nestedShapes : parentShape.getShapes()) {
            nestedShapes.draw(mMVPMatrix);
        }
    }

    private ArrayList<Shape> getGridShapes() {
        return gridShapes;
    }

    private int getBottomRowLastCellIndex() {
        int lastCellIndex = 0;
        Shape prevShape = null;
        for (int i = 0; i < getGridShapes().size(); i++) {
            if (prevShape == null || getGridShapes().get(i).getCentreY() == prevShape.getCentreY()) {
                lastCellIndex = i;
                prevShape = getGridShapes().get(i);
            } else {
                return lastCellIndex;
            }
        }
        return lastCellIndex;
    }

    private void removeBottomRow() {
        for (int i = getBottomRowLastCellIndex(); i >= 0 ; i--) {
            getGridShapes().remove(i);
        }
        //Reset the bottom row shapes
        setBottomRowShapes();
    }

    public ArrayList<Shape> getBottomRowShapes() {
        return bottomRowShapes;
    }

    private void setBottomRowShapes() {
        ArrayList<Shape> tempRowShapes = new ArrayList<Shape>();

        //Apply scaling to the bottom row and just move the other rows.
        for (int i = 0; i <= getBottomRowLastCellIndex(); i++) {
            tempRowShapes.add(getGridShapes().get(i));
        }
        bottomRowShapes = tempRowShapes;
    }

    @Override
    public void onSurfaceChanged(GL10 unused, int width, int height) {
        // Adjust the viewport based on geometry changes,
        // such as screen rotation
        GLES20.glViewport(0, 0, width, height);

        //Log.d("MyGLRenderer", "Width: " + width + " Height: " + height);

        float ratio = (float) width / height;

        Log.d("Screen","Width: "+ width +" - Height: "+ height +" - Ratio: "+ ratio);

        // this projection matrix is applied to object coordinates
        // in the onDrawFrame() method
        if (ratio > 1) {
            ratio = Screen.DEFAULT_LANDSCAPE_RATIO;
        } else {
            ratio = Screen.DEFAULT_PORTRAIT_RATIO;
        }

        Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);

        //TODO Store the current answer, the current answer Text and the current Equation. 
    }

    public static int loadShader(int type, String shaderCode){

        // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
        // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
        int shader = GLES20.glCreateShader(type);

        // add the source code to the shader and compile it
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);

        return shader;
    }

    public static void checkGlError(String glOperation) {
        int error;
        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
            Log.e(TAG, glOperation + ": 1glError " + error);
            printStack();
            //TODO - Print out the fixed shapes values to see if something wierd is being displayed after a while.
            throw new RuntimeException(glOperation + ": glError " + error);
        }
    }

    public float getMovementY() {
        return mMovementY;
    }

    public void setMovementY(float movementY) {
        mMovementY = movementY;
    }

    public float[] getProjectionMatrix() {
        return mProjectionMatrix;
    }

    public float[] getGridModelMatrix() {
        return mGridModelMatrix;
    }

    public float[] getFixedModelMatrix() {
        return mFixedModelMatrix;
    }

    public String getAnswerText() {
        return mAnswerText;
    }

    public void setAnswerText(String guessInput) {
        if (guessInput == "") {
            this.mAnswerText = getInputUnderscores();
            return;
        }

        this.mAnswerText = this.mAnswerText.replaceFirst("_", guessInput);
    }

    public void resetAnswerText() {
        this.mAnswerText = CurrentAnswer.getLabel();
    }

    private String getInputUnderscores() {
        if (Equation.getExpectedAnswer() <= 0) {
            return "";
        }

        return Equation.getExpectedAnswerLabel().replaceAll("[0-9]", "_");
    }

    public ArrayList<Shape> getInputShapes() {
        return inputShapes;
    }

Shape.java

package com.laytonlabs.android.levelup.shapes;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayList;

import android.opengl.GLES20;

import com.laytonlabs.android.levelup.MyGLRenderer;
import com.laytonlabs.android.levelup.Vec2;
import com.laytonlabs.android.levelup.game.Cell;

/**
 * A two-dimensional square for use as a drawn object in OpenGL ES 2.0.
 */
public abstract class Shape {

    private final String TAG = "Shape";

    private final String vertexShaderCode =
            // This matrix member variable provides a hook to manipulate
            // the coordinates of the objects that use this vertex shader
            "uniform mat4 uMVPMatrix;" +
            "attribute vec4 vPosition;" +
            "void main() {" +
            // The matrix must be included as a modifier of gl_Position.
            // Note that the uMVPMatrix factor *must be first* in order
            // for the matrix multiplication product to be correct.
            "  gl_Position = uMVPMatrix * vPosition;" +
            "}";

    private final String fragmentShaderCode =
            "precision mediump float;" +
            "uniform vec4 vColor;" +
            "void main() {" +
            "  gl_FragColor = vColor;" +
            "}";

    private final FloatBuffer vertexBuffer;
    private final ShortBuffer drawListBuffer;
    private final int mProgram;
    private int mPositionHandle;
    private int mColorHandle;
    private int mMVPMatrixHandle;
    protected float[] shapeCoords;
    private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex

    // number of coordinates per vertex in this array
    static final int COORDS_PER_VERTEX = 3;

    //These will be initiated by the abstract class
    private final float[] ORIGINAL_COORDS;
    private final short[] DRAW_ORDER; // order to draw vertices

    //#RGB: white (255, 255, 255)
    private final float[] COLOR;

    //Sets the scale of the shape and where the X centre is.
    private final float SCALE;
    private final float CENTRE_X;
    private final float CENTRE_Y;

    public abstract float getCentreX();
    public abstract float getCentreY();

    public float[] getNestedTextColor() {
        return null;
    }

    public void setNestedTextColor(float[] textColor) {}

    public Cell getCell() {
        return null;
    }

    public ArrayList<Shape> getShapes() {
        return null;
    }

    public void setShapes(float scale, String nestedText) {}

    public void setShapes(float scale, String nestedText, float[] textColor) {}

    public boolean intersects(Vec2 touchCoords) {
        return false;
    }

    public float getMinX() {return getMin(getArraySubset(0));}
    public float getMaxX() {return getMax(getArraySubset(0));}
    public float getMinY() {return getMin(getArraySubset(1));}
    public float getMaxY() {return getMax(getArraySubset(1));}

    private float getMin(float[] values) {
        float minVal = 1000f;
        for (float value : values) {
            if (value < minVal) {
                minVal = value;
            }
        }
        return minVal;
    }

    private float getMax(float[] values) {
        float maxVal = -1000f;
        for (float value : values) {
            if (value > maxVal) {
                maxVal = value;
            }
        }
        return maxVal;
    }

    private float[] getArraySubset(int offset) {
        if (shapeCoords == null || shapeCoords.length == 0) {
            return null;
        }

        float[] subsetArray = new float[shapeCoords.length / COORDS_PER_VERTEX];
        int subsetIndex = 0;

        for (int i = offset; i < shapeCoords.length; i=(i+COORDS_PER_VERTEX)) {
            subsetArray[subsetIndex] = shapeCoords[i];
            subsetIndex++;
        }
        return subsetArray;
    }

    /**
     * Sets up the drawing object data for use in an OpenGL ES context.
     */
    public Shape(float[] originalCoords, short[] drawOrder, float[] color, 
            float scale, float centreX, float centreY) {

        this.ORIGINAL_COORDS = originalCoords;
        this.DRAW_ORDER = drawOrder;
        this.COLOR = color;
        this.SCALE = scale;
        this.CENTRE_X = centreX;
        this.CENTRE_Y = centreY;

        this.shapeCoords = ORIGINAL_COORDS.clone();

        adjustShape(scale, centreX, centreY);
        //Resize based on the scale
        //adjustSize(scale);

        // initialize vertex byte buffer for shape coordinates
        ByteBuffer bb = ByteBuffer.allocateDirect(
        // (# of coordinate values * 4 bytes per float)
                shapeCoords.length * 4);
        bb.order(ByteOrder.nativeOrder());
        vertexBuffer = bb.asFloatBuffer();
        vertexBuffer.put(shapeCoords);
        vertexBuffer.position(0);

        // initialize byte buffer for the draw list
        ByteBuffer dlb = ByteBuffer.allocateDirect(
                // (# of coordinate values * 2 bytes per short)
                DRAW_ORDER.length * 2);
        dlb.order(ByteOrder.nativeOrder());
        drawListBuffer = dlb.asShortBuffer();
        drawListBuffer.put(DRAW_ORDER);
        drawListBuffer.position(0);

        // prepare shaders and OpenGL program
        int vertexShader = MyGLRenderer.loadShader(
                GLES20.GL_VERTEX_SHADER,
                vertexShaderCode);
        int fragmentShader = MyGLRenderer.loadShader(
                GLES20.GL_FRAGMENT_SHADER,
                fragmentShaderCode);

        mProgram = GLES20.glCreateProgram();             // create empty OpenGL Program
        GLES20.glAttachShader(mProgram, vertexShader);   // add the vertex shader to program
        GLES20.glAttachShader(mProgram, fragmentShader); // add the fragment shader to program
        GLES20.glLinkProgram(mProgram);                  // create OpenGL program executables
    }

    //Adjust the original scale of the shape and position
    private void adjustShape(float scale, float centreX, float centreY) {
        for (int i = 0; i < shapeCoords.length; i++) {
            //Apply the scale
            shapeCoords[i] = (ORIGINAL_COORDS[i] * scale);

            //Apply the x offset
            shapeCoords[i] += (i % 3 == 0 ? centreX : 0);

            //Apply the y offset
            shapeCoords[i] += (i % 3 == 1 ? centreY : 0);
        }
    }

    /**
     * Encapsulates the OpenGL ES instructions for drawing this shape.
     *
     * @param mvpMatrix - The Model View Project matrix in which to draw
     * this shape.
     */
    public void draw(float[] mvpMatrix) {
        // Add program to OpenGL environment
        GLES20.glUseProgram(mProgram);

        // get handle to vertex shader's vPosition member
        mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");

        // Enable a handle to the triangle vertices
        GLES20.glEnableVertexAttribArray(mPositionHandle);

        // Prepare the triangle coordinate data
        GLES20.glVertexAttribPointer(
                mPositionHandle, COORDS_PER_VERTEX,
                GLES20.GL_FLOAT, false,
                vertexStride, vertexBuffer);

        // get handle to fragment shader's vColor member
        mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");

        // Set color for drawing the triangle
        GLES20.glUniform4fv(mColorHandle, 1, COLOR, 0);

        // get handle to shape's transformation matrix
        mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
        MyGLRenderer.checkGlError("glGetUniformLocation");

        // Apply the projection and view transformation
        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
        MyGLRenderer.checkGlError("glUniformMatrix4fv");

        // Draw the square
        GLES20.glDrawElements(
                GLES20.GL_TRIANGLES, DRAW_ORDER.length,
                GLES20.GL_UNSIGNED_SHORT, drawListBuffer);

        // Disable vertex array
        GLES20.glDisableVertexAttribArray(mPositionHandle);
    }
}

最佳答案

glGetUniformLocation 会发出 GL_INVALID_OPERATION 错误的原因只有两个:因为程序不是程序对象,或者因为它没有成功链接。

我没有看到你实际在哪里的代码test whether glLinkProgram was successful .您永远不会调用 glGetProgramiv(program, GL_LINK_STATUS) 来测试程序是否正确链接。显然,链接在某个时候失败了。

错误处理的一般代码(在 C++ 中)是:

//Link the program.
glLinkProgram(program);

GLint isLinked = 0;
glGetProgramiv(program, GL_LINK_STATUS, &isLinked);
if(isLinked == GL_FALSE)
{
    GLint maxLength = 0;
    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);

    //The maxLength includes the NULL character
    std::vector<GLchar> infoLog(maxLength);
    glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);

    //The program is useless now. So delete it.
    glDeleteProgram(program);

    //Provide the infolog in whatever manner you deem best.
    //Exit with failure.
    return;
}

关于java - OpenGL 2.0 glGetUniformLocation : glError 1282 in draw(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34240137/

相关文章:

java - 如何为 Apache TomEE 设置首选库?

java - 集合排序多项目

安卓工作室 : add virtual folder in gradle

android - LibGDX 如何让标签变大?

android - 在游戏引擎之上构建音乐制作应用程序是否有意义?

java - 让 OpenGL-ES 模板缓冲区工作

iphone - 无法制作完整的帧缓冲区对象 8cd6(iOS,以编程方式创建的 OpenGL View )

java - 通过调用webClient请求出现IllegalStateException

java - 在android中重复本地通知

java - Android studio中POST请求示例