Разработка мобильных приложений. Программирование мобильных устройств на языке Kotlin. Учебное пособие для СПО
.pdf
•Dockerfile: Текстовый файл, содержащий инструкции для сборки Docker image. Dockerfile описывает, как создать окружение контейнера, включая установку зависимостей, копирование файлов и настройку параметров запуска приложения.
•Docker Hub (и другие registries): Онлайн-репозиторий для хранения и распространения Docker images. Docker Hub предоставляет как публичные, так и приватные репозитории для обмена образами контейнеров.
Пример Dockerfile (упрощенный):
#Базовый образ
FROM ubuntu:latest
#Установка зависимостей
RUN apt-get update && apt-get install -y python3 python3-pip
#Копирование кода приложения
COPY . /app
#Установка Python зависимостей
WORKDIR /app
RUN pip3 install -r requirements.txt
#Определение команды запуска
CMD ["python3", "app.py"]
Кпреимуществам Docker можно отнести:
•Сокращение времени разработки и развертывания: Docker упрощает процесс развертывания приложений, позволяя разработчикам быстро создавать и тестировать контейнеры на локальных машинах, а затем развертывать их в продакшн без изменений.
•Улучшенная переносимость приложений: Docker обеспечивает согласованное поведение приложений в различных окружениях, упрощая перенос приложений между разными платформами и облаками.
•Повышенная эффективность использования ресурсов: Контейнеры используют ресурсы более эффективно, чем виртуальные машины, что позволяет снизить затраты на инфраструктуру.
•Упрощенное управление микросервисами: Docker идеально подходит для развертывания микросервисных архитектур, позволяя создавать и управлять множеством небольших, независимых сервисов.
•Автоматизация и DevOps: Docker интегрируется с инструментами автоматизации и DevOps, упрощая процессы непрерывной интеграции и непрерывной доставки (CI/CD).
12
11
ПРАКТИЧЕСКАЯ РАБОТА 1
При первом запуске справочника на устройстве отображается окно для показа рекламы/новостей. В приложении имеется 10 новостей (заданы константно, содержание произвольное). Экран поделен на 4 четверти, в каждой из которых представлена новость. Четверть поделена на 2 части (90%, 10%): первая – новость, вторая – количество лайков (увеличиваются по нажатию). Каждые 5 секунд одна из новостей на экране заменяется на случайную из имеющегося набора. Реализация должна быть выполнена с применением библиотеки Jetpack Compose и ViewModel.
13
12
OpenGL ES 1.0.
OpenGL ES 1.0 – это версия OpenGL для встраиваемых систем. Несмотря на то, что она устарела, понимание ее принципов важно, так как многие базовые концепции OpenGL остались неизменными. В этом разделе мы рассмотрим основные концепции OpenGL ES 1.0 и предоставим примеры кода на Kotlin, чтобы показать, как их можно использовать на практике.
•Состояние OpenGL: OpenGL ES 1.0 является машиной состояний. Это значит, что его поведение определяется текущими значениями его многочисленных переменных состояния. Эти состояния влияют на то, как отрисовываются объекты, как обрабатываются текстуры и как применяется освещение.
•Конвейер отрисовки (Rendering Pipeline): Процесс отрисовки графики в OpenGL ES 1.0 можно представить как конвейер, состоящий из следующих этапов:
oВвод вершин (Vertex Input): Данные о вершинах (позиции, цвета, нормали, текстурные координаты) передаются в OpenGL.
oПреобразования (Transformations):
▪Модельно-видовая матрица (Modelview Matrix):
Преобразует координаты объектов из модельного пространства в видовое пространство (относительно камеры).
▪Матрица проекции (Projection Matrix): Преобразует координаты из видового пространства в пространство
o
o
o
отсечения (clip space), определяя перспективу и поле зрения. Освещение (Lighting): Вычисление цвета каждой вершины на основе источников света, свойств материала и нормалей. Отсечение (Clipping): Отбрасывание частей геометрии, находящихся за пределами видимого объема.
Растеризация (Rasterization): Преобразование геометрических примитивов (треугольников, линий, точек) в фрагменты (пиксели).
oТекстурирование (Texturing): Применение текстур к фрагментам, определяя их цвет и детализацию.
o Тестирование глубины (Depth Testing): Сравнение глубины каждого фрагмента с глубиной уже отрисованных пикселей в буфере глубины (Z-Buffer). Если новый фрагмент ближе, он заменяет старый.
oСмешивание (Blending): Комбинирование цвета нового фрагмента с цветом пикселя, уже находящегося в цветовом буфере.
•Буферы (Buffers): OpenGL использует буферы для хранения данных:
oЦветовой буфер (Color Buffer): Хранит информацию о цвете каждого пикселя.
oБуфер глубины (Depth Buffer): Хранит информацию о глубине каждого пикселя.
14
13
oБуфер трафарета (Stencil Buffer): Используется для расширенных операций трафаретной отрисовки.
II.Работа с OpenGL ES 1.0 на Kotlin (Android)
Для работы с OpenGL ES 1.0 на Android вам потребуется:
1.SurfaceView и GLSurfaceView: SurfaceView – это базовый класс для отображения графики. GLSurfaceView – это подкласс SurfaceView, предоставляющий удобный интерфейс для работы с OpenGL.
2. |
Renderer: Класс, |
реализующий интерфейс GLSurfaceView.Renderer, |
|
который содержит методы для инициализации OpenGL (onSurfaceCreated), |
|
|
изменения размеров экрана (onSurfaceChanged) и отрисовки кадра |
|
|
(onDrawFrame). |
|
3. |
OpenGL ES |
API: Использование классов и функций из |
пакета android.opengl для отправки команд OpenGL.
Пример: Простая отрисовка треугольника
import android.content.Context import android.opengl.GLES10 import android.opengl.GLSurfaceView import java.nio.ByteBuffer
import java.nio.ByteOrder import java.nio.FloatBuffer
import javax.microedition.khronos.egl.EGLConfig import javax.microedition.khronos.opengles.GL10
class MyGLSurfaceView(context: Context) : GLSurfaceView(context) { init {
//Создаем OpenGL ES 1.0 контекст setEGLContextClientVersion(1)
//Устанавливаем renderer для отрисовки setRenderer(MyRenderer())
//Отрисовываем только при изменении данных (оптимизация) renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY
}
}
private class MyRenderer : GLSurfaceView.Renderer {
private lateinit var triangleVertices: FloatBuffer private lateinit var triangleColors: FloatBuffer
init {
// Данные о вершинах треугольника val vertices = floatArrayOf(
0.0f, 0.5f, 0.0f, // Верхняя вершина
-0.5f, -0.5f, 0.0f, // Левая нижняя вершина
15
14
0.5f, -0.5f, 0.0f // Правая нижняя вершина
)
//Цвета для каждой вершины (R, G, B, A) val colors = floatArrayOf(
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 для вершин
triangleVertices = ByteBuffer.allocateDirect(vertices.size * 4).run { order(ByteOrder.nativeOrder())
asFloatBuffer().apply { put(vertices) position(0)
}
}
// Создаем FloatBuffer для цветов
triangleColors = ByteBuffer.allocateDirect(colors.size * 4).run { order(ByteOrder.nativeOrder())
asFloatBuffer().apply { put(colors) position(0)
}
}
}
override fun onSurfaceCreated(gl: GL10, config: EGLConfig?) {
// Устанавливаем цвет фона gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)
}
override fun onSurfaceChanged(gl: GL10, width: Int, height: Int) {
//Устанавливаем viewport (область отрисовки) gl.glViewport(0, 0, width, height)
//Устанавливаем матрицу проекции gl.glMatrixMode(GL10.GL_PROJECTION) gl.glLoadIdentity()
//Здесь можно установить ортографическую или перспективную
проекцию
// gl.glOrthof(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f) // Ортографическая
проекция
gl.glFrustumf(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 10.0f) // Перспективная
проекция
16
15
// Устанавливаем модельно-видовую матрицу gl.glMatrixMode(GL10.GL_MODELVIEW) gl.glLoadIdentity()
gl.glTranslatef(0.0f, 0.0f, -3.0f) // Перемещаем камеру немного назад
GL10.GL_DEPTH_BUFFER_BIT)
// Включаем массив вершин gl.glEnableClientState(GL10.GL_VERTEX_ARRAY) gl.glVertexPointer(3, GL10.GL_FLOAT, 0, triangleVertices)
// Включаем массив цветов gl.glEnableClientState(GL10.GL_COLOR_ARRAY) gl.glColorPointer(4, GL10.GL_FLOAT, 0, triangleColors)
// Рисуем треугольник gl.glDrawArrays(GL10.GL_TRIANGLES, 0, 3)
// Отключаем массивы gl.glDisableClientState(GL10.GL_VERTEX_ARRAY) gl.glDisableClientState(GL10.GL_COLOR_ARRAY)
}
}
• MyGLSurfaceView: Создает GLSurfaceView и |
|
устанавливает MyRenderer в качестве renderer. |
|
• MyRenderer: |
|
o onSurfaceCreated: Инициализирует OpenGL (установка цвета фона). |
|
o onSurfaceChanged: Настраивает viewport и матрицы проекции и |
|
модельно-видовой матрицы. Важно установить правильные |
|
матрицы, чтобы объекты отображались корректно. В данном |
|
примере используется перспективная проекция с камерой, |
|
отодвинутой назад по оси Z. |
|
} |
|
override fun onDrawFrame(gl: GL10) { |
|
// Очищаем буфер цвета и буфер глубины |
|
gl.glClear(GL10.GL_COLOR_BUFFER_BIT |
or |
Пояснения к коду:
oonDrawFrame: Очищает буферы, включает массивы вершин и цветов, устанавливает указатели на данные вершин и цветов, рисует треугольник с помощью glDrawArrays и отключает массивы.
•ByteBuffer: Используется для передачи данных в OpenGL. Важно использовать ByteBuffer.allocateDirect для создания нативных буферов, которые OpenGL может эффективно обрабатывать.
17
16
Работа с текстурами
Чтобы глубже понять процесс наложения текстур в OpenGL ES 2.0, необходимо рассмотреть следующие аспекты:
1. Текстурный конвейер OpenGL.
Процесс наложения текстур в OpenGL можно представить как последовательность шагов в конвейере:
•Загрузка текстуры: Изображение загружается в память GPU и преобразуется в формат, оптимизированный для использования OpenGL.
•Текстурные координаты: Каждой вершине модели назначаются текстурные координаты, которые определяют, какая часть текстуры будет отображена на этой вершине.
•Вершинный шейдер: Вершинный шейдер преобразует координаты вершин и передает текстурные координаты во фрагментный шейдер в качестве varying переменной. Интерполяция varying переменных происходит автоматически между вершинами треугольника.
•Растеризация: Треугольники, определенные вершинами, разбиваются на фрагменты (пиксели).
•Фрагментный шейдер: Фрагментный шейдер получает интерполированные текстурные координаты для каждого фрагмента. Он использует эти координаты для выборки цвета из текстуры с помощью функции texture2D.
•Текстурная выборка (Texture Sampling): Процесс извлечения цвета пикселя из текстуры на основе текстурных координат. Включает в себя:
o Нормализация: Текстурные координаты нормализуются в диапазон
от 0.0 до 1.0.
oФильтрация: Применяются текстурные фильтры для сглаживания текстуры и уменьшения артефактов.
oОбработка границ: Определяется, что делать, если текстурные координаты выходят за пределы текстуры (clamp, repeat, mirrored repeat).
•Фрагментный шейдер (окончательный цвет): Фрагментный шейдер может комбинировать цвет, полученный из текстуры, с другими источниками цвета, такими как освещение или другие текстуры. Окончательный цвет записывается в буфер кадра.
2.Текстурные координаты (UV-координаты):
•Текстурные координаты (обычно обозначаются как u и v) определяют соответствие между вершиной объекта и точкой на текстуре.
•u координата представляет горизонтальную позицию на текстуре (от 0.0 до 1.0, где 0.0 – левый край, а 1.0 – правый край).
•v координата представляет вертикальную позицию на текстуре (от 0.0 до 1.0, где 0.0 – нижний край, а 1.0 – верхний край).
•Правильное назначение текстурных координат критически важно для получения желаемого отображения текстуры на объекте.
18
17
•Разные модели могут требовать разные методы назначения текстурных координат (например, кубические карты для отражений).
3.Текстурные фильтры:
•GL_TEXTURE_MIN_FILTER: Определяет, как текстура фильтруется, когда пиксель на экране покрывает область текстуры, меньшую, чем сам пиксель (текстура кажется меньше, чем она есть).
o GL_NEAREST: Выбирает ближайший пиксель в текстуре. Самый
быстрый, но выглядит блочным.
oGL_LINEAR: Выполняет билинейную фильтрацию (усредняет цвета четырех ближайших пикселей). Выглядит более сглаженным,
чем GL_NEAREST.
oGL_NEAREST_MIPMAP_NEAREST: Выбирает ближайший mipmap
и использует GL_NEAREST для фильтрации.
o
o
GL_LINEAR_MIPMAP_NEAREST: Выбирает ближайший mipmap и
использует GL_LINEAR для фильтрации. GL_NEAREST_MIPMAP_LINEAR: Выбирает два ближайших
mipmap |
и |
линейно |
интерполирует |
между |
ними, |
используя GL_NEAREST для фильтрации каждого. |
|
||||
oGL_LINEAR_MIPMAP_LINEAR: Выбирает два ближайших mipmap
и линейно интерполирует между ними, используя GL_LINEAR для фильтрации каждого (трилинейная фильтрация). Лучшее качество, но медленнее.
•GL_TEXTURE_MAG_FILTER: Определяет, как текстура фильтруется, когда пиксель на экране покрывает область текстуры, большую, чем сам пиксель (текстура кажется больше, чем она есть).
oGL_NEAREST: Выбирает ближайший пиксель в текстуре.
oGL_LINEAR: Выполняет билинейную фильтрацию.
4.Mipmapping:
•Mipmapping – это метод создания серии уменьшенных версий текстуры
(mipmap levels).
•Каждый уровень mipmap представляет собой уменьшенную версию исходной текстуры (обычно в два раза меньше по ширине и высоте).
•OpenGL выбирает наиболее подходящий уровень mipmap для использования в зависимости от расстояния до объекта.
•Mipmapping помогает уменьшить артефакты алиасинга (мерцание) и улучшить качество рендеринга текстур на большом расстоянии.
• Mipmaps |
генерируются |
автоматически |
с |
помощью |
функции glGenerateMipmap(GL_TEXTURE_2D). |
|
|
||
5.Текстурные юниты:
•OpenGL поддерживает несколько текстурных юнитов. Это позволяет
использовать несколько текстур одновременно в одном шейдере.
• Текстурные юниты адресуются с помощью GL_TEXTURE0, GL_TEXTURE1, GL_TEXTURE2и т.д.
19
18
•Чтобы использовать текстурный юнит, необходимо его активировать с помощью glActiveTexture(GL_TEXTURE0) и привязать к нему текстуру с помощью glBindTexture(GL_TEXTURE_2D, textureId).
•В фрагментном шейдере необходимо указать, какой текстурный юнит использовать для выборки текстуры, с помощью uniform переменной типа sampler2D.
6.Обработка границ текстур (Texture Wrapping):
•Определяет, что делать, если текстурные координаты выходят за пределы текстуры (значения меньше 0.0 или больше 1.0).
•GL_TEXTURE_WRAP_S: Определяет, как текстура обертывается по горизонтали (u-координата).
•GL_TEXTURE_WRAP_T: Определяет, как текстура обертывается по вертикали (v-координата).
•Возможные значения:
o GL_REPEAT: Текстура повторяется.
oGL_MIRRORED_REPEAT: Текстура повторяется, но зеркально отображается на каждом повторении.
oGL_CLAMP_TO_EDGE: Цвет края текстуры используется для заполнения области за пределами текстуры.
7.Uniform переменные:
•Uniform переменные используются для передачи данных в шейдеры из приложения.
•Для работы с текстурами используются следующие uniform переменные:
osampler2D: Тип uniform переменной, представляющий текстурный сэмплер. Используется для указания текстурного юнита, из которого нужно выбирать текстуру.
o Матрицы Model-View-Projection (MVP): Используются для преобразования координат. Влияют на то, как текстура “приклеивается” к поверхности.
8.Оптимизация:
•Использование текстурных атласов: Объединение нескольких текстур в одну большую текстуру (текстурный атлас) может улучшить производительность, уменьшив количество переключений текстур.
•Сжатие текстур: Использование сжатых текстурных форматов (например, ETC1, ETC2) может уменьшить размер текстур и ускорить загрузку и отрисовку.
•Оптимизация шейдеров: Убедитесь, что ваши шейдеры оптимизированы для производительности. Избегайте сложных вычислений и неиспользуемого кода.
•Минимизация переключений текстур: Переключение текстур – дорогая операция. Постарайтесь минимизировать количество переключений текстур в каждом кадре.
9.Проблемы и решения:
•Aliasing (ступенчатость): Можно уменьшить с помощью mipmapping и фильтрации.
20
19
•Текстурные артефакты (мерцание): Может быть вызвано недостаточной фильтрацией или неправильным выбором mipmap.
•Искажение текстур: Может быть вызвано неправильными текстурными координатами или матрицами преобразования.
•Низкая производительность: Может быть вызвана большими текстурами, сложными шейдерами или частыми переключениями текстур.
precision mediump float; varying vec2 v_TexCoord;
uniform sampler2D u_Texture0; // Первая текстура uniform sampler2D u_Texture1; // Вторая текстура
void main() {
vec4 color0 = texture2D(u_Texture0, v_TexCoord); vec4 color1 = texture2D(u_Texture1, v_TexCoord);
// Смешиваем цвета двух текстур
gl_FragColor = mix(color0, color1, 0.5); // Смешиваем цвета 50/50
}
В этом примере используются два текстурных юнита (u_Texture0 и u_Texture1). В коде Kotlin вам нужно будет:
1.Загрузить две разные текстуры.
2.Активировать GL_TEXTURE0 и привязать к нему первую текстуру.
3.Активировать GL_TEXTURE1 и привязать к нему вторую текстуру.
4. Получить location uniform переменных u_Texture0 и u_Texture1 и
установить их значения на 0 и 1 соответственно (указывая, что они
соответствуют |
текстурным |
юнитам |
0 |
и |
1). glUniform1i(glGetUniformLocation(program, |
"u_Texture0"), |
|||
0);glUniform1i(glGetUniformLocation(program, "u_Texture1"), 1);
Понимание этих теоретических аспектов позволит вам более эффективно использовать текстуры в OpenGL ES 2.0 и создавать более качественные и производительные приложения.
21
20
