вторник, 2 февраля 2016 г.

И снова немного о планетах из кубиков

Как же все-таки из шарика сделать кубик?
Конечно, когда я говорил, что надо пробовать делать "Майнкрафт со сферическим миром", я несколько размыто описал, как же все-таки в итоге можно сделать так, чтобы на поверхности все выглядело как плоскость из кубиков, а высоко вверху - как сфера. Хотя, признаюсь, сначала я отнесся к этому как-то по-наивному просто, решив, что можно и тупо перепрыгивать с левой стороны плоскости в правую и обратно, а на сферу просто такую "текстурку" натянуть, сделанную из плоскости.
Конечно, еще на этапе, когда я попытался сгенерировать такой мир, я понял, что генератор должен тоже понимать, что у него должен быть повторяющийся плавный узор из того, что он сделал, а не просто обрывать его в том месте, где нам больше не нужно ничего. Поэтому, да, есть такая вещь как Sphere в flow-noice, которая позволяет получать значения по координатам вроде долготы и широты в градусах.
И шо, вы таки думаете, что можно вот так вот взять и перенести полученные значения на плоскость? Вообще-то нет.
В общем, главным критерием "правильности" была возможность, в итоге, ползая по полученной плоскости обойти вокруг света за 8 шагов, если ты находишься прямо рядом с полюсом планеты. То есть никакой "растянутости" возле полюса быть не должно, а ведь она обычно есть, и эту проблему долго пытались решать картографы. Причем, если так подойти, то у вас на сферической проекции к полюсам такой широкий на плоскости мир сожмется до невероятно малых размеров.
Раздумия на эту тему, конечно, прошли не без гугла, ведь странно было бы, если бы этим никто еще не занимался. Да, я нашел кучу разных вариантов разной степени паршивости. Например, такой: https://en.wikipedia.org/wiki/Peirce_quincuncial_projection.
Но это не совсем хорошо для нашего случая. Самый крутой для меня вариант, который равномерно размазывает искажения, это проекция поверхности сферы на вписанный в нее куб, но не так, а немного иначе. По крайней мере, мне сейчас так кажется.
Ну и, конечно, нашлось, что это уже не новая идея: https://acko.net/blog/making-worlds-1-of-spheres-and-cubes/
И, получается, единственное, что здесь нужно, это преобразование координат из lat/long в x/y и конкретную поверхность "куба". Что, конечно, чревато некоторыми погрешностями на уровне плавающей точки, но я пока работаю над этим вариантом.
У этого последнего блога есть еще немного просто вдохновляющих и открывающих глаза идей вроде правильного использования SVO, которые выглядят красиво, но я еще не совсем понял, как потом этим пользоваться. И это тоже стоит попробовать.

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

среда, 6 января 2016 г.

Снова про эти воксельные движки

Все-таки, в заду жжет и хочется изобретать велосипед. Однако, вместо очередной попытки сделать что-то в лоб я принялся за изучение имеющихся API, протоколов и внутренних структур Minecraft как одного из наиболее успешных (хотя, все уверены, что он "неоптимизирован", "криво написан", "тормозит потому что жава"). Узнал много интересного, развеял многие свои заблуждения насчет "да блин, это ж так просто". Смотришь так формат хранения/пересылки чего-то и видишь там много интересных особенностей. И начинаешь думать, можно ли сделать как-то иначе, и как-то в голову сразу ничего не приходит (особенно после опыта собственной "жырноты").

Например, о чем я сразу подумал плохо - это об объемах данных, которые нужно перегнать с сервера на клиент, например, чтобы показать мир в радиусе 80 блоков (то есть 10 чанков - по 5 в каждую сторону).
Примем ради простоты, что у нас каждый чанк состоит из 4096 блоков (16х16х16), и каждый блок у нас ничего кроме статичного ID не описывает. И пусть наш ID будет 32-битным (4 байта), потому что мы щедрые и хотим много блоков (или хранить какие-то дополнительные данные о них).
Если загрузить все полностью (и с этим, в принципе, я справился даже с жирнотой, в которой было больше 4-х байт на блок, просто все не так быстро было), то это 10*10*10 чанков, то есть тыща чанков... и если использовать даже по 4 байта на блок, у вас получается 16 мегабайт данных (4096*4*1000). Вроде-бы не космос какой-то для современных сетей. Но так и 10 чанков это не так много - это средние настройки для Майнкрафта. Максимум там 16 чанков (правда, это не радиус, а диаметр). Примерно 64 мегабайта (4096*4096*4), что чуть больше. 100-мегабитная сеть будет грузить это до 10 секунд. Конечо же, в идеале, нужно догнать и перегнать MC, отрисовывая не 8 чанков перед игроком, что всего-то составляет 128 блоков (128 метров). Размер блоков без снижения детализации позволяет рисовать гораздо дальше, создавая офигительный ландшафт, и надо увеличить это хотя-бы раза в два, но это будет не в 2 раза больше по объему, а в 8 (это ведь 3Д, Карл!), то есть, офигенная половина гигабайта (если быть точным, то 32*32*32*4*4096 байт).

Конечно, вы не хотите передавать от сервера клиенту полгигабайта данных (ну может меньше, за счет сжатия), поэтому нужно делать что-то еще, изобретая невероятные способы уменьшить эти объемы. Например, Minecraft целиком "пустые" куски чанков не передает вообще, совершает ряд манипуляций с blockID, чтобы вместо 2-х байт использовать иногда и один. Нам же придется кроме этого добавить и еще что-то вроде уменьшения числа данных о далеких чанках (такой себе LOD) и умные алгоритмы определения, надо ли их вообще загружать, что я уже делал, хоть и криво). И даже если не хочется очень далеко видеть, это очень нужно чтобы уметь быстро двигаться в мире.

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

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