Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Разработка мобильных приложений. Программирование мобильных устройств на языке Kotlin. Учебное пособие для СПО

.pdf
Скачиваний:
0
Добавлен:
12.08.2026
Размер:
955 Кб
Скачать
☆

Масштабирование (проекция)

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

Проекция. Это преобразование корректирует координаты нарисованных объектов в зависимости от ширины и высоты GLSurfaceView , в котором они отображаются. Без этого расчета объекты, нарисованные OpenGL ES, искажаются из-за неравных пропорций окна просмотра. Преобразование проекции обычно необходимо рассчитывать только тогда, когда пропорции представления OpenGL устанавливаются или изменяются в методе onSurfaceChanged() вашего средства визуализации.

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

камеры

может

 

рассчитываться

только

один

раз,

когда

вы

устанавливаете GLSurfaceView , или

может

меняться динамически

в

зависимости от действий пользователя или функции вашего приложения.

 

Данные

для

преобразования

проекции

рассчитываются

в

методе onSurfaceChanged() вашего класса GLSurfaceView.Renderer . Следующий пример кода принимает высоту и ширину GLSurfaceView и использует их для

заполнения

Matrix

преобразования

проекции

с

помощью

метода Matrix.frustumM() :

 

 

 

 

// vPMatrix is an abbreviation for "Model View Projection Matrix"

 

 

private val vPMatrix = FloatArray(16)

 

 

 

private val projectionMatrix = FloatArray(16)

 

 

 

private val viewMatrix = FloatArray(16)

 

 

 

override fun onSurfaceChanged(unused: GL10, width: Int, height: Int) { GLES20.glViewport(0, 0, width, height)

val ratio: Float = width.toFloat() / height.toFloat()

//this projection matrix is applied to object coordinates

//in the onDrawFrame() method Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1f, 1f, 3f, 7f)

}

// vPMatrix is an abbreviation for "Model View Projection Matrix" private final float[] vPMatrix = new float[16];

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

22

21

@Override

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

float ratio = (float) width / height;

//this projection matrix is applied to object coordinates

//in the onDrawFrame() method Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);

}

Этот код заполняет матрицу проекции mProjectionMatrix, которую затем можно объединить с преобразованием вида камеры в методе onDrawFrame(), который показан в следующем разделе.

Чтобы использовать комбинированную матрицу преобразования проекции и вида камеры, показанную в разделах предварительного просмотра, сначала добавьте переменную матрицы в вершинный шейдер, ранее определенный в классе Triangle:

class Triangle {

private val 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;" + "}"

// Use to access and set the view transformation private var vPMatrixHandle: Int = 0

...

}

23

22

// vPMatrix is an abbreviation for "Model View Projection Matrix" private val vPMatrix = FloatArray(16)

private val projectionMatrix = FloatArray(16) private val viewMatrix = FloatArray(16)

override fun onSurfaceChanged(unused: GL10, width: Int, height: Int) { GLES20.glViewport(0, 0, width, height)

val ratio: Float = width.toFloat() / height.toFloat()

//this projection matrix is applied to object coordinates

//in the onDrawFrame() method Matrix.frustumM(projectionMatrix, 0, -ratio, ratio, -1f, 1f, 3f, 7f)

}

Этот код заполняет матрицу проекции mProjectionMatrix, которую затем можно объединить с преобразованием вида камеры в методе onDrawFrame(), который показан в следующем разделе.

Завершите процесс преобразования нарисованных объектов, добавив преобразование вида камеры как часть процесса рисования в средстве визуализации. В следующем примере кода преобразование вида камеры рассчитывается с помощью метода Matrix.setLookAtM(), а затем объединяется с ранее рассчитанной матрицей проекции. Объединенные матрицы преобразования затем передаются в нарисованную фигуру.

override fun onDrawFrame(unused: GL10) {

...

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

//Calculate the projection and view transformation Matrix.multiplyMM(vPMatrix, 0, projectionMatrix, 0, viewMatrix, 0)

//Draw shape

triangle.draw(vPMatrix)

24

23

ПРАКТИЧЕСКАЯ РАБОТА 2

Сделать классы OpenGL квадрат, куб и отобразить их на экране. На квадрат наложить текстуру галактики / звездного неба. Отодвинуть и отмасштабировать квадрат так, чтобы он воспринимался как фоновое изображение. Куб должен располагаться по центру экрана.

25

24

Вращение фигур

В OpenGL ES 1.0 (фиксированный конвейер) вращение фигур осуществляется с использованием матриц преобразования. Поскольку это фиксированный конвейер, у нас нет шейдеров для непосредственного управления преобразованием координат. Вместо этого мы используем функции OpenGL для управления матрицей моделирования (Model Matrix). Матрица моделирования определяет положение, ориентацию и масштаб объекта в мировом пространстве. Разберем ключевые понятия.

Матрица моделирования (Model Matrix). Матрица 4x4, представляющая преобразование объекта из его локальной системы координат в мировую систему координат.

Стек матриц (Matrix Stack). В OpenGL ES 1.0 используется стек матриц для управления матрицами преобразования. Мы можем помещать матрицы в стек, умножать текущую матрицу на новую матрицу и извлекать матрицы из стека.

glRotatef(angle, x, y, z). Функция OpenGL, которая создает матрицу вращения вокруг указанной оси и умножает ее на текущую матрицу моделирования.

o angle: Угол поворота в градусах.

o x, y, z: Компоненты вектора, определяющего ось вращения.

Алгоритм реализации вращения:

1.Выбор режима матрицы. Указываем, что мы хотим работать с матрицей моделирования с помощью glMatrixMode(GL10.GL_MODELVIEW).

2.Сброс матрицы. Загружаем единичную матрицу, чтобы убрать все

предыдущие

преобразования.

Это

можно

сделать

с

помощью glLoadIdentity(). Очень

важно!

Не сбросив

матрицу,

вы

продолжите накапливать вращения и другие преобразования, что приведет

к непредсказуемым результатам.

3.Выполнение вращения. Вызываем функцию glRotatef() для выполнения вращения.

4.Отрисовка фигуры. После выполнения вращения рисуем фигуру. OpenGL использует текущую матрицу моделирования для преобразования координат вершин фигуры.

override fun onSurfaceCreated(gl: GL10, config: EGLConfig) { gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f) gl.glEnable(GL10.GL_DEPTH_TEST) // Включаем тест глубины

gl.glEnableClientState(GL10.GL_VERTEX_ARRAY) // Включаем использование массива вершин

gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer)

gl.glEnableClientState(GL10.GL_COLOR_ARRAY) // Включаем

26

25

использование массива цветов

gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer)

}

override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) { gl.glViewport(0, 0, width, height) gl.glMatrixMode(GL10.GL_PROJECTION)

gl.glLoadIdentity()

val ratio = width.toFloat() / height

GLU.gluPerspective(gl, 45.0f, ratio, 0.1f, 100.0f) // Перспективная

проекция

}

override fun onDrawFrame(gl: GL10) { gl.glClear(GL10.GL_COLOR_BUFFER_BIT or

GL10.GL_DEPTH_BUFFER_BIT) // Очищаем буфер цвета и глубины

gl.glMatrixMode(GL10.GL_MODELVIEW) // Указываем, что работаем с матрицей моделирования

gl.glLoadIdentity() // Загружаем единичную матрицу (сброс) gl.glTranslatef(0.0f, 0.0f, -6.0f) // Отдаляем куб от камеры gl.glRotatef(angle, 1.0f, 1.0f, 0.0f) // Вращаем куб вокруг оси (1, 1, 0)

// Рисуем куб с использованием индексов gl.glDrawElements(GL10.GL_TRIANGLES, indices.size,

GL10.GL_UNSIGNED_BYTE, indexBuffer)

angle += 1.0f // Увеличиваем угол для анимации

}

}

Kotlin

Впрограмме выше:

•MyGLRenderer: Класс, реализующий GLSurfaceView.Renderer, отвечает за отрисовку графики.

•angle: Переменная, хранящая угол поворота.

•vertices, colors, indices: Массивы данных для куба (вершины, цвета, индексы для отрисовки). Вам нужно будет адаптировать эти данные для вашей фигуры.

•vertexBuffer, colorBuffer, indexBuffer: Буферы для хранения данных вершин, цветов и индексов. OpenGL работает с данными, находящимися в буферах.

27

26

•onSurfaceCreated(): Инициализация OpenGL и буферов.

•onSurfaceChanged(): Настройка проекции (perspective).

•onDrawFrame():

o gl.glClear(): Очищает буфер цвета и глубины.

o gl.glMatrixMode(GL10.GL_MODELVIEW): Устанавливает режим матрицы в “модель-вид” (матрица моделирования).

o gl.glLoadIdentity(): Ключевой момент! Загружает единичную матрицу, сбрасывая предыдущие преобразования.

ogl.glTranslatef(): Перемещает объект в пространстве (чтобы его было видно, т.к. камера находится в точке (0,0,0)).

ogl.glRotatef(): Выполняет вращение. angle определяет угол, а 1.0f, 1.0f, 0.0f – ось вращения.

o gl.glDrawElements(): Рисует куб с использованием индексированного рисования.

o angle += 1.0f: Увеличивает угол поворота для анимации.

Важные моменты:

•Ось вращения: Вращение происходит вокруг оси, проходящей через начало координат (0, 0, 0). Если вы хотите вращать объект вокруг другой точки, вам нужно сначала переместить объект так, чтобы эта точка совпадала с началом координат, затем выполнить вращение, а затем переместить объект обратно.

•Порядок преобразований: Порядок, в котором выполняются преобразования, имеет значение. В коде выше сначала выполняется перемещение, а затем вращение. Это означает, что объект сначала перемещается на -6.0f по оси Z, а затем вращается вокруг оси, проходящей через начало координат.

•Система координат: OpenGL использует правую систему координат.

•Производительность: OpenGL ES 1.0 (фиксированный конвейер) менее гибок и менее оптимизирован, чем OpenGL ES 2.0 (программируемый

конвейер). В OpenGL ES 2.0 вы можете использовать шейдеры для более эффективного управления преобразованиями.

• Использование GLSurfaceView: Этот код предназначен для использования в GLSurfaceView в Android.

Альтернативные способы вращения:

•Использование кватернионов: Кватернионы – это математический способ представления вращения, который может быть более эффективным и стабильным, чем использование углов Эйлера (как в glRotatef). Однако реализация с использованием кватернионов сложнее.

28

27

Стереометрия

Стереометрия в OpenGL ES 1.0 на Kotlin подразумевает построение и отображение трехмерных объектов в двумерном пространстве экрана. Поскольку OpenGL является графической библиотекой, ориентированной на работу с примитивами, понимание трехмерной геометрии и ее преобразование в 2D проекцию является ключевым.

 

Основные концепции стереометрии в OpenGL ES 1.0:

1.

Вершины (Vertices):

 

o Основной строительный блок для представления 3D-объектов.

 

o Представляют собой точки в трехмерном пространстве, заданные

 

координатами (x, y, z).

 

o В OpenGL ES 1.0 вершины передаются в виде массивов данных

 

(например, FloatBuffer).

2.

Примитивы (Primitives):

 

o Способ соединения вершин для формирования геометрических

 

фигур.

oНаиболее распространенные примитивы:

▪GL_POINTS: Рисует отдельные точки для каждой вершины.

▪GL_LINES: Рисует отдельные линии между каждой парой вершин.

▪GL_LINE_STRIP: Рисует последовательность соединенных линий.

▪GL_LINE_LOOP: Как GL_LINE_STRIP, но замыкает контур,

соединяя последнюю вершину с первой.

▪GL_TRIANGLES: Рисует отдельные треугольники, используя каждую тройку вершин. (Самый распространенный для 3D)

▪GL_TRIANGLE_STRIP: Рисует последовательность соединенных треугольников. (Оптимизированная версия для определенных случаев)

▪GL_TRIANGLE_FAN: Рисует веер треугольников, используя первую вершину как общую для всех треугольников.

3.Индексированное рисование (Indexed Drawing):

oСпособ оптимизации отрисовки, особенно для сложных моделей, содержащих общие вершины.

oИспользуется массив индексов, указывающий порядок использования вершин для формирования примитивов.

oФункция glDrawElements() используется для выполнения индексированного рисования.

4.Цвет (Color):

oКаждой вершине или всему примитиву можно назначить цвет.

oЦвета обычно задаются в формате RGBA (красный, зеленый, синий, альфа), где каждое значение находится в диапазоне от 0.0 до

1.0.

29

28

oВ OpenGL ES 1.0 цвета передаются в виде массивов данных

(например, FloatBuffer).

5.Матрицы преобразований (Transformation Matrices):

oИспользуются для изменения положения, ориентации и масштаба объектов в трехмерном пространстве.

oОсновные типы матриц преобразований:

▪Моделирования (Model Matrix): Преобразует объект из его локальной системы координат в мировую систему координат.

▪Вида (View Matrix): Преобразует мировую систему координат в систему координат камеры (глаза).

▪Проекции (Projection Matrix): Преобразует 3D координаты в 2D координаты экрана.

oВ OpenGL ES 1.0 матрицы преобразований управляются с использованием стека матриц и функций, таких

как glTranslatef(), glRotatef(), glScalef(), glFrustumf(), gluPerspective()

6.Проекция (Projection):

oПроцесс преобразования трехмерных координат в двухмерные

координаты экрана.

oДва основных типа проекций:

▪Перспективная проекция (Perspective Projection): Создает эффект перспективы, где объекты, находящиеся дальше от камеры, кажутся меньше. Используется

функция gluPerspective() или glFrustumf().

▪Ортогональная проекция (Orthographic Projection): Не создает эффект перспективы; объекты сохраняют свой размер независимо от расстояния до камеры. Используется

функция glOrthof().

7.Буфер глубины (Depth Buffer):

oИспользуется для определения, какие объекты находятся ближе к

камере и должны быть отображены поверх других объектов. o Включается с помощью glEnable(GL10.GL_DEPTH_TEST).

oОчищается с помощью glClear(GL10.GL_DEPTH_BUFFER_BIT).

8.Освещение (Lighting): (Необязательно, но важно для реалистичного отображения)

oOpenGL ES 1.0 поддерживает базовые модели освещения, такие как диффузное, зеркальное и окружающее освещение.

oДля работы с освещением необходимо включить освещение

(glEnable(GL10.GL_LIGHTING)) и настроить параметры источников света и материалов.

o Также требуются нормали к поверхностям для расчета освещения (векторы, перпендикулярные поверхности).

Для создания более сложных трехмерных объектов необходимо:

1.Определить вершины, цвета и индексы для объекта.

2.Создать буферы для хранения этих данных.

30

29

3.Использовать glDrawElements() для отрисовки объекта с использованием индексов.

4.Использовать матрицы преобразований для изменения положения, ориентации и масштаба объекта.

5.Настроить освещение для реалистичного отображения.

ПРАКТИЧЕСКАЯ РАБОТА 3

Скройте куб. Добавьте в центр экрана модель солнечной системы. Солнце и вращающиеся планеты. Добавьте вращение Луны перпендикулярно плоскости эклиптики.

31

30

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]