Создание ландшафтов для opengl

Ландшафт шаг за шагом.

Автор: Серба Андрей

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

Представление ландшафта, карта высот.

Для представления ландшафта мы будем использовать карту высот.

Карта высот — это двумерный массив значений высот ландшафта, взятых с определенным интервалом. Т.е. мы каждому дискретному значению Х и Y в горизонтальной плоскости сопоставляем высоту.


массив


Графическое представление массива

Создать карту высот можно с помощью графического редактора (прекрасно подойдет Photoshop) или с помощью программ специально для этого предназначенных, например TerraGen. Для создания карты высот в Photoshop’е необходимо выполнить фильтр Clouds, а затем несколько раз фильтр Different clouds. И сохранить полученную картинку как Grayscale файл в формате RAW (в принципе можно использовать другой формат, но об этом поговорим позже). Размер карты может быть произвольный, но удобней использовать квадратную, с размером стороны кратным числу степени двойки: 128х128, 256х256 и т.д.

Будем считать, что на представленных примерах светлые области представляют собой возвышения, соответственно темные — низменность.

Photoshop
TerraGen

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

В примере ландшафт реализован в виде класса Terrain. Приведенный ниже кусочек кода — часть функции Terrain::RenderLandscape() демонстрирует простейшую реализацию процедуры рисования.


Пример (40 кБ)

Раскраска (текстурирование) ландшафта.

Я расскажу о двух способах закраски ландшафта (и во втором случае текстурирования). Это очень краткое объяснение, не затрагивающее множество аспектов, таких как мультитекстурирование, блендинг нескольких текстур, и т.п. Обо всем этом я напишу отдельную статью.

Способ первый — интерполяция цветов.

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

ниже приведен код демонстрирующий рисование треугольника с интерполяцией цветов:

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

Грубо говоря, любая RGB картинка сохраненная, как Raw-файл, может быть использована в качестве карты цветов. Важно заметить, что ширина и высота этих файлов должны быть равными размеру карты высот!

Как известно в RGB режиме одна точка изображения описывается тремя байтами — значение Red, Green, Blue компоненты цвета. Таким же образом точки картинки хранятся и в Raw-файле.

Хранить карту цветов (как и карту высот) мы будем в массиве, только в карте высот одному элементу массива соответствует одно значение высоты, а в карте цветов три значения — интенсивность красной, зеленой и синей составляющей цвета. Поэтому введем следующую структуру, которая и будет элементом массива цветов:

При этом процедура рисования (я убрал рисование «проволочной» модели) претерпела минимальные изменения:

Способ второй — текстурирование.

Суть второго способа состоит в наложении на ландшафт текстуры. Для этого нам понадобится текстура, точно такая же как файл для карты цветов, только сохранить его надо как TGA файл (понятно, что выбор формата — это дело вкуса, но в приведенных мною примерах используются TGA-файлы). Я предполагаю что вы знакомы с текстурирование, и не буду описывать процесс загрузки и создания текстуры в OpenGL.

Размер текстуры, может и не соответствовать размеру карты высот. Например для карты высот 128×128 может быть выбрана текстура размером 64×64 или 512×512 точек. В последнем случае качество буде лучше. На практике достаточно выбрать размер текстуры равный размеру карты высот.

Читайте также:  Как убрать ржавчину с теплицы

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

Итак, прежде чем приступить к текстурированию мы должны определит шаг изменения координат текстуры. Необходимо вычислить значение 1.0/MapSize (MapSize — размер карты высот). И тогда умножая координаты x и y треугольника на этот шаг, мы получим координаты текстуры соответствующие этому треугольнику. Ниже приведен рисунок иллюстрирующий текстурирование, и пример процедуры рисования.

Если вы хотите, чтобы текстура не «растягивалась» на весь ландшафт, а соответствовала определенной его части, необходимо при вычислении шага, вместо 1 подставить нужное вам число, и текстура повториться заданное количество раз.

Шаг изменения координат текстуры объявлен как константа в Terrain.H.

const GLfloat TextureBit = 1.0f/(float)MapSize;
а измененная процедура рисования выглядит следующим образом:

Следует сказать пару слов о фильтрации текстуры. В приведенном примере используется линейная фильтрация, что намой взгляд, является оптимальным вариантом. Фильтрация ближайший сосед (GL_NEAREST) существенно ухудшает качество, в то время как мипмаппинг практически его не улучшает. Использование мипмаппинга будет иметь смысл, если размер текстуры превышает размер ландшафта хотя бы в два раза, или если текстура повторяется.

Оптимизация на уровне OpenGL.

Сразу необходимо заметить, что только оптимизация на уровне OpenGL не может решить проблему производительности в целом. Безусловно, прирост производительности будет но не всегда достаточный. OpenGL оптимизацию необходимо использовать вместе с оптимальным алгоритмом отображения ландшафта. Хотя, если размер карты не превышает 128×128, можно обойтись оптимизацией только на уровне OpenGL.

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

GL_TRIANGLE_STRIP
GL_TRIANGLE_FAN

Правда в примере, я использовал GL_TRINGLE_STRIP

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

1. Активировать массивы с данными, в нашем случае массив вершин и координат текстур (аналогично можно поступить с цветами, нормалями и некоторыми другими атрибутами). Для этого необходимо воспользоваться функцией void glEnableClientState(GLenum Array), где в качестве параметра указать GL_VERTEX_ARRAY, а затем GL_TEXTURE_COORD_ARRAY.

2. Задать параметры данных и массивы для их хранения. Для задания массива и типа вершин служит функция

void glVertexPointer( GLint Size, GLenum Type, GLsizei Stride, void *Ptr )
которая определяет способ хранения и координаты вершин. При этом Size определяет число координат вершины (может быть равен 2, 3, 4), Type определяет тип данных (может быть равен GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE). Иногда удобно хранить в одном массиве другие атрибуты вершины, и тогда параметр Stride задает смещение от координат одной вершины до координат следующей. Если Stride равен нулю, это значит, что координаты расположены последовательно. В параметре Ptr указывается адрес, где находятся данные.

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

void glTexCoordPointer(GLint Size, GLenum Type, GLsizei Stride);

3. Заполнить массивы данными и выполнить отрисовку. Как уже было сказано, рисование выполняется с помощью функции

Источник статьи: http://www.gamedev.ru/articles/?id=30015

AlterVision Антон Резниченко

Создание ландшафта по карте высот (OpenGL)

В своё время попалась мне в руки одна очень интересная задачка — реализация программы, которая строит ландшафты по карте высот. В качестве карты высот можно было бы использовать любое растровое изображение, яркость точки на котором была бы для нас высотой её над поверхностью …
Как известно, Э.Э. Александров никогда не подкидывает неинтересных задачек, что ж, я взялся, кое-что из этого вышло …

Генерация ландшафта по карте высот

Мы реализуем метод построения поверхности по «карте высот». Картой высот называют растровое изображение, на котором интенсивность света определяет высоту точки над некоторым нулевым уровнем.

Все материалы по данному проекту можно скачать отсюда:

В нашем случае мы используем полноцветное изображение bmp. Использование именно полноцветного RGB а не greyscale удобно тем, что мы можем выбирать требуемый цветовой канал для построения поверхности, что даёт возможность кодировать в одном изображении несколько поверхностей. Применение может быть следующим: в игре при построении модели пещеры r-канал используется для построения нижней поверхности — пола, g-канал — для создания потолка пещеры и b-канал для моделирования воды в разных по высоте нишах пещеры.

Читайте также:  Однолетние растения для огорода семенами

Дополнительно, для более удобной демонстрации функции построения поверхностей, мы реализуем некоторые интересные возможности: создание водной поверхности с применением эффекта отражения, добавление «неба» и эффекта тумана, реализация режима обхода карты (с явлением инерции и способностью ходить по воде). Плюс к этому, посвящая Новому году, появился снег, музыка Jingle Bells на фоне и синхронизация 30fps, чтобы это всё не выглядело страшно.

Генерация ландшафта по карте высот

Реализация программ Landscape и Landscape WE (Winter Edition) на языке C++ с использованием функций OpenGL.

Исходный код программы (зимняя версия, как более полная) находится в приложении 1.
В целом, программа работает следующее образом:

Инициализация: на этом этапе происходит создание окна Windows, создание контекста OpenGL, загрузка текстур, загрузка карты высот и создание массива высот, инициализация основных параметров рендеринга, установка начального положения наблюдателя, в зимней версии создаётся снег и включается музыка.

Основной цикл программы: обрабатываются нажатия клавиш, происходит обработка эффекта частиц, перемещения наблюдателя, происходит отрисовка сцены по элементам.

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

Это первый взгляд на функционирование программы. Рассмотрим весь ход программы подробнее. Для начала, определимся с используемыми переменными.

Основная функция построения поверхности применяет следующие переменные и константы:

  • MAP_SIZE — размер создаваемого ландшафта, и соответственно используемого изображения.
  • STEP_SIZE — шаг построения поверхности, равен степени двойки.
  • MAP_CHAN — канал изображения, используемый для построения.
  • SKY_H, WATER_H — высота неба и воды.
  • MN_HEIGHT, MX_HEIGHT — минимальная и максимальная высота поверхности.
  • g_HeightMap — массив высот.

Для реализации обходчика требует создание переменных и констант:

  • MAX_SPEED — максимальная скорость движения.
  • CAM_HEIGHT — высота камеры над землёй.
  • wx, wy, wz — позиция наблюдателя.
  • cx, cy, cz — координаты точки, на которую смотрит наблюдатель
  • yang, xang — углы поворота головы наблюдателя горизонтально и вертикально.
  • wspeed, sspeed — скорости движения вперёд и «стрейфа».
  • MOUSE_SENS — чувствительность мышки.
  • MOUSE_STX, MOUSE_STY — начальные координаты мышки.
  • mmvx, mmvy — сдвиг мышки.

В зимней версии добавлены переменные для реализации снега :

  • SNOW_COUNT — количество снежинок в мире
  • MIN_SNOW_DIST, MAX_SNOW_DIST — максимальная и минимальная дистанция отображения снега
  • SNOW_SPEED — скорость падения снега
  • SNOW_SIZE — размер снежинок
  • snows — массив снежинок структур snow

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

  • g2r — преобразует градусы в радианы
  • randf — случайное число в пределах от 0 до 1.

Основные функции программы:

LoadTextures

Загрузка текстур. Используется массив texname, в котором указаны названия загружаемых текстур. В цикле загружаются изображения, создаются текстуры с линейной фильтрацией и освобождается память. Текстуры будут доступны через массив textures.

LoadHeightFile

Загрузка карты высот. Изначально проверяется наличие файла высот, во избежание ошибок. Файл загружается как изображение. Для получения конкретного значения высоты мы используем указатель на байт. Изначально он устанавливается в первую позицию данных изображения, сдвигается на величину используемого канала изображения. Далее, в цикле значение под указателем помещается в массив высот, указатель сдвигается на три позиции вперёд, индекс увеличивается на единицу. Цикл продолжается до тех пор, пока не будут считаны все данные, то есть пока индекс не дойдет до значения квадрата размера карты. Затем память изображения очищается, и массив высот передаётся для дальнейшего использования.

Height

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

GetGroundHeight

Возвращает значение высоты земли в произвольной точке. Получает на вход ссылку на массив высот и координаты точки.
Функция считывает значения высот в четырёх точках, составляющих квадрат в котором находится требуемая точка, и на основании некоторых формул вычисляет значение высоты в данной точке.
Высоту точки на наклонной плоскости можно определить, если разницу высот между опорными точками домножить на расстояние от одной точки до наблюдателя, деленное на расстояние между опорными точками, прибавив высоту этой точки. Таким образом, мы находим высоты точек на двух параллельных плоскостях, и затем, используя полученные значения, находим результирующую высоту, как среднюю на плоскости, перпендикулярной этим плоскостям.

Читайте также:  Грядка для тыквы с осени

SetVertexColor

Устанавливает тон данной точки ландшафта зависимости от высоты точки над нулевой поверхностью. Цвет устанавливается от 50% серого до 100% белого цвета.

RenderHeightMap

Создаёт ландшафт по массиву высот из квадратных сегментов. На вход функции поступает массив высот.
В двух вложенных циклах осуществляется проход по всему массиву. На каждом проходе строятся 4 точки для каждого конкретного квадрата в пространстве, устанавливается тон точки и накладываются координаты текстур. В зависимость от режима рендеринга карта создаётся из элементов типа QUADS или LINE_STRIP для solid и wireframe режимов соответственно.

RenderWater, RenderSkyBox

Отвечают за вывод плоскостей земли и неба. Функция создаёт плоскость два раза больше ландшафта.
Разница между этими функциями только в используемых текстурах и высоте плоско-сти.

CreateSnow

Заполняет массив снежинок данными. В зависимости от позиции наблюдательность на расстоянии, не превышающем максимальную дистанцию снега, устанавливают «снежинки», имеющие различную высоту над поверхностью, скорость падения и раз-мер.

ProcessSnow

Обрабатывает массив частиц снежинок. Если частица выходит из поля зрения на-блюдателя, она возвращается в поле зрения с противоположной стороны. Если части-ца опускается ниже поверхности земли, то она удаляется и вместо неё создается новая частица в случайной позиции на высоте неба. Если частица находится в «свободном падении», ее высота уменьшается на величину скорости.

DrawSnowOne

Рисует снежинку. Происходит отрисовка плоскости снежинки, параллельно плоско-сти взгляда наблюдателя. В случае, если включено текстурирование снежинок, зада-ются текстурные координаты.

RenderSnow

Выводит снежинки на экран. Функция проходит по массиву снежинок, запуская для каждой отрисовку. Если включено текстурирование снежинок, то сначала отрисовыва-ется маска текстуры, а затем сама снежинка.

InitGL

Инициализует движок OpenGL. Включается текстурирование, устанавливается по-ложение мышки и скрывается курсор, устанавливается тест глубины, цвет фона, вклю-чается туман, добавляется источник света, вызываются функции загрузки текстур и карты высот, устанавливается позиция наблюдателя, включается музыка и создаётся массив частиц снега.

ReSizeGLScene

Изменяет пропорции окна. Сбрасывается текущая матрица перспективы и устанав-ливается новая.

DrawGLScene

Прорисовывает сцену. Сбрасывается текущая проекция и очищается экран.
Изначально обрабатывается движение мышки. После получения и использования сдвигов, они обнуляются, и мышь устанавливается в изначальную позицию.
Далее, происходит обработка позиции наблюдателя, в зависимости от его угла по-ворота yang и скоростей поступательного движения wspeed и стрейфа sspeed. Уста-навливаются координаты вектора взгляда наблюдателя по углам поворота xang и yang и текущей позиции наблюдателя. Эти значения передаются функции gluLookAt и позиционируют наблюдателя.
Основная часть функции отвечает за саму отрисовку сцены. Если не включено от-ражение, то просто отрисовывается сцена вызовом функций рендеринга. Если же от-ражение включено, то сначала отрисовывается перевернутая сцена в буфере шаблона, затем сцена отрисовывается заново с использованием буфера шаблона.

WndProc

Оконная функция Windows, обрабатывающая сообщения. Практически все сообще-ния обрабатываются стандартным образом.
Нажатия на клавиши и отпускание клавиш используют особый обработчик, устанав-ливающий в true/false элементы массива, соответствующие нажатым клавишам.
Обработчик события перемещения мыши задаёт две переменных — сдвиг мыши от изначальной позиции.

WinMain

Основная функция приложения Windows.
В главном цикле программы вызывается функция отрисовки сцены. Мы вызываем её вручную сами, не обрабатывая сообщение WM_PAINT, чтобы обеспечить правильную отрисовку динамической сцены.
Все нажатия клавиш отрабатываются ниже. Клавиши курсора отвечают за переме-щения объекта. При нажатии на них возрастает или убывает значение скорости отно-сительно одной из осей. При отпускании клавиш срабатывает эффект инерции — зна-чение скорости медленно приближаются к нулю.
При нажатии на клавиши W, S, T, R, M активируются или дезактивируются те или иные режимы рендеринга — отрисовка и текстовом снега, режим каркасного отображе-ния ландшафта, музыка и отражение от воды.
Последняя команда отвечает за синхронизацию вывода в 30 кадров в секунду.
Выход из цикла осуществляется при нажатии на клавишу Escape.

Источник статьи: http://www.av13.ru/creative/opengl-landscape-height-map/

Оцените статью