Этот урок научит вас

  1. Инициализация фигур
  2. Отрисовка фигуры

Вы также должны прочитать

После определения фигур для рисования на OpenGL, вы, вероятно, уже хотите нарисовать их. Рисование фигур на OpenGL ES 2.0 занимает немного больше кода, чем вы можете себе представить, потому что API предоставляет большой контроль над конвейером графической визуализации.

Этот урок объясняет, как рисовать фигуры, которые были определены в предыдущем уроке, используя OpenGL ES 2.0 API.

Инициализация фигур

Прежде чем нарисовать что-либо, необходимо инициализировать и загрузить фигуры, которые вы планируете рисовать. Если структура (оригинальные координаты) фигур, которые вы используете в вашей программе не изменяются в ходе исполнения, вы должны инициализировать их в onSurfaceCreated() методе вашего визуализатора для эффективного использования памяти и обработки.

public void onSurfaceCreated(GL10 unused, EGLConfig config) {
    ...

    // initialize a triangle
    mTriangle = new Triangle();
    // initialize a square
    mSquare = new Square();
}

Отрисовка фигуры

Рисование определенной фигуры, используя OpenGL ES 2.0, требует значительного количества кода, потому что вы должны предоставить много деталей для конвейера визуализации. В частности, необходимо определить следующее:

  • Вершинный шейдер (Vertex Shader) - OpenGL ES графический код для визуализации вершин фигуры.
  • Шейдер фрагментов (Fragment Shader) - OpenGL ES код для визуализации лицевой стороны фигуры, используя цвета или текстуры.
  • Программа - OpenGL ES объект, который содержит шейдеры, которые необходимо использовать для рисования одной или нескольких фигур.

Вам нужен по крайней мере один вершинный шейдер для рисования фигуры и один шейдер фрагментов для заполнения фигуры цветом. Эти шейдеры должны быть корректны, и затем они должны быть добавлены к программе OpenGL ES, которая затем использует их для рисования фигуры. Вот пример того, как определить основные шейдеры, которые можно использовать для рисования фигур:

private final String vertexShaderCode =
    "attribute vec4 vPosition;" +
    "void main() {" +
    "  gl_Position = vPosition;" +
    "}";

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

Шейдеры содержат код на языке OpenGL Shading Language (GLSL), который должен быть скомпилирован до начала их использования в среде OpenGL ES. Для компиляции кода, создайте метод в вашем классе визуализатора:

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;
}

Чтобы нарисовать вашу фигуру, вы должны скомпилировать код шейдеров, добавить их в объект программы OpenGL ES, а затем связать программу. Делайте это в конструкторе вашего рисуемого объекта, чтобы это происходило только один раз.

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

public class Triangle() {
    ...

    int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
    int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

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

На данный момент, вы уже готовы добавить реальные вызовы, которые нарисуют вашу фигуру. Рисование фигур на OpenGL ES требует указания нескольких параметров для указания конвейеру визуализации, что вы хотите сделать и как это рисовать. Поскольку параметры рисования могут варьироваться в зависимости от фигуры, хорошая идея заключается в том, чтобы ваши классы фигур содержали свою собственную логику рисования.

Создайте draw() метод для рисования фигуры. Этот код устанавливает позицию и цветовые значений для вершинного шейдера фигуры и шейдера фрагментов, а затем выполняет функцию рисования.

public void draw() {
    // Add program to OpenGL ES 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);

    // Draw the triangle
    GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, vertexCount);

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

Как только у вас будет весь этот код, отрисовка этого объекта просто требует вызова draw() метода из вашего визуализатора onDrawFrame() метода. Когда вы запустите приложение, оно должно выглядеть примерно так:

Рисунок 1. Треугольник рисуется без проекции или положения камеры.

Есть несколько проблем с этим кодом примера. Прежде всего, он не произведет впечатление на ваших друзей. Во-вторых, треугольник немного сдавленный и меняет форму при изменении ориентации экрана устройства. Причина, по которой фигура искажается связано с тем, что вершины объекта не были исправлены для соблюдения пропорций области экрана, в которой отображается GLSurfaceView . Вы можете решить эту проблему с помощью проекции и положения камеры в следующем уроке.

Наконец, треугольник находится в неподвижном состоянии, что немного скучно. В уроке Добавление движений , вы сделаете вращение этой фигуры, и сделаете более интересным использование графического конвейера OpenGL ES.