Комментарии 27
Спасибо за описание алгоритма, может пригодится. У меня вопрос безотносительно вашего плагина и Unity3d, но про изометрию.
Допустим мы хотим положить наши 2д тайлы в атлас. В случае с простыми прямоугольными тайлами (как в марио) есть множество инструментов для упаковки атласов с возможностью повторения граничных пикселей — более-менее стандартный способ избежать мерцания на стыках, возникающего из-за интерполяции текстур.
Но хочется иметь специализированный паковщик для изометрических тайлов:
Как-то не хочется для ландшафта использовать квады с альфа блендингом, рисуя в 2 раза больше пикселей чем на самом деле надо. Но судя по отсутствию инструментария все так и делают?
Допустим мы хотим положить наши 2д тайлы в атлас. В случае с простыми прямоугольными тайлами (как в марио) есть множество инструментов для упаковки атласов с возможностью повторения граничных пикселей — более-менее стандартный способ избежать мерцания на стыках, возникающего из-за интерполяции текстур.
Но хочется иметь специализированный паковщик для изометрических тайлов:
- В случае с простыми одноуровневыми тайлами их можно упаковать плотнее срезая уголки (почти в 2 раза)
- Повторялка краев чтобы избежать мерцания (по периметру ромба)
- В игре использовать правильную геометрию — ромбик. Снижается fillrate в 2 раза, а также можно отключить альфа-блендинг.
Как-то не хочется для ландшафта использовать квады с альфа блендингом, рисуя в 2 раза больше пикселей чем на самом деле надо. Но судя по отсутствию инструментария все так и делают?
Для общего случая уменьшения филлрейта (за счет использования прозрачных областей) в Юнити есть, так называемая, плотная упаковка текстур в атласы (tight packer policy). Потом это всё рисовать нужно не как два треугольника, естественно, а с жутко триангулированным мешем. Так плотно как в специфическом случаи тайлов не жмёт, но хоть что-то.
Спасибо за наводку, запишу на подумать, как о возможной фиче в этот плагин.
Спасибо за наводку, запишу на подумать, как о возможной фиче в этот плагин.
Предложенная вами сортировка вытянутых убийственно проста и одновременно с тем убийственно медленная. Можете затестить сколько сравнений она у вас сделает имея в кадре 300 объектов, например.
Гораздо более шустрое решение ИМХО можно получить сохраняя промежуточные данные между кадрами и меняя сортировку элементов только тогда, когда один из них меняет положение. Так можно ещё одного эффекта добиться, иногда полезного — можно сделать пересортировку минимальным количеством перестановок. Для этого вам нужно хранить кроме положения каждого элемента по каждой из двух координат и размеров ещё два List<List> вдоль каждой из координат. В первый вы записываете все элементы, которые в этой целочисленной координате начинаются вдоль данной оси, а во второй все элементы, которые в этой координате заканчиваются.
Имея такую структуру данных вы в первый раз отсортируете элементы очень быстро, а при перемещении одного из элементов сможете делать изменение в минимальное количество перестановок. В изометрической игре, как правило, реально подвижных элементов не больше 10%.
Гораздо более шустрое решение ИМХО можно получить сохраняя промежуточные данные между кадрами и меняя сортировку элементов только тогда, когда один из них меняет положение. Так можно ещё одного эффекта добиться, иногда полезного — можно сделать пересортировку минимальным количеством перестановок. Для этого вам нужно хранить кроме положения каждого элемента по каждой из двух координат и размеров ещё два List<List> вдоль каждой из координат. В первый вы записываете все элементы, которые в этой целочисленной координате начинаются вдоль данной оси, а во второй все элементы, которые в этой координате заканчиваются.
Имея такую структуру данных вы в первый раз отсортируете элементы очень быстро, а при перемещении одного из элементов сможете делать изменение в минимальное количество перестановок. В изометрической игре, как правило, реально подвижных элементов не больше 10%.
Гораздо более шустрое решение ИМХО можно получить сохраняя промежуточные данные между кадрами и меняя сортировку элементов только тогда, когда один из них меняет положение.
Да, всё так и сделано, забыл про это написать. Сортируется всё не каждый кадр, а только тогда, когда это нужно:
- когда кто-то видимый сдвинулся
- когда кто-то стал видимым
Так можно ещё одного эффекта добиться, иногда полезного — можно сделать пересортировку минимальным количеством перестановок.
Пытался сделать несколько таких вариантов, пока хорошего и удобного не получилось, но продолжаю поиски в фоновом режиме.
>> Пытался сделать несколько таких вариантов, пока хорошего и удобного не получилось, но продолжаю поиски в фоновом режиме.
Для Юнити не так критично если вы не используете DestroyInstantly и рейтрейсинг после изменений в дереве. Потому что она всё равно дерево отображения перестраивает один раз за кадр. А вот для Флэши, которая перестроение всего дерева делала после каждого SwitchDepth это было огого как критично.
Моё решение было такое — благодаря этим вот массивам, которые я описал выше легко искать ближайший элемент, который ниже, и ближайший элемент, который выше. Я вставляя новый элемент искал место в существующей сортировке, если обнаруживался конфликт, когда первый элемент который выше вставляемого оказывался ниже последнего элемента который ниже, я брал одну из этих элементов, например верхний и двигал по сортировке до максимально допустимого для него положения. После этого повторял и если всё ещё конфликт брал нижний и сдвигал его вниз. Обычно в одно-три движения конфликт разрешается.
Для Юнити не так критично если вы не используете DestroyInstantly и рейтрейсинг после изменений в дереве. Потому что она всё равно дерево отображения перестраивает один раз за кадр. А вот для Флэши, которая перестроение всего дерева делала после каждого SwitchDepth это было огого как критично.
Моё решение было такое — благодаря этим вот массивам, которые я описал выше легко искать ближайший элемент, который ниже, и ближайший элемент, который выше. Я вставляя новый элемент искал место в существующей сортировке, если обнаруживался конфликт, когда первый элемент который выше вставляемого оказывался ниже последнего элемента который ниже, я брал одну из этих элементов, например верхний и двигал по сортировке до максимально допустимого для него положения. После этого повторял и если всё ещё конфликт брал нижний и сдвигал его вниз. Обычно в одно-три движения конфликт разрешается.
Забудьте о всём что может выделять память, а в C# (а особенно в местном старом Mono) это может делать всё, начиная от foreach(!) заканчивая создающимися лямбдами, а уж какой-нибудь LINQ противопоказан даже в самых простых случаях.
Случайно не этот LINQ?
Для чего-то типа поиска пути просто юзать что-то типа такого?
Где умные дяди сделали за меня кучу оптимизаций?
Сам сильно зауважал дядей писавших Linq с их оптимизациями когда попытался дополнить его своими функциями, делающими то же самое, что и последовательность из нескольких коробочных команд. К сожалению забыть о нём придётся по более банальной причине — некоторые его функции не работают на iOS. А учитывая соотношение доходов от iOS и Android в юнитёвых проектах это смертный приговор.
Не вводите людей в заблуждение.
"LINQ for iOS" — Вот этот плагин заменяет библиотеку LINQ на работающую в iOS. Все отлично работает, проверено на личном опыте.
"LINQ for iOS" — Вот этот плагин заменяет библиотеку LINQ на работающую в iOS. Все отлично работает, проверено на личном опыте.
Или бесплатный но менее оптимизированный UniLinq или ещё много что. Но это не System.Linq
Я не говорил, что System.Linq нельзя заменить. Я говорил только что его нельзя взять и использовать.
Я не говорил, что System.Linq нельзя заменить. Я говорил только что его нельзя взять и использовать.
Судя по данной теме о нём, он работает только на mono, на il2cpp опять же не работает.
Но и да, мой посыл был не в том, что работает, а что нет, а в производительности которую он может выдать. Удобно, круто, изящно, но не про скорость. Ибо аллокации на каждом шагу, а за это потом догоняет GC и даже без них цена использования выше, чем написать по старинке всё руками и развернуть все эти красивые конструкции.
Но и да, мой посыл был не в том, что работает, а что нет, а в производительности которую он может выдать. Удобно, круто, изящно, но не про скорость. Ибо аллокации на каждом шагу, а за это потом догоняет GC и даже без них цена использования выше, чем написать по старинке всё руками и развернуть все эти красивые конструкции.
У нас проект с этой либой. Все работает, естественно и в il2cpp (потому что другого под iOS сейчас нет)
Значит вы не используете то, что не работает. В теме, ссылку на которую я дал выше, автор сам об этом говорит.
Правка:
Но опять же не в том проблема. Проблема в цене, а цена высока.
Правка:
Но опять же не в том проблема. Проблема в цене, а цена высока.
Цена высока? $40?? Это цена 1 рабочего дня джуниор программиста с з/п 50 тыс.руб.
Цена не в деньгах имелась в виду.
А я не про деньги?
Цена в деньгах — это цена 1 рабочего дня плохого программиста.
Цена в деньгах — это цена 1 рабочего дня плохого программиста.
Я вот знаю, что кроме меньшей оптимизации UniLinq отличается ещё только одним: Если вы измените перебираемую коллекцию, он не выдаст экспешена сразу, так что возможны инконсистэнс или выход индекса за размеры массива, если вы ошибётесь, но больше никаких отличий мы не видели.
А чем отличается библиотека за $40? Я не знаю. И вы не знаете, я уверен. Поэтому если ничего не будет мне специальным образом мешать я буду использовать UniLinq. Не потому, что сорок баксов, а потому что чтобы чего не того.
А чем отличается библиотека за $40? Я не знаю. И вы не знаете, я уверен. Поэтому если ничего не будет мне специальным образом мешать я буду использовать UniLinq. Не потому, что сорок баксов, а потому что чтобы чего не того.
Причем тут деньги вообще?! Остановитесь )
Тогда могу лишь повторить. У нас есть проект, где было использована куча несложных LINQ. При переходе на iOS просто подцепили «LINQ for iOS» и все заработало (в т.ч. в 64 битах, на последних девайсах и т.п.)
Да, никакие совсем уж хитрые конструкции не использовали. Но для наших целей — оно подошло на 100%, по этому и советую. Основываясь исключительно на собственном опыте.
Да, никакие совсем уж хитрые конструкции не использовали. Но для наших целей — оно подошло на 100%, по этому и советую. Основываясь исключительно на собственном опыте.
Оно будет работать (половина функций в случае «LINQ for iOS»), вопрос Как и в цене за использование, а цена — это куча аллокаций на ровном месте, просаженный перфоманс, опять же на ровном месте, если вам это позволительно, то пожалуйста, используйте, просто будьте осторожны. Одно неверное движение и может случиться плохое, а потом эти страшные сны с участием GC, часы профайлинга, переписывания кусков кода и прочее.
Ну как бы не обязательно строгий запрет. Можно делать Linq-ом что-то что на нём будет понятнее и выполняется не больше раза в кадр и с небольшим количеством элементов. Конечно карту линковским перебором обежите — убъёте пол производительности. Иногда можно спроттипировать с линком и потом при причёсывании кода Linq оттуда элеминировать.
Ы. Когда я последний раз брался за 3Д, а было это овер10 лет назад, для перехода от перспективной проекции к изометрической достаточно было заменить одну константу при инициализации окна.
Че ж так все изменилось не в лучшую сторону то?
Че ж так все изменилось не в лучшую сторону то?
3D движок рендерит 2D спрайты, пытающиеся казаться трёхмерными =)
Простите за нубский вопрос, но в чём преимущество в использовании двухмерных спрайтов, имитирующих 3D, перед использованием 3D моделей? Например, спрайты в вашем примере очень похожи на lo-poly модельки. Неужели использование низкополигональных моделей дороже (в плане производительности и/или производства)?
Простите за нубский вопрос, но в чём преимущество в использовании двухмерных спрайтов, имитирующих 3D, перед использованием 3D моделей? Например, спрайты в вашем примере очень похожи на lo-poly модельки. Неужели использование низкополигональных моделей дороже (в плане производительности и/или производства)?
Вопросов тут много и нужно смотреть глубже. В производство арта вообще, модели никогда не будут такие, какие их можно отрисовать. Скажу больше, что многие нынче делают сначала модель, потом её рендерят и далее обрисовывают уже рендер этот, чтобы получить изометрический спрайт. А примеры мои похожи на модели, что бы тестировать было проще и нагляднее.
У вас может быть совершенно гениальный 2D художник в распоряжении. Никакое 3D ни за какие деньги этого не заменяет. Вот это, например, наш за один день нарисовал:


Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Изометрический плагин для Unity3D