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

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

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

od0 = x - x0 – вектор от левого узла до точки.

od1 = x - x1 – вектор от правого узла до точки.

4.Вычисляем точечные произведения:

os = dot(g0, d0) – точечное произведение для левого узла.

ot = dot(g1, d1) – точечное произведение для правого узла.

5.Интерполируем значения:

of(x) = smoothstep(d0) – функция плавного шага (Smoothstep).

onoise = lerp(s, t, f(x)) – линейная интерполяция между s и t с использованием f(x) в качестве коэффициента интерполяции.

Для многомерного шума (2D, 3D и т.д.) процесс аналогичен, но необходимо учитывать больше узлов решетки и интерполировать значения в нескольких измерениях.

Преимущества шума Перлина:

•Природный вид: Генерируемый шум выглядит более естественным, чем простой белый шум.

•Управляемость: Частота и амплитуда шума могут быть настроены для создания различных эффектов.

•Масштабируемость: Можно легко масштабировать шум для разных уровней детализации.

•Широкое применение: Используется для создания разнообразных эффектов в компьютерной графике, играх, анимации и других областях.

Недостатки шума Перлина:

•Вычислительная сложность: Генерация шума Перлина может быть относительно затратной с вычислительной точки зрения.

•Повторяемость: Хотя шум выглядит случайным, он все же является детерминированным, что может привести к заметным повторениям при использовании на больших масштабах.

•Ограниченная рандомность: Шум Перлина не является истинно случайным, и его структура может быть заметна при внимательном рассмотрении.

Примеры использования:

•Создание текстур: Шум Перлина используется для создания текстур дерева, мрамора, облаков и других природных материалов.

•Генерация ландшафтов: Шум Перлина используется для генерации высот ландшафта, создавая реалистичные горные хребты и долины.

•Анимация: Шум Перлина может быть использован для создания анимации пламени, дыма и других динамических эффектов.

•Процедурная генерация контента: Шум Перлина используется для генерации случайных, но правдоподобных уровней, объектов и других элементов в играх.

52

51

//Вершинный шейдер (простой) attribute vec4 a_Position;

void main() {

gl_Position = a_Position;

}

//Фрагментный шейдер precision mediump float;

uniform float u_Scale; // Scale factor for the noise uniform float u_Offset;

//Simple random function float random(vec2 st) {

return fract(sin(dot(st.xy, vec2(12.9898,78.233))) * 43758.5453123);

}

//Linear interpolation

float lerp(float a, float b, float t) { return a + t * (b - a);

}

//Improved SmoothStep function float smoothStep(float t) {

return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);

}

//2D Value Noise

float valueNoise2D(vec2 st) { vec2 i = floor(st);

vec2 f = fract(st);

//Corners coordinates float a = random(i);

float b = random(i + vec2(1.0, 0.0)); float c = random(i + vec2(0.0, 1.0)); float d = random(i + vec2(1.0, 1.0));

//Smooth the values

vec2 smooth_f = smoothStep(f);

// Interpolate using smooth values

return lerp(lerp(a, b, smooth_f.x), lerp(c, d, smooth_f.x), smooth_f.y);

}

53

52

// Fractal Brownian Motion (FBM) for multiple octaves float fbm(vec2 st, int octaves) {

float value = 0.0; float amplitude = 0.5; float frequency = 1.0; float maxValue = 0.0;

for (int i = 0; i < octaves; i++) {

value += amplitude * valueNoise2D(st * frequency); maxValue += amplitude;

amplitude *= 0.5; // Adjust amplitude for each octave (gain) frequency *= 2.0; // Adjust frequency for each octave (lacunarity)

}

return value / maxValue; // Normalize to [0,1]

}

void main() {

vec2 st = gl_FragCoord.xy/u_Scale+u_Offset; // Normalize coordinates by scale

int octaves = 5;

float noise = fbm(st,octaves);

gl_FragColor = vec4(vec3(noise), 1.0); // Output grayscale noise

}

Основные моменты реализации на GLSL:

•random(vec2 st): Простая функция хеширования для создания псевдослучайных чисел на основе координат st.

•lerp(float a, float b, float t): Функция линейной интерполяции.

•smoothStep(float t): Функция Smoothstep для плавной интерполяции.

•valueNoise2D(vec2 st): Функция для генерации “value noise” –

упрощенного варианта шума Перлина, где вместо градиентов используются случайные значения в узлах решетки.

•fbm(vec2 st, int octaves): Функция Fractal Brownian Motion (FBM), которая суммирует несколько октав шума для создания более детализированного результата.

•main():

o Нормализует координаты фрагмента (gl_FragCoord.xy) в диапазон от

0 до 1.

o Вызывает функцию fbm() для генерации шума.

o Устанавливает цвет фрагмента (gl_FragColor) на основе значения шума.

Шум Перлина – это мощный инструмент для создания реалистичных и интересных визуальных эффектов. Понимание принципов его работы и умение реализовать его в GLSL ES позволит вам создавать впечатляющую графику в ваших OpenGL ES 2.0 приложениях на Kotlin.

54

53

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

Добавьте справочное описание каждой планеты и картинку, которые открываются при выборе планеты.

55

54

Водная гладь

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

Основные методы и техники:

1. Создание поверхности воды:

o Обычно используется плоская сетка, состоящая из множества треугольников. Чем больше треугольников, тем более детализированной будет водная гладь.

oВершины сетки определяют геометрию воды.

2.Волны (Waves):

oСинусоидальные волны: Простейший способ добавить волны – смещать вершины сетки по оси Y (вверх-вниз) с использованием синусоидальных функций. Можно комбинировать несколько

синусоидальных волн с разными амплитудами, частотами и направлениями для создания более сложного волнового паттерна.

oШум Перлина (Perlin Noise): Более реалистичные волны можно создать с помощью шума Перлина (описанного выше). Шум Перлина может использоваться для смещения вершин сетки или для создания карты высот (heightmap), которая затем используется для смещения вершин.

oGerstner Waves (или Trochoidal Waves): Более продвинутый метод, который создает волны, более похожие на реальные волны на воде. Они более сложные в вычислениях, но дают более реалистичный результат.

3.Отражение (Reflection):

oПланарное отражение (Planar Reflection): Простейший способ создать отражение – отрендерить сцену дважды: один раз для вида сверху (как обычно), а второй раз – отраженным видом под поверхностью воды. Отраженное изображение затем используется в

качестве текстуры для поверхности воды. Этот метод подходит только для плоских водных поверхностей.

oКубическое отражение (Cube Map Reflection): Для более сложных отражений, учитывающих кривизну поверхности воды, используются кубические карты. Сначала рендерится сцена в 6 направлениях (внутрь куба), и эти изображения сохраняются в кубической карте. Затем кубическая карта используется для определения цвета отражения для каждого фрагмента поверхности воды.

4.Преломление (Refraction):

oСвет, проходящий через воду, преломляется (изменяет направление). Эффект преломления можно имитировать, используя текстуру, которая содержит изображение того, что находится под

56

55

водой. Эта текстура смещается и искажается в зависимости от волнового паттерна на поверхности воды.

5. Fresnel Effect:

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

oЭффект Френеля реализуется с использованием математической формулы, которая вычисляет коэффициент отражения на основе угла обзора.

6.Блики (Specular Highlights):

oДобавление бликов (specular highlights) на поверхности воды создает эффект солнечных бликов или отражений от других источников света. Интенсивность бликов зависит от угла между вектором отражения света, вектором обзора и шероховатости поверхности воды.

7.Карты нормалей (Normal Maps):

oДля добавления мелких деталей на поверхности воды используются карты нормалей. Карты нормалей – это текстуры, которые содержат информацию о направлении нормалей поверхности. Они позволяют имитировать неровности и шероховатости поверхности без

увеличения количества вершин.

Рассмотрим небольшой пример базовой реализации с синусоидальными волнами:

void main() {

// Simple sine wave displacement

float waveHeight = sin(a_Position.x * 2.0 + u_Time) * 0.1 + sin(a_Position.z * 3.0 + u_Time * 1.5) * 0.1;

vec4 displacedPosition = a_Position + vec4(0.0, waveHeight, 0.0, 0.0); v_Position = displacedPosition.xyz; // Pass vertex position to fragment shader gl_Position = u_MVPMatrix * displacedPosition;

}

// Function to generate the water grid vertices

private fun generateWaterGrid(width: Int, height: Int, size: Float): FloatArray { val numVertices = (width + 1) * (height + 1) * 3 // 3 floats per vertex (x, y, z) val vertices = FloatArray(numVertices)

var index = 0

for (z in 0..height) { for (x in 0..width) {

val xPos = (x.toFloat() / width.toFloat() - 0.5f) * size val zPos = (z.toFloat() / height.toFloat() - 0.5f) * size vertices[index++] = xPos

vertices[index++] = 0f // Y coordinate (initially 0)

57

56

vertices[index++] = zPos

}

}

return vertices

}

Пояснения к коду:

•generateWaterGrid(): Создает массив вершин для плоской сетки воды.

•vertexShaderCode:

o

o o o

u_MVPMatrix: Uniform-переменная для матрицы Model-View- Projection.

a_Position: Атрибут для координат вершин.

u_Time: Uniform-переменная для времени (для анимации волн). Смещает вершины по оси Y с использованием синусоидальных функций, создавая эффект волн.

ov_Position: Передает положение вершины во фрагментный шейдер.

•fragmentShaderCode:

ov_Position: Varying-переменная, полученная из вершинного

шейдера.

oУстанавливает цвет фрагмента на синий, имитируя цвет воды.

•onDrawFrame():

oПередает матрицу MVP и значение времени в шейдеры.

o Рисует сетку воды с использованием glDrawArrays(). o Обновляет значение времени для анимации волн.

Улучшения и дальнейшие шаги:

1.Более реалистичные волны: Замените синусоидальные волны на шум Перлина или Gerstner waves.

2.Отражение и преломление: Реализуйте планарное отражение или кубическое отражение для создания отражений на поверхности воды. Добавьте преломление, чтобы имитировать искажение света, проходящего через воду.

3.Fresnel Effect: Добавьте эффект Френеля для изменения количества отраженного и преломленного света в зависимости от угла обзора.

4.Блики (Specular Highlights): Добавьте specular highlights для создания эффекта солнечных бликов.

5.Карты нормалей (Normal Maps): Используйте карты нормалей для добавления мелких деталей на поверхности воды.

6.Освещение (Lighting): Добавьте реалистичную модель освещения, чтобы вода выглядела более естественно.

7.Пена (Foam): Добавьте пену на гребнях волн и у берегов.

8.Движение камеры: Свяжите параметры волн с движением камеры, чтобы создать ощущение, что вода бесконечна.

Приведем основные моменты в реализации Gerstner Waves:

58

57

//Wave Parameters (Can be passed as uniform arrays) const int NUM_WAVES = 3;

uniform float u_Amplitude[NUM_WAVES]; uniform vec2 u_Direction[NUM_WAVES]; uniform float u_Steepness[NUM_WAVES]; uniform float u_Wavelength[NUM_WAVES];

varying vec3 v_Position; varying vec3 v_Normal;

void main() {

vec4 position = a_Position;

vec3 normal = vec3(0.0, 1.0, 0.0); //Base normal pointing up

for(int i = 0; i < NUM_WAVES; ++i) {

float k = 2.0 * 3.14159 / u_Wavelength[i]; //Wave number float c = sqrt(9.8 / k); //Wave speed (simplified)

vec2 d = normalize(u_Direction[i]); //Wave direction

float f = k * (dot(d, position.xz) - c * u_Time); float a = u_Amplitude[i];

float s = u_Steepness[i];

position.x += d.x * a * cos(f); position.z += d.y * a * cos(f); position.y += a * sin(f);

//Calculate the Tangent and Bi-Tangent vec3 tangent = vec3(

-d.x * d.x * s * a * sin(f), d.x * a * cos(f),

-d.x * d.y * s * a * sin(f)

);

vec3 bitangent = vec3( -d.x * d.y * s * a * sin(f), d.y * a * cos(f),

-d.y * d.y * s * a * sin(f)

);

normal = normalize(cross(bitangent,tangent)); //Recalculate the normal

}

v_Position = position.xyz; v_Normal = normal;

59

58

gl_Position = u_MVPMatrix * position;

}

Ключевые моменты:

•Gerstner Waves: Эта реализация использует Gerstner Waves для более реалистичного смещения вершин. Каждая волна определяется амплитудой, направлением, крутизной и длиной волны.

•Normals: В вершинном шейдере также вычисляются нормали к поверхности воды. Нормали важны для правильного освещения.

•Multiple Waves: Можно комбинировать несколько волн Gerstner для создания более сложного волнового паттерна.

•Lighting: Фрагментный шейдер использует базовую модель освещения для добавления бликов и затенения на поверхность воды.

60

59

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

Замените картинку планеты Нептун на поверхность водной глади с волнами.

61

60

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