Перейти к содержимому


Свернуть чат Чат Открыть чат во всплывающем окне

GranMinigun : (3 дней назад) Внезапно, со всем. А что можешь?
Гость : (3 дней назад) в чем сейчас помощь требуется?
Гость : (3 дней назад) есть "вакансии" для проекта?
GranMinigun : (неделю назад) Ы. Круто.
Yandersen : (неделю назад) Ну я ж хотел приехать? Ну вот и приехал. Ау, типа.
GranMinigun : (неделю назад) Хера. Ты же вроде всё в Канаде торчал, не?
Yandersen : (неделю назад) Эй, я в Беларуси уже почти год, даже работаю на Тракторном Заводе!
GranMinigun : (неделю назад) Ты вообще западный щпиён.
Yandersen : (неделю назад) Шабат по субботам. Ты не кошерный.
GranMinigun : (неделю назад) Не-не, только по четвергам.
lz : (неделю назад) +
Yakim (Watco... : (неделю назад) наркоманы)
Гость : (2 недель назад) Лошадка?
Yandersen : (2 недель назад) Тракторы!
GranMinigun : (2 недель назад) Радуга!
lz : (3 недель назад) Не, я тут всегда, просто пока своими делами занят. Если есть желание - присоединяйся, я подскажу что и чего.
GranMinigun : (3 недель назад) Есть ещё онлайн-проект, но я за ним вообще не следил. Знаю только, что им занимается молодняк.
GranMinigun : (3 недель назад) Я здесь для виду. Не могу сказать, ведутся ли какие-либо работы над P4. Скорее всего, единственный разработчик решил переключиться на другие дела вследствие отсутствия помощи и заинтересованности со стороны.
Гость : (3 недель назад) а....ремастер пилил последний раз:( печаль, столько слов было про 3-й....
Гость : (3 недель назад) август последняя активность
Гость : (3 недель назад) Я просто активности то не вижу на форуме, поэтому и спрашиваю нужна она вообще или нет?))
GranMinigun : (3 недель назад) Команды никогда и не было. О деталях я умолчу. Если можешь помочь - обратись к lz.
Гость : (3 недель назад) т.е. да? команды нет?
GranMinigun : (3 недель назад) Мечта всегда будет тлеть.
Гость : (3 недель назад) Умер проект?
lz : (18 Август 2017 - 14:31) Не, спс)))
GranMinigun : (17 Август 2017 - 18:59) Только он доступен так же, как и сырцы UE4. Читай - без аккаунта получишь 404.
Gaantro : (17 Август 2017 - 09:02) Исходный код движка Lumberyard от Amazon доступен на GitHub (Переделка CE)
GranMinigun : (12 Август 2017 - 17:02) Мэханоыди?.. wut
lz : (12 Август 2017 - 16:19) клятi
Гость : (12 Август 2017 - 11:16) механоиді
lz : (01 Август 2017 - 00:33) https://mesamatrix.net/
lz : (31 Июль 2017 - 21:04) Какие проблемы?)
lz : (31 Июль 2017 - 21:04) Я просто не хотел скидывать, но... http://www.phoronix....enGL-4.6-Driver
PA3UJIb : (31 Июль 2017 - 20:00) Ага, осталось дождаться этого функционала в дровах
lz : (31 Июль 2017 - 17:14) https://www.khronos....-spir-v-support
lz : (27 Июль 2017 - 10:22) В чём там сложность возникает?
Yakim (Watco... : (27 Июль 2017 - 09:21) Имеешь навык С++ и не можешь даже просто загуглить? Сириусли?)
Гость : (27 Июль 2017 - 09:20) https://www.google.c...a/search?q=ln(e)&oq=ln(e)&aqs=chrome..69i57&sourceid=chrome&ie=UTF-8
Гость : (27 Июль 2017 - 09:19) https://www.google.c...ch?q=log2(65536)&oq=log2(65536)&aqs=chrome..69i57&sourceid=chrome&ie=UTF-8
Гость : (27 Июль 2017 - 06:57) НО КАК ЗАРЕГИСТРИРОВАТЬСЯ ТО777111
Гость : (27 Июль 2017 - 02:02) Разве что так)
lz : (27 Июль 2017 - 01:59) А так для души делать, как хобби, может потренироваться в программировании, может ещё что-то полезное для себя найти.
Гость : (27 Июль 2017 - 01:54) Если кто-то играет)
lz : (27 Июль 2017 - 01:41) В ремастер будут играть все, кто играет в оригиналы. Поэтому вопрос - сколько людей играет в оригиналы?

Yandersen

Регистрация: 06 Июл 2014
OFFLINE Активность: 2 дней назад
*****

#1935 Механоиды Remastered (Polygon-4)

Написано Yandersen 14 Июль 2016 - 01:32

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




#1928 Механоиды Remastered (Polygon-4)

Написано Yandersen 11 Июль 2016 - 22:22

А, и вот ещё насчёт обородувоания типа Криотронов, Ремонтных модулей, Больших Энергоконденсоров и т.п. - пусть это будут товары непостоянного потребления, случайно появляющиеся на Сырьевой Базе. Пусть строения (кроме СБ) периодически "ломаются" - начинают простаивать и требовать один из этих товаров в определённом количестве (т.е. у каждого строения определённый шанс поломки в день, у каждого строения свой, у некоторых, как в Вулканах, например, выше).

 

Торговцы пусть товары типа оборудование не таскают. Пусть это только Курьеры делают: если залетают в строение с поломкой, летят на СБ за соответствующим товаром и обратно. Если не успевают (кто-то уже привёз раньше курьера), возвращаются на СБ и скидывают обратно, после чего возвращаются к рутине.

 

Насчёт охотников вот ещё что. Когда они набивают трюм награбленным и летят на Базу для ремонта и скидывания колобков, они там продают потребляемое лишь до недельной нормы, и если что-то ещё остаётся в трюме из товаров, то летят на СБ и скидывают всё там, и только с пустым трюмом возвращаются на свои участки патрулирования. Т.е. рациональнее будет выбирать им маршруты вблизи СБ.

 

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




#1926 Механоиды Remastered (Polygon-4)

Написано Yandersen 11 Июль 2016 - 02:10

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

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

Ящитаю, каждое строение должно потреблять один из энергоресурсов для своей работы (Ядерное топливо или Энергомодули, производящиеся на Заводе Расходных Материалов или появляющиеся на Сырьевой Базе если Завод Расходных стоит без сырья) и сырьё / полуфабрикаты для производства.

 

Каждый вид товара в секторе должен производиться лишь в одном строении (потребляться может несколькими). Цены закупки товара для мехов должны быть стандартными, а цены продажи в другие строения пусть зависят от расстояния между строением и точкой производства плюс бонус, если строение простаивает без товара или дебонус, если склад итак переполнен. Количество производимого и суммарное количество потребляемого товара должны быть одинаковы. При простое строений получится перепроизводство - для этого есть Сырьевая база ака дэпо для излишков: там цены покупки и продажи должны быть одинаковыми (себестоимость). Если склады строений переполнены, продать товар туда можно лишь ниже себестоимости, поэтому лучше скидывать на Сырьевую базу по себестоимости. Если на СБ или собсно точке производства кол-во товара превышает кап, данный товар перестаёт производиться в секторе.

 

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

 

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

 

Про курьеров ХЗ. Может, пусть информпакеты возят между строениями рандомом?

 

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




#1911 Механоиды Remastered (Polygon-4)

Написано Yandersen 29 Июнь 2016 - 21:55

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

 

Но тут есть один нюанс. В оригинальных мехах при наложении горизонтальной текстуры (проекция сверху вниз) на вертикальный склон, текстура выглядела растянутой. Это потому, что в оригинальных мехах все вершины были выровнены по сетке, из-за чего треуги крутых склонов имели бОльшую площадь, чем треуги, лежашие на горизонтальных плоскостях. Однако в УЕ4 вершины передвинуты так, чтобы эти неравномерности скомпенсировать (вершины кучкуются на вертикальных склонах и разрежены на горизонтальных плоскостях). Поэтому позиции вершин карты из оригинальных мехов не соответствуют позиции вершин карты после импорта даже если общее количество вершин такое же. Это значит, что мы просто не можем передрать индексы вершин напрямую и ожидать, что локации будут выглядеть так же. Нам по-любому придётся перетекстуривать сектора вручную, накладывая текстуры заново.

 

Хорошая же новость в том, что, похоже, нам не придётся заморачиваться насчёт вертикальных и горизонтальных текстур в УЕ4. Как я понимаю, текстурные координаты там уже препросчитаны так, чтобы равномерно растягивать горизонтальную текстуру по всей поверхности (как я могу судить по наложению дефолтной шахматной текстуры). Это значит, что нам нужно добавить в аттрибуты вершины лишь индекс текстуры и заставить шейдер при рисовании треугов смешивать по три текстуры из набора секторных текстур. Этот набор (палитру текстур) ещё нужно создать для каждого сектора (выбрать используемые в секторе картинки и упаковать в одну текстуру). Палитра текстур - это особый тип текстуры: слоёная (layered). Массив картинок, грубо говоря. Индекс текстуры у вершины указывает индекс слоя в палитре. Для каждого треуга используется три слоя, соответствующих текстурным индексам в вершинах.

 

К примеру, в палитре у нас 10 текстур. Мы рисуем треуг с индексами текстур в вершинах 3, 5, 7. Это значит, что для слоя "3" интенсивность текстуры в соответствующей вершине будет 100%, а в двух других - 0%. Так делаем для трёх слоёв и суммируем получившийся цвет. Получаем требуемый результат - плавный переход текстур между вершинами.

 

Вопрос в том, как расставить индексы вершинам карты? Напомню, индекс текстуры вершины - это индекс картинки, преимущественно испольуемой в близости этой вершины. Соответственно, алгоритм присвоения индексов вершинам (наф вручную это делать) должен рассматривать такие характеристики вершины, как, к примеру, наклон (средняя нормаль к поверхности), высота, объекты. Пусть в нашей палитре будет 7 слоёв:

0) тундровая скудная растительность, для высокогорных плато;

1) травка, для долин средних высот;

2) травка с опавшей листвой на ней;

3) галька, для подводных местностей;

4) скалистая почва, для склонов гор;

5) дорожное покрытие;

6) фундамент.

Соответственно, в зависимости от наклона, мы сперва определяем, лежит ли вершина на склоне горы или на поверхности (отклонение нормали от вертикального направления >Х градусов), и если да, то индекс вершине присваиваем 4 (скалистая почва). Если же это плоскость (отклонение <=X градусов), то смотрим на высоту и выбираем из индексов 0,1 или 3). Если поблизости есть деревья, то переделываем индекс на 2 (травка с листиками на ней). При рисовании дорог вручную индекс замещается на 5 (дорожное покрытие). Строения заменяют индексы вершин в зоне на 6 (фундамент). Ну и в таком плане.




#1883 Механоиды Remastered (Polygon-4)

Написано Yandersen 15 Июнь 2016 - 03:59

Полигон-4: Исход Супера

По-библейски как-то звучит. Может, "Полигон-4: Новые Директивы" или "Полигон-4: Отмена Директив", раз уж действия ПизПа в конце М1 к этому привели?

 

Показать откуда там вылезли пятые

Из Биомолекулярных ёмкостей, чё там показывать?  :)

 

как арио лазил за первым

Блуждание по пустошам ВМ с попутным геноцидом агрессивной живности? Типа, сафари штоле?

 

может как лоарат следовал за Супером и первыми

Игра-лабиринт с элементами погони по корридорам подземки? Ээээ...

 

Становление кланов

Кланы как были, так и остались, только лидерами их стали Пятые. Типа, поочерёдная игра за каждого из Пятых с целью зохвата контроля над кланом? Вот это разве что может быть интересным, ИМХО, к тому же Пятые не все разом появились, а поочереди вылезали. Но тут загвоздка: отыгравший свою партию Пятый ведь остаётся на Полигоне, т.е. при игре за следующего Пятого мы встречаемся с предыдущими. Как быть? Закрыть сектора чтоб изолировать аквариумы друг от друга? Но что тогда с Монцебер-Тарантоговой Пустыней делать?

 

изменения синигр ну и подобное

Так закрылись они в своих Болотах и всё, о чём там рассказывать?

 

Ну, в принципе, можно это всё сделать как набор коротких квестовых историй для каждого перса (Пятого). Типа, после появления из Сборочного Цеха Супер ставит целью найти способ возглавить тот или иной клан в таком-то секторе. Переходы запрещены, для каждого свои квесты. У Третего из Пятых (или второго ХЗ) миссией будет возглавление клана Синигр в Болотах, но в конце его сюжетно шлёпают и Болота закрываются. К Лоаррату и Арио в конце возвращаемся по второму кругу для бонус-миссии (Лоаррат следует в подземку за "странной всетящейся цепочкой" или как там было, а Арио вылазит во В.М. за ПизПом - это ужев самом конце, самый последний квест).




#1877 Механоиды Remastered (Polygon-4)

Написано Yandersen 14 Июнь 2016 - 22:45

О, а это очень правильно и похвально.

 

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

 

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

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

Урон среди всего вооружения наименьший. Энергопотребление среднее.

 

2) Плазменное оружие ("импульсные лазеры" переименовать нужно в плазмомёты) жгут щиты, броню и хулл. Урон средний, энергопотребление наибольшее.

 

3) Кинетическое оружие жгёт щиты и хулл, но не броню. Взаимодействие с бронёй следующее: 100% живая броня уменьшает урон снаряда на Х единиц (т.е. крепкая Нуль-броня может бесконечно долго полностью защищать от урона слабого кинетического оружия типа Атомки). Если урон снаряда больше Х, всё остальное приходится на хулл и компоненты глайдера, а не на броню (т.е. кинетичка не уменьшает хэлы брони). Если броня покоцана наполовину, то и уменьшение урона будет Х/2 ед. Т.е. чтоб эффективно кромсать бронированные глайдеры желательно их сперва лазерами или плазмой пожечь.

Урон наибольший, энергопотребление наименьшее.

 

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

 

Первый нюанс, что всплывает - возможность патовой ситуации: оба противника с атомками и Крсталлическими броньками. Предлагаю переделать способ установки лёгкого вооружения с попарного на попилонный, чтоб даже на мелких двупилонных глайдерах (1-2 стандарты) можно было ставить два разных лёгких пилона. В этом случае кнопка лёгкого оружия активирует оружие в левом пилоне, а кнопка тяжёлого оружия - в правом. Для остальных трёхпилонных глайдеров (3-4 стандарты) как раньше - оба пилона лёгкого оружия на одну кнопку, тяжёлое - на другую.

 

Насчёт щитов. Пусть 3 вида будут - быстровосстанавливающиеся, с высокой напряжённостью, либо сбалансированные. Отличие в отношении скорости восстановления к напряжённости. Крепкие щиты хороши для быстрых атак, быстровосстанавливающиеся эффективны в длительном бою на живучих танках.

 

Насчёт доп.оборудования. В Стелларисе конструктор кораблей хорошо сделан, оттуда передрать бы чё-нить. Суть в том, что в хулле каждого глайда есть определённое количество слотов разного стандарта (у каждого глайда своё). Вот при покупке туда всё и перетаскивается. Некоторые слоты в нашем случае должны быть специализированными: пилоны оружия, движки (чтоб модели соответствовало), щит и броня (чтоб лишь один конкретный тип можно было выбирать). В остальные универсальные слоты можно пихать реакторы и доп оборудование. ХЗ насчёт варианта со сменой глайда: либо всё накопленное продаётся автоматом, либо нужно дать возможность перетаскивания компонентов со старого глайда на новый (для некоторых компонентов может слота не найтись, например - что тогда делать?).

 

Насчёт оборудования и стандартов. Пусть наиболее пепячные будут доступны лишь в вариантах более высоких стандартов.




#1762 Unity 5 - "Механоиды без границ"

Написано Yandersen 30 Ноябрь 2015 - 23:37

Я вот не пойму: чем задается цвет текстур? Colormap-ом, параметром "Color" в базе данных или как-то ещё?

Да, именно так. Там ещё карта теней есть, но это уже архаизм, щас тени динамически рисуюцца.

 

Добавлен регулятор мощности двигателя (слева снизу)

Этот регулятор привязан к кнопкам управления (A-D).

 

Стыков больше нет, действительно. Но вот с вертикальными текстурами жопа. Ты их, походу, как и обычные текстуры накладываешь, так? А у них на самом деле другая плоскость проекции должна быть - вертикальная, а не горизонтальная. Причём вертикальных плоскостей две. Смотри. Горизонтальная плоскость обычно задаётся осями Ox, Oz, соответственно текстурные координаты - это координаты вершины x,z для горизонтальных текстур. Но для вертикальных текстур текс.координаты берутся из x,y или z,y (в зависимости от того, как ориентирован полигон).

В своём самописном движке я определял материал тремя текстурами - горизонтальной и вертикальными, причём обе вертикальные имели одинаковую картинку. Накладывал сразу все три и в шейдере уже смешивал их в зависимости от ориентации нормали: чем вертикальнее торчит нормаль, тем больший процент горизонтальной текстуры; чем больше нормаль отклонена по горизонтальной оси (компоненты x,z), тем больший процент той или иной вертикальной текстуры. Улавливаешь?

 

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

 

Хотелось бы увеличить чувствительность носа глайдера по вертикали - чтоб меньшее отклонение курсора сильнее задирало нос. А то камера в небо смотрит, а брюхо всё равно скребёт по земле.

 

И по прежнему, всё было вкусно, спасибо!  :)




#1751 Unity 5 - "Механоиды без границ"

Написано Yandersen 28 Ноябрь 2015 - 19:49

Офигеть, это восхитительно! Я даже смог сориентироваться и прилететь к Сборочному цеху.  :)

Надеюсь, текстурки поправишь и стыки зашпаклюешь?  :)  Тогда уж и здания и объекты неплохо было бы увидеть. У нашего Гуру Егора и на это выдиралка есть.  :)




#1730 Unity 5 - "Механоиды без границ"

Написано Yandersen 19 Ноябрь 2015 - 03:37

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

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

С белыми точками пока не знаю, как бороться. Про дырки в ландшафте пожалуйста, поподробнее - желательно со скриншотом. Может, это из-за низкого разрешения heightmap? Я не заметил особенных дыр...

Сорь, моя неправ - это не щели и дыры, а всё те же "солнечные зайчики" рандомно бегающие по карте и иногда растягивающиеся в полоски. Хз что за хрень.

Глайдер любит носом в землю втыкаться. Сделай два режима курсора. 1) Курсор всегда по центру и направляет глайдер. 2) При разовом нажатии клавиши меняется режим, курсор свободно двигается по экрану и глайдер на него не реагирует.
Ну это мелочи уже, не грузи творца.  :)

 

А так - впечатляюще. Успехов в охоте за мистическими точками и доведении ландшафта до ума!  :)




#1722 Unity 5 - "Механоиды без границ"

Написано Yandersen 17 Ноябрь 2015 - 08:07

Ух ты, надеюсь, такими темпами и дальше дело идти будет!

Со щитом классно сделано, одобряю.

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

Уммм... стрефы, прыжок, Esc на пропуск заставки закодил бы ишо... :)

 

А что насчёт ландшафта? Это как бы большая проблема вапще-та: в меховских картах под 20 текстур на карте используется. Есть идеи, как реализовать такой мультитекстуринг?

 

Вопщем держи пятюню, маны! ^_^




#1702 OpenGL

Написано Yandersen 31 Октябрь 2015 - 21:36

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

Прикрепленный файл  Bezier9DemoFullProject.zip   245,2К   87 - Раз(а) скачано

 

Код функции выложишь?

См. файл Tessellator.hpp - там всё и описано. Хотя разобраться в способе построения врядли удастся, ибо в папке нет файла геометрической модели построения, что я в Риноцерусе наваял и карты топологического размещения контрольных точек, что у меня на листиках накаляканы, так что подразумевается вариант "инклюд-н-йюз" класса CTessellator, который, собсно и юзается в основном файле WindowGL.cpp.

 

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

 

Затем запускаем функцию построения меша, которая спрашивает, сколько промежуточных вершин будет всунуто в каждую грань исходного треугольника при разбиении. Если ввести 0, то будет один треуг, если единицу, то каждая грань будет пополам разбита (4 треуга), когда 2 вершины в грани, то 9 треугов выйдет, 3 - 16, и т.д.

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

 

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

 

В демошке я юзаю обычные функции glVertex3fv и glNormal3fv, т.е. рисовка неоптимальная. Ибо класс тесселлятора предназначен чисто для построения меша, а не для рисовки. Подразумевается, что после потроения меш будет переконвертирован в нужный юзеру формат и сохранён в файл или что-то вроде того. Хотя я размышляю над добавлением функции, которая будет лепить треуги в стрипсы и сохранять меш в файл *.glm (GL Model), но этот формат нужно сперва ещё доработать, возможно.

 

И не совсем ясно пока с наложением текстурных координат: они генерируются независимо для каждого меша ведь, так что, получится, по своей текстуре на меш. А чтоб меши лепить друг к другу, надо бы текстуры и тангенты с битангентами совмещать чтоле. Когда меш к мешу стыкуешь, можно текстурную карту стыкуемого меша повернуть, масштабнуть, сдвинуть и битангенты с тангентами пересчитать, чтоб всё совпало. Но это не всегда реально: что если 6 мешей в шестиугольник стукуются? Циклозависимость. Так что я думаю, пусть так и остаётся, по своей текстуре на сегмент брони.




#1698 OpenGL

Написано Yandersen 28 Октябрь 2015 - 11:30

А теперь поверхности Безье, товарищи! Точнее, треугольные патчи.

 

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

 

Как это сделать? На основании трёх контрольных точек вычислим кординаты промежуточных точек, ну а дальше - поверхность Безье и в меш её.

 

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

 

Нашёл решение проблемы тут. Оказывается, чтоб поверхности Безье стыковались без щели (C0 continuity), нужно, чтоб контрольные точки на границе патчей были одинаковыми. А чтобы шва не было видно, т.е. чтоб нормали на границе одинаковые получались (C1 continuity), "панели" на границе должны быть копланарными и симметричными.

 

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

 

Очевидно, что для этого нужен особый способ построения поверхности. Как оказалось, достаточно взять поверхность 7-го уровня (7 панелей на границах) и сжать в точку по 2 панели с каждого края (отсингхулярить их к вершинам). Таким образом убирается зависимость между общими панелями соседних граней (в отличие от треугов, две совпадающие точки всегда "симметричны" и "копланарны"). А опорные точки оставшихся 3х панелей вычисляются на основании двух вершин соответствующей грани, тем самым не зависят от третьей вершины. Так что если два треуга шарят две опорные точки, то и смежные панели у них получатся симметричными, а значит и полученные поверхности будут стыковаться без шва.

Что интересно, так это то, что 3 панели каждой грани можно вытягивать вглубь (масштабировать все на одинаковую величину), и при этом связность патчей не нарушится. Это полезное свойство позволяет контролировать кривизну, и при этом не нарушает требуемого свойства бесшовности.

 

:!: Единственный нюанс данного метода в том, что при вычислении координаты и нормали точки на поверхности по её барицентрической координате нужно проверять отдельно, не является ли данная точка вершиной треуга, ибо из-за сжатия крайних панелей нормаль там получается нулевой длины. Просто нужно исходные контрольные точки хранить отдельно и подставлять их значения если барицентрическая координата равна (1,0,0), (0,1,0) или (0,0,1).

 

Короче, вот весь проект вместе с экзешником (в папке Release):

 

Прикрепленный файл  BezierDemoFullProject.zip   247,38К   90 - Раз(а) скачано

 

Демонстрирует построение независимых патчей из двух рандомных треугов, шарящих 2 вершины. Поверхности строятся по своим правилам, но независимо друг от друга, и при этом совпадают без шва. Не чудо ли это?  :)

 

Управление:

Esc - выход;

Enter - полноэкранка;

WASD,C,Space - перемещение камеры;

мышь, Q,E - вращение камеры;

R - реинициализировать поверхности (новые рандомные позиции и нормали);

+- - увеличить/уменьшить детализацию;

L - показать/скрыть линии меша;

N - показать/скрыть нормали у вершин;

P - показать/скрыть нормализованные срединные перпендикуляры треугольников меша.

 

Что из всего этого следует? Гладкая сегментная броня по трём опорным точкам на сегмент - реализуемо!




#1677 OpenGL

Написано Yandersen 14 Октябрь 2015 - 22:12

Курвы Безье, товарищи - как их рисовать?
Пусть у нас есть две 3D точки (Va, Vb), через которые мы хотим провести изогнутую линию так, чтобы эта линия была перпендикулярна нормалям в этих точках (Na, Nb). Чтобы нарисовать требуемую линию нам нужно вычислить координаты нескольких промежуточных точек на желаемой кривой и соединить эти точки отрезками.
 
Введём коэффициент "k" для разбиения:
k = [0...1], если k==0, значит промежуточная точка находится у Va, если k==1, то мы у конца где Vb.
И добавим ещё один параметр, "Curvature", контролирующий степень изогнутости курвы:
Curvature = (0...1), Curvature==0 соответствует прямой линии, при Curvature>1 курва может выпячиться так, что узлом изогнётся в средней точке, что нам не нужно. Наилучшее значение: 0.5.
Итак, вот функция для вычисления промежуточных точек на курве:

#include "GLSL.hpp"
bool TessellateEdge(const vec3& Va, const vec3& Na, const vec3& Vb, const vec3& Nb,
                    vec3* Vm, vec3* Nm,
                    float k, float Curvature=0.5f){
 //Check for input errors
 if(k<0.f||k>1.f||Curvature<=0.f||Curvature>=1.f)return false;
 //Precalculate some values, check for errors
 vec3 AB = Vb-Va; //Direction from Va to Vb
 if(dot(AB,AB)==0.f){ //Va==Vb
  if(Vm)*Vm = Va;
  if(Nm)*Nm = normalize(Na*(1.f-k)+Nb*k);
  return true;
 }
 if(dot(cross(AB,Na),cross(AB,Nb))<=0.f)return false; //"Möbius" problem
 //Calculate curve' tangents
 vec3 Ta = Curvature*(AB-Na*dot(AB,Na)),
      Tb = Curvature*(Nb*dot(AB,Nb)-AB),
      DF = AB+Tb-Ta,
      J = k*((2.f-k)*DF - k*Tb) + Va + Ta,
      H = k*(k*DF + (2.f-k)*Ta) + Va,
      Tm = J-H;
 //Calculate coordinates of the middle point
 if(Vm)*Vm = H*(1.f-k)+J*k;
 //Calculate normal at the middle point
 vec3 P = Va+normalize(cross(Na,AB)),
      Q = Vb+normalize(cross(Nb,AB)),
      PQ = Q-P,
      RS = PQ+Tb-Ta,
      L = k*((2.f-k)*RS - k*Tb) + P + Ta,
      W = k*(k*RS + (2.f-k)*Ta) + P,
      U = W*(1.f-k)+L*k;
 if(Nm)*Nm = normalize(cross( Tm, U - (*Vm) ));
 return true;
}



#1595 Механоиды Remastered (Polygon-4)

Написано Yandersen 11 Июль 2015 - 06:43

У Мастодонта (или Жала - хз) кабина для человека есть. Плюс в моделях есть капсулы с создателями. По этим ориентирам можно прикинуть примерный масштаб моделей для перевода в метры.




#1546 [GLT.hpp] - поддержка текстур в формате GLT

Написано Yandersen 28 Апрель 2015 - 19:51

Формат файла *.glt (OpenGL Texture) предназначен для сохранения и загрузки текстур (мипмапы и настройки) для OpenGL приложений.

GLT.hpp содержит описание структуры файлов *.glt и класс GLTexture, осуществляющий сохранение и загрузку *.glt файлов и работу с текстурами:

 

GLT.hpp
 

:!: Требуется наличие LoadGL.h.

:!: Некоторые функции используют OpenGL4.5.

 

Для создания файла текстуры нужно создать и настроить текстуру, загрузить мипмапы удобным способом, а затем средствами класса GLTexture сохранить готовую текстуру из контекста OpenGL в указанный *.glt файл. Альтернативно, можно создать *.glt файл из *.bmp с помощью специальной программы - GLT editor.

Пока что для работы с *.glt файлами использовался FileGLT.hpp, поддерживавший формат файла первой версии ('G','L','T',1). Первая версия позволяла хранить любое количество картинок в любом порядке, и в шапке файла размеры базовой картинки не указывались явно, так как загрузка мипмапов шла с помощью функции glTexImage*D. Но эта функция уже устарела - сегодня текстуры имеют immutable формат, т.е. аллоцируются лишь один раз (glTexStorage*D) и для этого необходимо знать размерность самой большой картинки и количество уровней мипмапов. Поэтому шапка второй версии файла ('G','L','T',2) включает размерность базовой картинки. Плюс добавлена поддержка бордеров и свиззл-настроек. Короче, вторая версия просто лучше. Хотя первая всё так же поддерживается - GLT.hpp умеет её грузить, но сохраняет уже в формате второй версии.
 
---
 
Структурно файл *.glt выглядит так:

  • первые 4 байта - это "подпись", определяющая тип файла и версию - 0x02544C47 для GLT второй версии (0x01544C47 было для GLT первой версии);
  • затем идёт заголовок с настройками и параметрами текстуры (у первой и второй версий шапки разные - 40 байт для GLT1 и 80 байт для GLT2);
  • массив картинок; каждая картинка имеет шапку (GLTMipmapHeader) и собсно данные (опционально); эта часть файла одинакова для обоих версий, хотя имеет разный оффсет, т.к. шапки разного размера.

Все структуры (GLT1Header, GLT2Header, GLTMipmapHeader) описаны и обкоменчены в GLT.hpp, хотя юзеру и не требуется с ними знакомиться, т.к. класс GLTexture умеет грузить и сохранять *.glt файлы.

 

Итак, включаем GLT.hpp в проект:

#include "GLT.hpp"

Класс GLTexture содержит лишь одну переменную - имя текстуры, т.к. большая часть интерфейса использует функции из расширения Direct State Access (OpenGL4.5). Если это расширение не поддерживается, доступными будут лишь загрузка и сохранение *.glt файлов. Узнать имя текстуры можно так:

//GLTexture Texture;
GLuint Name = Texture.Name();

Класс GLTexture автоматически кастается в GLuint при его использовании в OpenGL функциях там, где требуется имя текстуры. Например:

//GLTexture Texture;
glBindTexture(GL_TEXTURE_2D, Texture);

Это имеет смысл для работы с текстурами на аппаратуре, не поддерживающей DSA из OpenGL4.5, т.к. большинство функций класса GLTexture используют это расширение.

 

Чтобы создать новую текстуру определённого типа и размерности, пользуемся этими функциями:

void GLTexture::Create1D(GLenum internalFormat, GLsizei width, bool Mipmapped=true);

void GLTexture::Create1DArray(GLenum internalFormat, GLsizei width, GLsizei layers, bool Mipmapped=true);

void GLTexture::CreateRectangle(GLenum internalFormat, GLsizei width, GLsizei height);

void GLTexture::Create2D(GLenum internalFormat, GLsizei width, GLsizei height, bool Mipmapped=true);

void GLTexture::Create2DArray(GLenum internalFormat, GLsizei width, GLsizei height, GLsizei layers, bool Mipmapped=true);
 
void GLTexture::Create3D(GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, bool Mipmapped=true);
 
void GLTexture::CreateCubeMap(GLenum internalFormat, GLsizei width, bool Mipmapped=true);

void GLTexture::CreateCubeMapArray(GLenum internalFormat, GLsizei width, GLsizei layers, bool Mipmapped=true);

При создании текстуры требуется указать формат текселя (одна из OpenGLевских констант), размерность базовой картинки (и количество слоёв, если текстура слоёная, т.е. "layered"), а также будут ли у текстуры мипмапы (обычно да, поэтому последний параметр можно не указывать).

 

Сами же картинки загружаются этими функциями:

void GLTexture::SubImage1D(GLint level,
                           GLint xoffset,
                           GLsizei width,
                           GLenum format, GLenum type, const void *pixels);
 
void GLTexture::SubImage1DArray(GLint level,
                                GLint xoffset, GLint layerOffset,
                                GLsizei width, GLsizei layers,
                                GLenum format, GLenum type, const void *pixels);

void GLTexture::SubImageRectangle(GLint xoffset, GLint yoffset,
                                  GLsizei width, GLsizei height,
                                  GLenum format, GLenum type, const void *pixels);
 
void GLTexture::SubImage2D(GLint level,
                           GLint xoffset, GLint yoffset,
                           GLsizei width, GLsizei height,
                           GLenum format, GLenum type, const void *pixels);
 
void GLTexture::SubImage2DArray(GLint level,
                                GLint xoffset, GLint yoffset, GLint layerOffset,
                                GLsizei width, GLsizei height, GLsizei layers,
                                GLenum format, GLenum type, const void *pixels);
 
void GLTexture::SubImage3D(GLint level,
                           GLint xoffset, GLint yoffset, GLint zoffset,
                           GLsizei width, GLsizei height, GLsizei depth,
                           GLenum format, GLenum type, const void *pixels);
 
void GLTexture::SubImageCubeMap(GLint level,
                                GLint xoffset, GLint yoffset, GLint layerFaceOffset,
                                GLsizei width, GLsizei height, GLsizei layerFaces,
                                GLenum format, GLenum type, const void *pixels);

void GLTexture::SubImageCubeMapFace(GLenum targetFace, GLint level,
                                    GLint xoffset, GLint yoffset,
                                    GLsizei width, GLsizei height,
                                    GLenum format, GLenum type, const void *pixels);

void GLTexture::SubImageCubeMapArrayFace(GLenum targetFace, GLint layer, GLint level,
                                         GLint xoffset, GLint yoffset,
                                         GLsizei width, GLsizei height,
                                         GLenum format, GLenum type, const void *pixels);

Параметры следующие:

level - уровень мипмапы, для которой указывается картинка (у текстур типа GL_TEXTURE_RECTANGLE мипмапов нет, лишь базовая картинка).

xoffset, yoffset, zoffset - смещение в пикселах от левого нижнего переднего края картинки; обычно 0, если вся картинка загружается целиком, а не по частям.

layerOffset - для слоёных текстур это номер слоя, с которого начинается перезаписываемый регион картинок.

layerFaceOffset - то же, что и layerOffset, но для текстур типа GL_TEXTURE_CUBE_MAP и GL_TEXTURE_CUBE_MAP_ARRAY, для которых слои играют роль картинок для различных сторон куба. Чтобы не запутаться со сторонами и слоями, особенно для слоёных куб-мапов, где всё вперемежку и абы как, я ввёл несколько функций, позволяющих конкретно указывать сторону и номер слоя отдельно загружаемой картинки (функция SubImageCubeMapFace для обычных кубмапов и SubImageCubeMapArrayFace для слоёных кубмапов).

targetFace - для кубмапов этот параметр указывает на конкретную сторону куба (GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, ...).

width, height, depth, layers (layerFaces) - количество пикселей в передаваемой картинке и слоёв (если сразу несколько слоёв грузятся разом).

format, type, pixels - эти параметры описывают передаваемую картинку: format+type определяют формат пикселя, а pixels - собственно указатель на массив данных. Не забывайте о padding bytes - каждый ряд пикселей должен иметь длину, кратную 4 байтам. К примеру, если формат GL_BGR и тип - GL_UNSIGNED_BYTE (у стандартных bmp-шек так), и ширина картинки - 2 пикселя, то это 6 байт данных - непозволительный размер. Соответственно, каждый ряд должен иметь в конце 2 лишних байта, дотягивающих длину до 8 байт. В битмапах так и есть, так что их можно грузить как есть. Но если Вы создаёте текстуру процедурно, эту мелочь нужно учитывать.

 

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

inline void GLTexture::GenerateMipmaps();

Чтобы настроить параметры текстуры, используйте эти функции:

//Setup the minification filtering mode
inline void GLTexture::SetMinFilter(GLenum minFilter);

//Setup the magnification filtering mode
inline void GLTexture::SetMagFilter(GLenum magFilter);

//Set the wrapping parameter for s coordinate
inline void GLTexture::SetWrapS(GLenum wrap_s);

//Set the wrapping parameter for t coordinate
inline void GLTexture::SetWrapT(GLenum wrap_t);

//Set the wrapping parameter for r coordinate
inline void GLTexture::SetWrapR(GLenum wrap_r);

//Set the swizzling parameters
inline void GLTexture::SetSwizzle(GLenum swizzle_r=GL_RED,
                                  GLenum swizzle_g=GL_GREEN,
                                  GLenum swizzle_b=GL_BLUE,
                                  GLenum swizzle_a=GL_ALPHA);

//Set the border color
inline void GLTexture::SetBorderColor(const GLuint *ColorRGBA);

//Set the border color
inline void GLTexture::SetBorderColor(const GLint *ColorRGBA);

//Set the border color
inline void GLTexture::SetBorderColor(const GLfloat *ColorRGBA);

//Set GL_DEPTH_STENCIL_TEXTURE_MODE to GL_STENCIL_INDEX
inline void GLTexture::SelectStencilMode();

//Set GL_DEPTH_STENCIL_TEXTURE_MODE to GL_DEPTH_COMPONENT
inline void GLTexture::SelectDepthMode();

//Set GL_TEXTURE_COMPARE_MODE to GL_COMPARE_REF_TO_TEXTURE and then set a given
//value for GL_TEXTURE_COMPARE_FUNC; permissible values are: GL_LEQUAL,
//GL_GEQUAL, GL_LESS, GL_GREATER, GL_EQUAL, GL_NOTEQUAL, GL_ALWAYS, GL_NEVER
inline void GLTexture::ConfigureShadowmap(GLenum CompareFuncToUse);

//Set GL_TEXTURE_LOD_BIAS parameter
inline void GLTexture::SetLODBias(GLfloat Value);

//Set GL_TEXTURE_MIN_LOD parameter
inline void GLTexture::SetMinLOD(GLint Value);

//Set GL_TEXTURE_MAX_LOD parameter
inline void GLTexture::SetMaxLOD(GLint Value);

Учтите, что в *.glt файл сохраняются лишь filter, wrap, swizzle и border color параметры. Картинку карты тени или трафарета можно сохранить, но настройки в файл не пойдут - при сохранении и последующей загрузке эти параметры вернутся в дефолтное состояние.

 

Узнать параметры текстуры можно в любой момент (без биндинья) этими функциями:

//Return the value of the requested texture parameter
inline GLint GLTexture::GetParameteri(GLenum pname)const;

//Return the value of the requested texture parameter
inline GLfloat GLTexture::GetParameterf(GLenum pname)const;

//Return the value of the requested vector texture parameter
inline void GLTexture::GetParameterv(GLenum pname, GLint *params);

//Return the value of the requested vector texture parameter
inline void GLTexture::GetParameterv(GLenum pname, GLfloat *params)const;

//Return the value of the requested vector texture parameter
inline void GLTexture::GetParameterIv(GLenum pname, GLint *params);

//Return the value of the requested vector texture parameter
inline void GLTexture::GetParameterIv(GLenum pname, GLuint *params)const;

//Return the value of the requested parameter for the specified level
inline GLint GLTexture::GetLevelParameteri(GLint level, GLenum pname)const;

Вариант GetParameterIv отличается от GetParameterv тем, что используется лишь для возвращения цвета бордера текстур integer-формата.

 

Некоторые ширпотребные параметры удостоены чести иметь свои отдельные функции:

//Return the target type of the texture or 0 on failure
inline GLenum GLTexture::Target()const;

//Return internalFormat value for the mipmap of the specified level
inline GLenum GLTexture::InternalFormat(GLint level=0)const;

//Get texture's width
inline GLint GLTexture::Width(GLint level=0)const;

//Get texture's height (or number of layers if type is GL_TEXTURE_1D_ARRAY)
inline GLint GLTexture::Height(GLint level=0)const;

//Get texture's depth (or number of layers if it is one of 2D array textures)
inline GLint GLTexture::Depth(GLint level=0)const;

Тут нужно учесть, что для слоёных текстур Height или Depth будут возвращать количество слоёв, а не высоту или глубину картинки в пикселях, несмотря на название функции. Если не указывать уровень мипмапы, то по-умолчанию будут возвращаться параметры базовой картинки.

 

Привязать текстуру к указанному текстурному юниту можно так:

//GLTexture Texture;
Texture.Bind(GL_TEXTURE0);

Загрузка из файла *.glt:

//GLTexture Texture;
bool Success = Texture.LoadFromFile("Texture.glt");

Возвращённое значение (Success) будет true в случае успеха.

Если файл уже загружен в память (если, например, в один файл запихано несколько текстур, моделей и других данных), то текстуру можно загрузить и оттуда. Нужно лишь указать на то место, где начинается кусок, принадлежащий текстуре (начинается с 4хбайтной сигнатуры GLT1 или GLT2). Например, у нас есть файл, склееный из двух *.glt файлов, т.е. содержащий две текстуры. В таком случае грузим их так:

GLTexture Texture1, Texture2;
  
int Handle=-1; //File handle
_sopen_s(&Handle, "Textures.pak", _O_RDONLY|_O_BINARY,_SH_DENYWR,_S_IREAD);
int FileSize=_filelength(Handle);
char* Buffer=(char*)malloc(FileSize);
_read(Handle,Buffer,FileSize);
_close(Handle);

void* ptr1 = Buffer;
unsigned int BytesLoaded = Texture1.LoadFromBuffer(ptr1);

void* ptr2 = Buffer+BytesLoaded;
Texture2.LoadFromBuffer(ptr2);

free(Buffer);

Логичный вопрос - отчего стримовую загрузку не предоставить? А потому, что при загрузке отдельных мипмапов ОпенГЛ требует указатель на картинку, поэтому при стримовой загрузке пришлось бы лишний раз отводить память (и, возможно, не один раз) и копировать туда части файла с массивом пикселей.

 

А вот сохранение текстур может идти стримом:

//GLTexture Texture1, Texture2;
FILE* Stream = _fsopen("Textures.pak","wb",_SH_DENYWR);

bool Success1 = Texture1.SaveToStream(Stream);

bool Success2 = Texture2.SaveToStream(Stream);

fclose(Stream);

В отдельный файл сохраняется текстура так:

//GLTexture Texture;
bool Success = Texture.SaveToFile("Texture.glt");

Вотъ.  :)