Как я могу прочитать более 4 вершинных данных из массива в OpenGL ES 2.0? - PullRequest
1 голос
/ 02 мая 2019

Я пытаюсь нарисовать точки один рядом друг с другом в OpenGL ES 2.0 из буферов массива с плавающей запятой для положения и цвета вершины, но он может принять только 4 вершины на рисование. Когда я добавляю больше, скажу ему рисовать больше, тогда он будет рисовать только 2 несмежные вершины в массиве. Почему это происходит? Почему я не могу нарисовать более 4 вершин в одном экземпляре? Если я могу, как?


Вот пример. Когда у меня есть 3*4 массив данных, он рисует их так:

. . . ., что сделано правильно.

Если бы я, например, установил 3*6 массив данных, он не рисует 6 точек, он рисует что-то вроде этого:

. .


Большая часть моего кода взята из проекта OpenGL ES Lesson, и я все еще учусь и не совсем понимаю, как выполняются такие вещи, как в onSurfaceCreated.

Вот мой класс OpenGLRenderer:

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

    ...

    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.

                    + "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.
                                                                // 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
                                                                // triangle per fragment.
                    + "void main()                    \n"       // The entry point for our fragment shader.
                    + "{                              \n"
                    + "   gl_FragColor = v_Color;     \n"       // Pass the color directly through the pipeline.
                    + "}                              \n";

    // Load in the vertex shader.
    int vertexShaderHandle = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);

    if (vertexShaderHandle != 0)
    {
        // Pass in the shader source.
        GLES20.glShaderSource(vertexShaderHandle, vertexShader);

        // Compile the shader.
        GLES20.glCompileShader(vertexShaderHandle);

        // Get the compilation status.
        final int[] compileStatus = new int[1];
        GLES20.glGetShaderiv(vertexShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);

        // If the compilation failed, delete the shader.
        if (compileStatus[0] == 0)
        {
            GLES20.glDeleteShader(vertexShaderHandle);
            vertexShaderHandle = 0;
        }
    }

    if (vertexShaderHandle == 0)
    {
        throw new RuntimeException("Error creating vertex shader.");
    }

    // Load in the fragment shader shader.
    int fragmentShaderHandle = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);

    if (fragmentShaderHandle != 0)
    {
        // Pass in the shader source.
        GLES20.glShaderSource(fragmentShaderHandle, fragmentShader);

        // Compile the shader.
        GLES20.glCompileShader(fragmentShaderHandle);

        // Get the compilation status.
        final int[] compileStatus = new int[1];
        GLES20.glGetShaderiv(fragmentShaderHandle, GLES20.GL_COMPILE_STATUS, compileStatus, 0);

        // If the compilation failed, delete the shader.
        if (compileStatus[0] == 0)
        {
            GLES20.glDeleteShader(fragmentShaderHandle);
            fragmentShaderHandle = 0;
        }
    }

    if (fragmentShaderHandle == 0)
    {
        throw new RuntimeException("Error creating fragment shader.");
    }

    // Create a program object and store the handle to it.
    int programHandle = GLES20.glCreateProgram();

    if (programHandle != 0)
    {
        // Bind the vertex shader to the program.
        GLES20.glAttachShader(programHandle, vertexShaderHandle);

        // Bind the fragment shader to the program.
        GLES20.glAttachShader(programHandle, fragmentShaderHandle);

        // Bind attributes
        GLES20.glBindAttribLocation(programHandle, 0, "a_Position");
        GLES20.glBindAttribLocation(programHandle, 1, "a_Color");

        // Link the two shaders together into a program.
        GLES20.glLinkProgram(programHandle);

        // Get the link status.
        final int[] linkStatus = new int[1];
        GLES20.glGetProgramiv(programHandle, GLES20.GL_LINK_STATUS, linkStatus, 0);

        // If the link failed, delete the program.
        if (linkStatus[0] == 0)
        {
            GLES20.glDeleteProgram(programHandle);
            programHandle = 0;
        }
    }

    if (programHandle == 0)
    {
        throw new RuntimeException("Error creating program.");
    }

    // Set program handles. These will later be used to pass in values to the program.
    mMVPMatrixHandle = GLES20.glGetUniformLocation(programHandle, "u_MVPMatrix");
    mPositionHandle = GLES20.glGetAttribLocation(programHandle, "a_Position");
    mColorHandle = GLES20.glGetAttribLocation(programHandle, "a_Color");

    // Tell OpenGL to use this program when rendering.
    GLES20.glUseProgram(programHandle);

}

Рисование точек:

@Override
public void onDrawFrame(GL10 gl) {

    GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);

    Matrix.setIdentityM(mModelMatrix, 0);

    drawPoints();

}

// Like I said, 4 and below works without any issue
private final int vertexesToDraw = 6;

// x, y, z (z being upwards)
private final float[] vertexPosData = {
        0.0f, 0.0f, 0.0f,
        1.0f, 0.0f, 0.0f,
        2.0f, 0.0f, 0.0f,
        3.0f, 0.0f, 0.0f,
        4.0f, 0.0f, 0.0f,
        5.0f, 0.0f, 0.0f
};

// red, green, blue, alpha
private final float[] vertexColorData = {
        1.0f, 0.0f, 0.0f, 1.0f,
        0.0f, 1.0f, 0.0f, 1.0f,
        0.0f, 0.0f, 1.0f, 1.0f,
        1.0f, 0.0f, 0.0f, 1.0f,
        0.0f, 1.0f, 0.0f, 1.0f,
        0.0f, 0.0f, 1.0f, 1.0f
};

FloatBuffer mVertexPos, mVertexColor;

// this gets initialized first
private void setupPoints() {

    mVertexPos = ByteBuffer.allocateDirect(vertexPosData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
    mVertexPos.put(vertexPosData).position(0);
    mVertexPos.position(0);

    mVertexColor = ByteBuffer.allocateDirect(vertexColorData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
    mVertexColor.put(vertexColorData).position(0);
    mVertexColor.position(0);

}

private void drawPoints() {

    GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 3 * vertexesToDraw, mVertexPos);
    GLES20.glEnableVertexAttribArray(mPositionHandle);

    GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, 4 * vertexesToDraw, mVertexColor);
    GLES20.glEnableVertexAttribArray(mColorHandle);

    Matrix.multiplyMM(mMVPMatrix, 0, mViewMatrix, 0, mModelMatrix, 0);
    Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mMVPMatrix, 0);

    GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mMVPMatrix, 0);
    GLES20.glDrawArrays(GLES20.GL_POINTS, 0, vertexesToDraw);

}

1 Ответ

2 голосов
/ 02 мая 2019

5-й параметр glVertexAttribPointer - это смещение в байтах между последовательными общими атрибутами вершин (stride), а не количество элементов в буфере.

Это означает, что дляатрибут типа float (размер с плавающей точкой 4 байта) и с размером кортежа 3 (например, координаты x, y, z), параметр шага должен быть 4 * 3 = 12.
Для атрибута сразмер кортежа 4 (цвет RGBA), параметр шага должен быть 4 * 4 = 16.

GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 3 * 4, mVertexPos);
GLES20.glEnableVertexAttribArray(mPositionHandle);

GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, 4 * 4, mVertexColor);
GLES20.glEnableVertexAttribArray(mColorHandle);

Поскольку вершины плотно упакованы, шага можно установить равным 0. Этоэто особый случай, который предоставляется glVertexAttribPointer.Если stride равен 0, тогда он автоматически рассчитывается по параметру size и type .

GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, mVertexPos);
GLES20.glEnableVertexAttribArray(mPositionHandle);

GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, 0, mVertexColor);
GLES20.glEnableVertexAttribArray(mColorHandle);

Обратите внимание, что при наличии4 атрибута, а затем количество элементов (число значений с плавающей запятой) в буфере совпадают по совпадению с байтовым смещением между последовательными общими атрибутами вершин.Таким образом, 4 вершины работают по совпадению, но 6 вершин не работают.
Размер буфера никогда не устанавливается явно.Когда вызывается glDrawArrays, то включенные атрибуты вершин должны ссылаться на буфер, который достаточно велик, чтобы обеспечить требуемые атрибуты.

...