Прежде чем мы начнем показывать вещи, мы должны знать несколько основных понятий трехмерного программирования, а также ознакомиться с терминологией. Я базовая геометрия на самом деле.
3D графика происходит в декартовой системе координат .
Это означает, что используемая система координат имеет три измерения. X , Y и Z
Традиционно X идет слева направо, Y снизу вверх, а Z, так сказать, от меня на экран.
В то время как мы имеем дело с отображаемыми объектами (например, робот или автомобиль), OpenGL имеет дело с компонентами этих объектов. Каждый объект создается из примитивов, которые в случае OpenGL являются треугольниками . У каждого треугольника есть лицо и задняя поверхность .
Треугольник определяется 3 точками в пространстве. Точка называется вершиной ( вершины множественного числа).
Следующая диаграмма показывает 2 вершины. А и Б.
вершины |
Я нарисовал эту диаграмму, чтобы показать, как мы будем различать 2D и 3D. Вершина определяется своими координатами X, Y и Z. Если мы используем 0 для компонента Z все время, у нас есть 2D. Вы можете видеть, что вершина A является частью плоскости, определенной X и Y. Вершина B находится дальше от координаты Z. Если вы думаете о Z как о линии, перпендикулярной экрану, мы даже не увидим B.
Треугольник называется примитивом . Примитив — это самый простой тип, который OpenGL понимает и может представлять графически.
Это очень просто. 3 вершины определяют треугольник. Есть и другие примитивы, такие как квадроциклы, но мы будем придерживаться основ. Каждая фигура может быть разбита на треугольники.
Мы упоминали лицо треугольника раньше.
Почему это важно? В 3D у вас будут объекты с частями, обращенными к вам, игроком и частями, обращенными от вас. Чтобы сделать рисование эффективным, OpenGL не будет рисовать треугольники, обращенные от вас, так как в этом нет необходимости, потому что они все равно будут скрыты треугольниками, обращенными к вам. Это называется отбором задних поверхностей .
Как OpenGL определяет это? Это определяется порядком вершин при рисовании треугольника. Если ордер против часовой стрелки, то это грань (зеленый треугольник). Порядок по часовой стрелке вершин означает, что это задняя сторона (красный треугольник). Это настройка по умолчанию, но, конечно, ее можно изменить. Следующая диаграмма иллюстрирует это.
Выбраковка |
Красный треугольник не будет нарисован.
Создание и рисование треугольника
После того, как вся теория понятна, давайте создадим треугольник и нарисуем его.
Треугольник определяется 3 вершинами. Координаты вершин не измеряются в пикселях. Мы будем использовать float для представления значений, и они будут относительно друг друга.
Если длина стороны равна 1,0f, а длина другой стороны равна 0,5f , то это означает, что вторая сторона равна половине длины первой стороны. Насколько большой он будет отображаться, зависит от того, как настроен видовой экран. Вообразите область просмотра как камеру. Когда мы используем 2D, то это означает, что камера ортогональна к экрану. Если камера находится очень близко, треугольник будет казаться большим, если он далеко, то треугольник будет маленьким.
Давайте создадим класс Triangle .
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
package net.obviam.opengl; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import javax.microedition.khronos.opengles.GL10; public class Triangle { private FloatBuffer vertexBuffer; // buffer holding the vertices private float vertices[] = { - 0 .5f, - 0 .5f, 0 .0f, // V1 - first vertex (x,y,z) 0 .5f, - 0 .5f, 0 .0f, // V2 - second vertex 0 .0f, 0 .5f, 0 .0f // V3 - third vertex }; public Triangle() { // a float has 4 bytes so we allocate for each coordinate 4 bytes ByteBuffer vertexByteBuffer = ByteBuffer.allocateDirect(vertices.length * 4 ); vertexByteBuffer.order(ByteOrder.nativeOrder()); // allocates the memory from the byte buffer vertexBuffer = vertexByteBuffer.asFloatBuffer(); // fill the vertexBuffer with the vertices vertexBuffer.put(vertices); // set the cursor position to the beginning of the buffer vertexBuffer.position( 0 ); } } |
Строка 11 определяет FloatBuffer, который будет содержать вершины для нашего треугольника. Нам нужно использовать пакет java.nio, так как это очень интенсивный ввод.
Массив vertices [] содержит фактические координаты для вершин.
Нарисованный нами треугольник представлен на следующей диаграмме. Мы рассчитываем все от происхождения.
Треугольник |
В конструкторе мы инициализируем треугольник из этого массива vertices [] .
Что мы делаем, мы заполняем vertexBuffer координатами и устанавливаем позицию курсора в начало буфера. Мы будем использовать этот буфер в вызове OpenGL для отображения треугольных полос. В настоящее время у нас есть только один.
Давайте посмотрим на рендер. GlRenderer
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
package net.obviam.opengl; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; import android.opengl.GLU; import android.opengl.GLSurfaceView.Renderer; public class GlRenderer implements Renderer { private Triangle triangle; // the triangle to be drawn /** Constructor */ public GlRenderer() { this .triangle = new Triangle(); } @Override public void onDrawFrame(GL10 gl) { // clear Screen and Depth Buffer gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); // Reset the Modelview Matrix gl.glLoadIdentity(); // Drawing gl.glTranslatef( 0 .0f, 0 .0f, - 5 .0f); // move 5 units INTO the screen // is the same as moving the camera 5 units away triangle.draw(gl); // Draw the triangle } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { if (height == 0 ) { //Prevent A Divide By Zero By height = 1 ; //Making Height Equal One } gl.glViewport( 0 , 0 , width, height); //Reset The Current Viewport gl.glMatrixMode(GL10.GL_PROJECTION); //Select The Projection Matrix gl.glLoadIdentity(); //Reset The Projection Matrix //Calculate The Aspect Ratio Of The Window GLU.gluPerspective(gl, 45 .0f, ( float )width / ( float )height, 0 .1f, 100 .0f); gl.glMatrixMode(GL10.GL_MODELVIEW); //Select The Modelview Matrix gl.glLoadIdentity(); //Reset The Modelview Matrix } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { } } |
Мы создаем треугольник в конструкторе.
OnDrawFrame (GL10 gl) представляет для нас наибольший интерес.
OpenGL работает с переменными состояния. Каждый метод, который мы вызываем в контексте OpenGL, меняет свое внутреннее состояние.
Следуя методу onDrawFrame, мы видим, что каждый раз, когда рисуется кадр, буферы очищаются, матрица ModelView перезагружается (не беспокойтесь, если вы не понимаете этого в данный момент), камера отодвигается на 5 единиц (мы Здесь мы имеем дело с единицами измерения, а не с пикселями), и вызывается метод draw () треугольника.
С другой стороны, onSurfaceChanged переводит контекст OpenGL между несколькими состояниями. Сначала он устанавливает в окне просмотра текущую ширину и высоту поверхности (так что он работает с состоянием GL_PROJECTION ), затем он переводит состояние в GL_MODELVIEW, чтобы мы могли работать с нашими моделями — в нашем случае с треугольником. Это будет иметь смысл позже, не волнуйтесь.
Давайте проверим метод рисования для треугольника:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
public void draw(GL10 gl) { gl.glEnableClientState(GL10.GL_VERTEX_ARRAY); // set the colour for the triangle gl.glColor4f( 0 .0f, 1 .0f, 0 .0f, 0 .5f); // Point to our vertex buffer gl.glVertexPointer( 3 , GL10.GL_FLOAT, 0 , vertexBuffer); // Draw the vertices as triangle strip gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0 , vertices.length / 3 ); //Disable the client state before leaving gl.glDisableClientState(GL10.GL_VERTEX_ARRAY); } |
Поскольку мы храним координаты вершин треугольника в FloatBuffer, нам нужно разрешить OpenGL читать из него и понимать, что это треугольник. Строка 02 делает именно это.
Линия 05 устанавливает цвет для сущности (в нашем случае треугольник), которая будет нарисована. Обратите внимание, что значения rgb являются числами с плавающей точкой и находятся в диапазоне от 0,0 до 1,0.
gl.glVertexPointer (3, GL10.GL_FLOAT, 0, vertexBuffer); скажет OpenGL использовать vertexBuffer для извлечения вершин из.
Первый параметр (значение = 3) представляет количество вершин в буфере. Второй позволяет OpenGL знать, какой тип данных содержит буфер.
Третий параметр — это смещение в массиве, используемом для вершин. Поскольку мы не храним дополнительные данные, наши вершины следуют друг за другом и смещения нет.
Наконец, последний параметр — наш буфер, содержащий вершины.
gl.glDrawArrays (GL10.GL_TRIANGLE_STRIP, 0, vertices.length / 3); говорит OpenGL рисовать треугольные полосы, найденные в ранее предоставленном буфере, начиная с первого элемента. Он также позволяет узнать, сколько существует вершин.
Вот и все. Запустите проект, и вы сможете увидеть свой первый ускоренный треугольник. Именно так:
Загрузите источник здесь (obviam.opengl.p02.tgz) :
Я был вдохновлен кодом из портов nehe android . Чтобы изучить принципы OpenGL, я настоятельно рекомендую эти руководства .
Далее мы увидим, как мы можем создавать базовые 3D-объекты и вращать их. Мы также узнаем, как мы можем использовать текстуры на элементах.
Справка: OpenGL ES Android — отображение графических элементов (примитивов) от нашего партнера по JCG Тамаса Яно из блога « Против зерна ».
- Введение в разработку игр для Android Введение
- Разработка игр для Android — Идея игры
- Разработка игр для Android — Создать проект
- Разработка игр для Android — базовая игровая архитектура
- Разработка игр для Android — основной игровой цикл
- Разработка игр для Android — Отображение изображений с Android
- Разработка игр для Android — перемещение изображений на экране
- Разработка игр для Android — The Game Loop
- Разработка игр для Android — Измерение FPS
- Разработка игр для Android — Sprite Animation
- Разработка игр для Android — Particle Explosion
- Разработка игр для Android — Дизайн игровых объектов — Стратегия
- Разработка игр для Android — Использование растровых шрифтов
- Разработка игр для Android — переход с Canvas на OpenGL ES
- Разработка игр для Android — OpenGL Texture Mapping
- Разработка игр для Android — Дизайн игровых сущностей — Государственный паттерн
- Серия игр для Android