Feed the Multiverse – Tiffany Munro s Fantasy Maps and World Building

ТОП-10 лучших редакторов
для рисования на компьютере

4.0 Оценок: 10 (Ваша: )

Хотите всерьез заняться цифровой живописью? Ищете подходящий софт? Тогда ознакомьтесь с этой статьей: в ней мы рассмотрели лучшие компьютерные программы для рисования и постарались определить их особенности. Помните главное: ваш редактор – это холст, на котором вы будете творить. Поэтому неважно насколько софт крут и напичкан функциями — важнее всего, чтобы он соответствовал вашим индивидуальным запросам как художника.

Free fantasy Country and Continent Map generators

Example of Agazaar fantasy map generator result with customizations

azgaar-demo

Randomly generated result with a couple of extra options selected.

Azgaar’s Fantasy Map Generator – creates colored world map bases. Someone could use this to create a zoomed out world map or country base. As for how to use Agazaar’s fantasy map generator, I have not determined if it is possible to freehand draw any shapes, but the menu button on the left contains a wide variety of customization options for the generated shape. Clicking on a text label or generated icon will allow you to move it freely and change its options. It also generates random information about the point of interest. This map creator is actively updated and considered one of the best free fantasy country makers, and there’s a subreddit that exists for help on how to use it.

Red Blob Games Map Generator allows you to place land, mountains, water, and ocean on a painted style map, free to download for any use. An exceptionally powerful mapping tool which uses 3D to do both overhead and isometric views. I created this map in mere minutes and was impressed by the potential. I might use this!

mewo2demo

Creation technique is detailed in a manner that may be of interest to programmers on the creator’s website!

Mewo2 Map Editor. This isn’t a single box editor like many of the others, but you scroll through to add bits and build the map through several stages. The procedural process of building the map might work well for some. I found it easy and enjoyable to move through. However, names are limited to automatically generated place names.

beaglemage fantasy map generator lets you create fantasy maps in Python for the geekiest method of map creation

beaglemage fantasy map generator lets you create fantasy maps in Python for the geekiest method of map creation

Beaglemage Fantasy Map Generator – If you’d rather GIT a map than get one, this tool can be downloaded from GitHub, and then you will need to know actual wizard magic, but you can make results like this one. I must disclose: the creator of the program sent me this result, I didn’t actually make it myself. It is Open Source. I took a look at it in Text Wrangler and it looks easy enough to expand the names it generates, and due to how the images are added in, it seems simple enough to change what textures and image assets are pulled. However, what looks much more complicated would be changing say, how the coastlines are generated. For someone with Python knowledge this could be the godsend fantasy map generator of your dreams, though. Ripe and ready to be picked apart and coded into your own personal fantasy map making tool. I admit I really do want to put some of my own textures and trees in and see what happens. One thing I don’t know is how to take the script and actually run it, but if you happen to be a programmer, you know exactly what must be done. Have fun.

Часть 3. Формы суши

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

(Откройте изображение в отдельном окне, чтобы увидеть карту в полном разрешении 4800×2400 во Flickr.)

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

Эта карта — просто хаос из островов и швейцарского сыра суши.

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

Это огромная континентальная масса суши, но тут довольно много странных форм суши, и в целом мир выглядит не совсем «реальным». (Хотя кому-то такой мир покажется вполне подходящим для фэнтези.) Так какие же формы должна иметь карта «мира»?

Большинство виденных мной карт фэнтезийных миров отображают большой островной континент (с небольшими островами вокруг), например такой, как эта карта Анделена:

Или полуостров континента, как на этой карте Ангоруна:

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

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

Я не ожидал большого центрального моря на этой карте, но это приятный сюрприз. Вот ещё один пример:

Проблема функции центрального острова в том, что она начинает с круга, который подходит для показываемых мной квадратных карт, но не очень хорош для прямоугольных. (Ниже показаны примеры с малым количеством искажений, чтобы были чётче видны базовые формы.)

Это легко исправляется маскированием суши вместо круга эллипсом (искажённым), взятым по размерам карты:

Эти центральные острова масштабируются для заполнения карты, но во многих случаях для континентальных карт нам нужно оставить вокруг континента «границу». Два параметра управляют величиной заполнения карты островом по осям X и Y.

Вот та же система управления границей с более логичными искажениями:

Видно, что восточная и западная части карты остаются океаном. (Можете открыть карту в отдельном окне, чтобы изучить её внимательнее.) Это значит, что карта отображает весь мир (и её правый и левый края можно соединить) или часть мира, которую можно присоединить к другой карте, тоже имеющей с соответствующего края океан.

Внимательный читатель, изучивший предыдущую карту, мог заметить, что паттерны океана и суши останавливаются посередине карты. Раньше у меня были карты размером только 1×1, поэтому размеры паттернов океана и суши подогнаны под эти карты. На картах большего размера мне нужно вручную тайлить паттерны по карте, поэтому я добавил эту функцию. (В SVG есть способ выполнения тайлинга паттерна, но в Chrome он содержит баг, поэтому использовать его я не могу.) Это хорошая функция, потому что теперь я могу использовать меньшие паттерны суши и океана, которые будут тайлиться автоматически. Не знаю, почему я не реализовал её раньше!

Итак, теперь островные континенты работают нормально, и мы перейдём к реализации «полуостровных» континентов — карт, в которых континент появляется на карте с её края.

В этом случае континент не может сворачиваться по трём краям. Но основная особенность таких карт в том, что на них существует значительное соединение суши между отображённым на карте континентом и сушей за пределами карты.

Проще всего обеспечить такое соединение вне карты — установить при генерации низкий уровень моря. Так мы увеличим площадь отображаемой на карте суши, что повышает вероятность появления больших масс суши и возникновения суши (а не моря) по краям карты.

Разумеется, это не гарантирует того, что масса суши будет очень интересной, да и вообще окажется единой:

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

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

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

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

Часть 4. Модель ветра

Как и сказал, размер континентов на картах Dragons Abound начал демонстрировать нереалистичные паттерны погоды и биомов. В этом примере видно, что лес выстраивается вдоль преобладающего направления ветра:

Причина не в сломанном коде; скорее, модели погоды и биомов слишком просты, и при большом масштабе это становится очевидным. Чтобы справиться с этими проблемами, я начал с пересмотра модели ветра.

Я хотел бы, чтобы моя модель ветра лучше отражала динамику ветра Земли: ячейки Хэдли, пассаты и тому подобное. Такая динамика может помочь избавиться от странных паттернов погоды на континентальных картах. Однако при их добавлении снова вскрылась мучительная неудовлетворённость моделью ветра Dragons Abound, медленной и слишком переусложнённой. (Прочитать об исходной реализации модели ветра можно здесь.) Подумав об этом несколько дней, я решил, что большинство проблем сводится к тому, что карта игры представлена как диаграмма Вороного. (А точнее триангуляция Делоне диаграммы Вороного.) Она имеет множество преимуществ при генерации рельефа — в сочетании с шумом она может создавать естественно выглядящие массы суши. Именно поэтому её так часто используют для генерации рельефа. Но так как отдельные треугольники имеют разные размеры и ориентацию, любые расчёты, в том числе и модели ветра, использующие воздействующие соседние клетки, становятся довольно сложными. Гораздо проще будет смоделировать ветер через сетку равномерно расположенных одинаковых областей. Кроме того, модель ветра скорее всего не обязана быть такой же детальной, как суша.

Но я не хочу полностью отказываться от диаграммы Вороного, которая лежит в основе Dragons Abound. (Как минимум, это потребует переписывания почти всей программы!) Вместо этого я хочу поэкспериментировать с привязкой карты к равномерной сетке, запустить модель ветра в ней, а затем выполнить обратную привязку. Если потери при копировании туда и обратно будут не слишком велики, то это может сделать модель ветра быстрее и проще.

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

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

Следующий шаг — нужно определить, как представить сетку шестиугольников в моей программе. Я немного поискал в сети подсказки, и каждая ссылка возвращала меня к странице о сетках шестиугольников Амита Патела (перевод на Хабре). Вероятно, с неё и надо начать; неплохо также сначала изучить сайт Red Blob Games, если вы ищете информацию об реализации игровой механики. Амит объясняет лучше, чем я, поэтому если что-то будет непонятно, то прочитайте его страницу.

Первый выбор, который предстоит сделать — способ хранения сетки шестиугольников. Проще всего хранить её как двухмерный массив, то мне нужна возможность привязки ячеек сетки к массиву. Тут есть множество вариантов (прочитайте страницу Амита), но я буду использовать то, что он называет odd-r:

Числа в каждой ячейке представляют собой индексы нахождения ячейки в двухмерном массиве. (Изображение украдено со страницы Амита. На его странице они интерактивны, так что советую поэкспериментировать с ними.)

Сделав выбор, теперь я должен научиться привязывать индексы к сетке шестиугольников. Например, если я ищу шестиугольную ячейку (3, 3), то какими будут её соседи? Если каждая ячейка имеет ширину 5 пикселей, то какими будут координаты центра ячейки (3, 3)? И так далее. Разбираться с этим может оказаться сложно, поэтому я рад, что Амит сделал это за меня.

Предположив, что мы можем своровать всё необходимое у Амита, то мне сначала нужно выяснить, как расположить шестиугольники на карте. На этом этапе мне ещё не нужен массив, я могу притвориться, что он есть и посмотреть, где будут шестиугольники. Если я буду знать расположение шестиугольников, то просто поделю ширину карты на горизонтальное расстояние между ними, чтобы получить количество столбцов, и сделаю то же самое по вертикали, чтобы получить количество строк, после чего отрисую в каждом месте шестиугольник:

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

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

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

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

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

При этом происходит перебор в другую сторону — шестиугольник помечается как суша, если в нём есть любая суша. Что лучше — зависит от того, что вам нужно.

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

Теперь побережье стало гораздо лучше, но возникла новая проблема — множество внутренних шестиугольников, которые не считаются сушей. Такое происходит, потому что когда шестиугольники становятся достаточно маленькими, внутри некоторых вообще не остаётся треугольников Делоне. Поэтому у них нет «высоты». (Это также демонстрирует неравномерность треугольников Делоне.)

Можно использовать такое решение — брать высоту отсутствующих треугольников как среднее от их соседей, или как максимум от их соседей.

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

Теперь, когда я наложил сетку шестиугольников на карту, можно приступить к реализации модели ветра. Основная идея модели ветра заключается в симуляции некоторых ветров (пассатов) и распространении их по всей карте, пока они не достигнут состояния неподвижности. На уровне шестиугольников (или уровне локаций, если я делаю это на треугольниках Делоне) это включает в себя два этапа: (1) суммируем все ветра, входящие в текущий шестиугольник, и (2) определяем, как суммированный ветер покидает шестиугольник.

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

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

В этом случае мы ожидаем, что ветер без изменений переместится в следующую ячейку. (Здесь красным показан вектор исходного ветра, а синим — вектор распространившегося ветра.)

Но что, если ветер не дует напрямую на соседнюю ячейку?

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

Также необходимо принять решение о направлении распространившегося ветра. Один из вариантов — сохранять направление исходного ветра:

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

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

Ещё одна сложность возникает при рассмотрении рельефа. Что должно случиться, когда на пути ветра встаёт гора?

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

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

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

Если мы отрисовываем вектор, начиная с (0, 0), то (X,Y) являются координатами конечных точек. Такая запись позволяет очень просто суммировать векторы. Мы просто суммируем все значения (X,Y) и получаем новый вектор:

Другой вариант — использование угла и длины вектора:

В этом виде легко выполнять такие операции, как поворот векторов или изменение его длины.
Для большинства операций, необходимых в модели ветра, лучше подходит первый вариант, но в некоторых случаях лучше второй, поэтому было бы удобно переключаться между ними при необходимости. Чтобы не изобретать заново велосипед, я поискал векторную библиотеку для Javascript и вполне подошла Victor.js, поэтому я воспользовался ей.

Я начну с того, что добавлю в каждый шестиугольник вектор ветра и посмотрю, смогу ли это визуализировать:

Пока выглядит хорошо.

Следующий этап — нужно проверить, смогу ли я правильно разделить вектор ветра и распространить его на следующую ячейку. Во-первых, нужно вычислить углы, ведущие в другие ячейки. Ответ я снова нашёл на странице Амита:

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

Например, если вектор ветра имеет угол 22 градусов:

тогда 38/60 значения распространяется в ячейку справа, а 22/60 значения вектора — в ячейку внизу справа. Если векторы представлены в виде пары значений X и Y, то распространить их можно, умножив каждое значение исходного вектора на долю (например, на 22/60), а затем прибавив его к вектору ветра в новом шестиугольнике.

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

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

Следующий этап — нужно учесть влияние суши на ветер. Разумеется, реальные модели ветра очень сложны, но меня в основном интересует то, как на поверхностные ветра влияет география суши. На простейшем уровне это влияние высот и низин суши на направление и скорость ветра. Я экспериментировал со множеством разных подходов, но в результате остановился на двух простых правилах:

  1. Ветер отворачивается от препятствий.
  2. Ветер замедляется, когда поднимается вверх, и ускоряется, опускаясь вниз.

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

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

Ещё одна черта, повышающая реализм — это рассеяние ветра. Например, на показанной выше карте видно, что ветер дует на запад прямо над городом Breeches. Хотя он дует на достаточно дальние расстояния, он никогда не рассеивается так, как мы бы ожидали. Когда дующий ветер встречает другой воздух, он обычно тянет этот ветер за собой. Чтобы симулировать это, я могу взять малую часть ветра, дующего в каждом шестиугольнике, и перераспределить его во все соседние ячейки. Вот, как будет выглядеть показанная выше карта с небольшим значением рассеяния:

Как видите, теперь ветер над Breeches начал немного рассеиваться вниз.

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

Вот, как всё это выглядит:

Теперь мы видим, что часть ветра, дующего через высокие горы в центральной части острова, оказалась отсечённой. И наоборот — появилось несколько новых ветров в западной части острова, где воздух движется с относительно высокой суши в море. (Это береговой бриз! Хотя на самом деле не совсем: механизм там другой.)

Теперь я могу подставить новый ветер в уже имеющийся алгоритм осадков. Вот их сравнение (старые ветра слева, новые — справа):

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

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

Смысл всего этого заключается в ускорении и упрощении генерации ветра, чтобы можно было добавить на континентальные карты новые поведения ветра. Получилось ли у меня? Я выполнил профилирование исходной модели ветра и новой модели на основе шестиугольников. Оказалось, что новая модель в 15-20 раз быстрее исходной (!). Это очень значительное ускорение, мало повлиявшее на карты. Эксперименты дают понять, что модель не особо чувствительна к размеру шестиугольников, поэтому при необходимости я смогу ещё больше ускорить алгоритм, увеличив размер ячеек.

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

Оцените статью
Fobosworld.ru
Добавить комментарий

Adblock
detector