09 июня 2004
Обновлено 17.05.2023

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - изображение обложка
Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 1

Рис. 1. Вид модели после скрытия лишних ребер.
В первой части статьи мы подробно рассмотрели процесс создания низкополигонной игровой модели. Но мало сделать модель, ее еще н ужно, что называется, причесать. Сейчас мы детально разберемся, как устранить неприятный эффект “грубой” модели, а также изучим такое важное понятие, как “текстурная развертка”. Без этого создание качественной модели персонажа невозможно._

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 2

_
Рис. 2. Подошва ступни.
Сглаживание сеточного каркаса _Понятие групп сглаживания _ Для прида ния каркасу сглаженного вида существуют группы сглаживания ( Smoothing Groups ). Инструменты для работы с ними расположены в свитке Surface Properties в группе Smoothing Groups — 32 маленькие кнопки с цифрами. Нам могут понадобиться еще две кнопки: Select by SG (выбрать треугольники по группе сглаживания) и Clear All (удалить треугольники из групп сглаживания). Идея метода сглаживания сетки заключается в том, что граница двух треугольников выглядит гладкой (то есть ребро рендерится сглаженным) только тогда, когда они

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 3

Рис. 3. Боковая часть ступни.
принадлежат одной группе сглаживания (иначе это называется шейдинг по Гуро-Фонгу ). На практике это означает следующее: если мы выделяем два смежных треугольника (предполагается, что никаких действий по сглаживанию над ними еще не предпринималось) и кликаем на любой кнопочке с цифрами, то переход между треугольниками станет плавным. Среда моделирования поддерживает 2^32 = 4 294 967 296 различных комбинаций групп

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 4

Рис. 4. Верхняя часть ступни.
сглаживания, отсюда и 32 кнопки. Цифра на кнопке означает номер бита в 32­битном значении (используется для хранения данных о группах сглаживания), который равен 1, только если треугольники принадлежат одной группе сглаживания. Звучит довольно непонятно, но только до тех пор, пока вы сами не попробуете освоить технику самостоятельно. Для наглядности вышеизложенного я произвел сглаживание камина, о котором мы уже говорили в первой части статьи. Его можно найти в файле Triangles_smoothing.max. _Подготовка модели к сглаживанию _ Во­первых, отключаем режим отображения модели See­Through и Vertex Ticks. Во­вторых, плоскости с проекциями персонажа можно спрятать (или даже удалить!) — они нам больше не нужны (см. scn27.max ).

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 5

Рис. 5. Cглаживание голени.
Делаем внешний вид нашей модели более эргономичным — прячем ненужные ребра (на уровне Edge в свитке Surface Properties кнопка Invisible ). В процессе работы оставлять все ребра видимыми может быть удобно только при редактировании сетки (хотя это вовсе не обязательно), но потом лишние ребра мешают. После их скрытия большинство полигонов модели увеличится в размере (будет состоять из большего числа треугольников).

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 6

Рис. 6. Чашка и фиксаторы наколенника.
При этом надо руководствоваться очень простым правилом: скрывать следует те и только те ребра, которые не несут “смысловой” нагрузки. Примером важных ребер являются, к примеру, места перегибов (складок одежды), контуры выпуклостей (наколенников, застежки пояса, мышц), контуры будущих деталей текстуры (губы, нос). Иными словами, оставшиеся ребра должны очерчивать детали модели, причем, обязательно минимальным числом непрерывных цепочек ребер ( рис. 1 ). Внимательно посмотрите, какие ребра я спрятал, в файле scn28.max. _Сглаживание тела _ Так как логические части модели “обведены” видимыми ребрами, то сглаживание можно производить на уровне полигонов. Приступим. Чтобы сгладить подошву ( рис. 2 ), выделяем ее и кликаем на кнопке с цифрой 1. Переходим к верхней части обуви. Выделяем боковую часть стопы и назначаем ей вторую группу сглаживания ( рис. 3 ), затем выделяем оставшуюся часть подошвы. Пусть она будет в третьей группе ( рис. 4 ). Выделяем голень и сглаживаем, кликая на кнопке 1. Не запрещено использовать **

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 7

**
Рис. 7. Оставшаяся часть наколенника.
одну цифру несколько раз, главное — следить, чтобы у смежных частей были разные номера групп ( рис. 5 ). Отдельно обрабатываем фиксаторы и чашку наколенника, помещая их во вторую группу ( рис. 6 ). Оставшейся части наколенника присваиваем группу с номером 3 ( рис. 7 ). Аналогично сглаживаем последовательно бедро, килт, бляху пояса, сам пояс, спину и живот, грудную клетку, руки и кисти, шею. Пока эти сегменты модели резко обособлены: кое­где между ними не хватает плавных переходов. Сглаженное туловище смотрите в файле scn29.max. Приступаем к голове персонажа, а именно — к лицу. Выделяем три области, отмеченные красным на рис. 8 и рис. 9. Сглаживаем их, помещая в разные группы. Точно так же поступаем с верхней, нижней губами и шлемом. Сглаживаем выделенную на рис. 10 часть носа, но тут выявляется дефект работы: виден грубый переход от ноздрей к переносице ( рис. 11 ). К счастью, механизм групп сглаживания позволяет всего за пару кликов устранить подобные недостатки. Переходим на уровень редактирования треугольников и выделяем треугольники, между которыми находится нежелательный “шов” ( рис. 12 ). Обратите внимание, что когда мы выделяем треугольники из разных групп сглаживания, то “Макс” убирает цифры с кнопок­номеров групп, которым треугольники принадлежат. В моем случае, выбранными оказались группы 2 и 9. Кликаем, например, на 19 — так мы помещаем граничные треугольники в общую группу, отчего они становятся сглаженными ( рис. 13 ). Пользуясь этой методикой, “подчищаем” модель в области ладоней, задников обуви, подбородка, спины и тыльной стороны колен (см. scn30.max ).

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 8
Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 9

Рис. 8. Область верхней губы. Рис. 9. Щека, подбородок и часть носа.
Вы, разумеется, заметили,

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 10

Рис. 10. Ноздри.
что мы постоянно обрабатываем только одну половинку тела, а вторую используем для визуальной оценки. Пришло время склеить две половинки туловища. Для этого “размораживаем” и удаляем Reference­копию левой половины. В точности повторяя действия по ее созданию, делаем копию типа Copy с требуемым смещением. На уровне элементов к левой половинке тела присоединяем правую. Удаляем присоединенную к правому запястью ладонь, а к левому — кулак. С помощью инструментов Weld / Collapse на уровне вершин “сшиваем” обе половинки тела и запястья с кистями. Сглаживаем шов. С помощью уже использованного нами ранее модификатора STL Check проверяем шов на наличие огрехов. Получившуюся у меня модель смотрите в файле scn31.max. _Модификатор MultiRes _ Нужно сделать еще кое­что важное — добавить в стек модификатор MultiRes. В параметрах модификатора кликаем Generate , не изменяя параметров. Данный модификатор нужен, потому что у движка Unreal Warfare нет LOD ( Level of Detail ). Вы, вероятно, могли наблюдать этот механизм в таких играх, как Sacrifice , Messiah или Enter the Matrix (движок­то у них один). Чем дальше от нас расположен какой­то объект, тем меньше полигонов после работы алгоритма от него будет оставаться. Это колоссально экономит системные ресурсы. Результат применения модификатора смотрите в scn32.max. Посмотрите на свое творение — 30% работы сделано! Лично у меня получилась модель “весом” около 2500 треугольников. __Возможная проблема с Edit UVWs В редакторе Edit UVWs могут пропадать ребра, когда мы используем определенный Material ID. Это может быть проблема как самого 3DS MAX 5.x , так и видеодрайвера. Для устранения проблемы, как правило, достаточно еще раз напомнить “Максу”, какой именно ID нам нужен. В 3DS MAX 6 данная проблема не была обнаружена.
Создание текстурной развертки модели _Что такое текстурная развертка _ Текстура — понятие, находящееся постоянно в обороте, — это картинка, на которой нарисованы детали модели в цвете. Так компенсируется недостаток мелких полигонных деталей. А вот что такое развертка, думаю, не всем очевидно. В среде моделирования каждой вершине по умолчанию соответствуют три величины — координаты X , Y и Z (вообще­то есть еще и другие параметры, например, vertex color и weight , но они нас не интересуют). Текстурные координаты вершины — это дополнительная пара координат U и V. Модель состоит из треугольников, и каждому треугольнику в пространстве { X , Y , Z } соответствует некоторый определенный треугольник в плоскости { U , V }. Значит, модель можно спроецировать из 3D в 2D. Множество спроецированных треугольников и называется разверткой.

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 11
Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 12
Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 13

Рис. 11. Отчетливо виден “шов”. Рис. 12. Ликвидация резкого перехода. Рис. 13. “Шов” устранен!
Плоскость { U , V } — это так называемое параметрическое пространство , где U и V — пропорциональные координаты вершин. Они называются так, потому что принимают значения в диапазоне от 0 до 1. Смысл текстурных координат прост: UV­координаты каждого треугольника сообщают среде, на какой процент от размера текстуры нужно отступить вправо от левого и вниз от верхнего краев текстуры для каждой вершины, чтобы пиксели изнутри полученного плоского треугольника “нарисовать” на соответствующем треугольнике модели в пространстве. Механизм допускает ситуацию, когда равностороннему треугольнику

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 14

Рис. 14. Интерфейс редактора развертки.
развертки соответствует, например, прямоугольный треугольник на модели. В этом случае применяется алгоритм растяжения/сжатия, наподобие тех, что можно встретить в графических редакторах. В свете вышесказанного, стоящая перед нами задача — сделать развертку, у которой: во-первых, треугольники максимально близки по форме к трехмерным оригиналам; во-вторых, отсутствуют пересечения ребер и незапланированные наложения и/или совпадения треугольников; в-третьих, треугольники занимают максимальную область UV­квадрата (то есть число “обрезков” текстуры минимально). _Подготовка материалов _ Разобьем тело модели на две части: голову и туловище. Каждой части мы в дальнейшем назначим по текстуре. Две части — только потому, что так принято в играх на основе UnrealTechnology. На самом деле, одной модели можно назначить до восьми (если не больше, цифра могла увеличиться) текстур с разрешением вплоть до 1024x1024. Для разбиения возвращаемся в стеке модификаторов к EditMesh и на уровне полигонов и выделяем голову с шеей, **

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 15

**
Рис. 15. “Разворачиваемая” часть лица.
после чего в свитке Surface Properties в группе Material в поле ID вводим число 1. Аналогично, всему остальному назначаем 2. ID — идентификатор материала — нужен для того, чтобы отдельным полигонам можно было назначать отдельный материал. Для создания материала будущего скина открываем редактор материалов и выбираем любой свободный слот. Щелкаем на кнопке Standard и в открывшемся списке выбираем материал Multi/Sub­Object. Он появляется в выбранном слоте. Кликаем Set Number и вводим требуемое количество материалов — 2 штуки. Обратите внимание на столбец ID : в нем стоят значения 1 и 2 по умолчанию, поэтому менять ничего не требуется. Щелкаем на кнопке напротив 1. Попадаем в дочерний материал. По аналогии с действиями из раздела “Пространство для моделлинга” (см. первую статью цикла в предыдущем номере “Игромании”), кликаем на кнопке Diffuse из свитка Maps , но теперь выбираем не Bitmap, а Checker. Основной цвет ( Color #1 ) устанавливаем зеленый. Параметры Tiling устанавливаем равными 32. Аналогично поступаем со вторым материалом, расположенным в материале Multi/Sub­Object напротив цифры 2. Цвет в этом случае выбираем синий. Двухкомпонентный материал для нашего персонажа создан. Применяем его к модели. Материал “в квадратик” нам нужен для оценки качества развертки: применив материал к каркасу, мы не должны обнаружить на нем артефактов в виде растяжений/сжатий текстуры. Если текстура состоит из квадратов, то наличие искажений обнаружить очень просто: квадраты превратятся в ромбы.

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 16

Рис. 16. Пересечение граней в развертке лица.
_Модификатор Unwrap UVW _ Сама развертка создается средствами модификатора Unwrap UVW. Давайте познакомимся с его интерфейсом. Имеется всего один уровень редактирования — Select Face. Таким названием разработчики противоречат сами себе, так как Face — это треугольник (в топологии самого же “Макса”), а на деле выбираются полигоны, поэтому просто помните об этом и не путайтесь. Кликаем на Edit , открывается окно редактора развертки Edit UVWs ( рис. 14). Нас будут интересовать лишь некоторые элементы интерфейса этого редактора. Цифрой 1 отмечен выпадающий список для выбора текстурной карты из имеющихся на сцене. Выбираем в списке Pick Texture и в открывшемся окне браузера материалов сначала устанавливаем флаг Mtl Editor , а затем выбираем созданную нами клетчатую текстуру Checker. На первый взгляд ничего в окне Edit UVWs не изменилось. На самом деле,

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 17

Рис. 17. Перемеще- ние вершин.
это не так. Все дело в опции Brightness ( 3 ), значение которой по умолчанию всегда равно 0. Опция отвечает, ни много ни мало, за яркость текстуры в окне редактора развертки и, когда равна нулю, текстура просто не отображается. Устанавливать значение 1 смысла не имеет: клетки будут слишком яркими, и мы просто не увидим на их фоне развертку. Установим Brightness в промежутке от 0.2 до 0.3. По желанию можно отключить опцию Tile Bitmap ( 2 ), которая “размножает” текстуру, что иногда сбивает с толку. Цифрой 5 обозначены инструменты редактора: перемещение, вращение, масштабирование, “свободное” изменение формы выделения и зеркальное отражение. Если мы выделим какой­нибудь участок модели (для примера, я выбрал голову и шею), то этот же самый участок выделится и в развертке ( 6 ). Цифрой 4 отмечен еще один выпадающий список — имеющихся у модели Material ID. Кликнув, например, на втором ID, мы ограничим имеющуюся развертку лишь полигонами головы.

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 18

Рис. 18. Деформации развертки лица.
Вернемся к интерфейсу самого модификатора. Map Channel по умолчанию равен 1. Это номер канала проецирования текстуры (удобнее всего представлять его себе, как количество разных координатных UV­плоскостей, которые используются при текстурировании). Однократное применение модификатора допускает работу лишь с одним каналом. Чтобы использовать второй, третий и т.д. каналы, нужно использовать соответственно два, три и большее число разных экземпляров модификатора Unwrap UVW. Кнопка Planar Map делает следующее: когда мы выделяем участок сетки (например, ту же голову), то отображается проекционная плоскость (отличие этой плоскости от встречаемых раннее в том, что ее позицию нельзя изменить непосредственно), и если кликнуть Planar Map , то в окне редактора мы увидим, что кусок развертки, соответствовавший выделенному участку сетки, отрезан, спроектирован на проекционную плоскость и растянут на весь квадрат. Так делать не всегда удобно. Альтернативой Planar Map является команда Detach Edge Verts (в контекстном меню выделения в редакторе развертки). С ее помощью от имеющегося куска отрезается выделенный участок сетки, с которым затем можно поступить на свое усмотрение. Уже “расправленные” куски развертки не нужно стараться уместить в квадрат с текстурой. Эта работа выполняется так называемым упаковщиком текстур ( Pack UVs ). Текстуры упаковывают вручную тогда, когда, например, текстура будет рисоваться вручную в 2D­редакторе типа Photoshop (т.е. требуется логичное расположение частей развертки). __О релаксации В “Максе” версии 6 появилась очень полезная функция для устранения деформаций развертки ( Tools/Relax Dialog ). Называется это чудо человеческой мысли релаксацией (от англ.relax — ослабить) и представляет собой специальный алгоритм, способный устранять дефекты разверток даже очень сложных высокополигонных моделей. Нельзя не упомянуть, что данный алгоритм доступен в коммерческих плагинах (например, Cebas GhostPainter или Right Hemisphere Deep UV ) и для 3DS MAX 5.x.
_Развертка лица _ Для создания развертки лица ограничимся частью сетки с ID , равным 2. Выделяем часть лица персонажа ( рис. 15 ) и кликаем на Planar Map. Получаем развертку этого участка ( рис. 16 ). Однако она имеет недостаток: в указанных ( рис. 16 ) местах ребра пересекаются. В данном случае это недопустимо. Устраняем дефект так: к выделенным вершинам ( рис. 17 ) применяем инструмент масштабирования. На паре вершин масштабирование работает как уменьшитель расстояния между этими вершинами. Этот метод весьма универсален и еще не раз пригодится. Таким образом, пересечение граней развертки ликвидировано. Все изменения сразу же вступают в силу, и текстура на модели “смещается”, что можно легко пронаблюдать.

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 19
Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 20

Рис. 19. Выделено защитное стекло шлема. Рис. 20. Боковые части шлема.
Теперь устраняем

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 21

Рис. 21. Финальный вид развертки головы.
неявные дефекты — деформации текстуры. У каждого из двух материалов, образующих заготовленный двухкомпонентный, включаем опцию отображения в видовом окне. Сеточный каркас окрасился “в квадратик”. Голова — в синий цвет, туловище — в зеленый. Фронтальный вид головы не позволяет выявить артефактов, а вот профильный — позволяет! На рис. 18 отмечены области растяжений, которые необходимо убрать. Для этого применяем уже использованный метод “масштабирования вершин” на граничных вершинах треугольников, где обнаружились деформации. Единственное, но важное замечание к этому методу: действия надо производить над парами противоположных вершин, иначе развертка потеряет симметричность, что нежелательно. При попытке устранить растяжение над верхней губой, сталкиваемся с проблемой: куда бы мы ни двигали вершины, портятся участки справа и слева. С носом та же проблема. Это тот случай, когда (слабонервных попрошу не читать) нос надо ампутировать. Выделяем полигоны носа в Viewport — в UV­редакторе вершины носа также выделились, — кликаем на Detach Edge Verts из контекстного меню. Перемещаем “отрезанный” нос за границу лица. В развертке на месте носа возникла дыра, которой мы и воспользуемся для устранения растяжений лица. Перемещаем вершины, чтобы максимально разгладить текстуру на сетке. Область носа без дробления или увеличения в размерах сделать “идеальной” сложно: наблюдается несильное растяжение на ноздрях, что, впрочем, для игровой модели совсем не критично и является вполне допустимым. Результат, к которому пришел я, можно посмотреть в файле scn33.max. **

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 22

Рис. 22. Этапы “разворачивания” туловища._Развертка шлема и шеи _Выбираем стекло шлема (рис. 19) и снова применяемPlanar Map**. Возможные растяжения текстуры по краям устраняем по уже усвоенной методике. Затем мы разворачиваем боковые части шлема (рис. 20). Планарная проекция теперь не поможет. Используем другой способ — встроенный в UV­редактор стандартный мэппер. Отрезаем (Detach Edge Verts) выделенную часть развертки и применяем к ней инструментMapping/Normal Mapping. В открывшемся окошке из списка стандартных способов мэппинга выбираемTop/Bottom Mapping. Настоятельно рекомендую экспериментировать со стандартными мэпперами “Макса”, они существенно упрощают жизнь. Особенно когда текстурируемый объект симметричен.

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 23

Рис. 23. Создание развертки ног.
Однако появилась еще одна проблема: полученная часть развертки не соответствует по масштабу тем, что мы уже сделали. Это выражается увеличением размера квадратиков текстуры. Выход из данной ситуации напрашивается сам собой: увеличим новый кусок развертки с помощью инструмента равномерного масштабирования так, чтобы квадратики везде по размеру стали одинаковы (см. scn34.max ). Действуя аналогично, “расправляем” оставшиеся участки развертки головы и шею. Лобную, теменную и затылочную части шлема “разворачиваем” с помощью стандартного планарного проектирования (см. scn35.max ). Шею разбиваем на четыре сегмента: передний, задний и два боковых. Каждый сегмент текстурируем по отдельности или в паре с противоположным (см. scn36.max ).

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 24

Рис. 24. Развертка рук и небольших областей.
_Упаковка развертки головы _ Следующий этап моделирования — упаковка развертки. Можно попробовать использовать автоматическую упаковку ( Tools/Pack UVs ), но результат получается не такой, как хотелось бы (автоупаковщик тем эффективнее, чем большее число кусков надо упаковать): остается слишком много “обрезков” текстурного пространства. У нас порядка десяти кусков, давайте разместим их вручную в квадрате. Это совсем не сложно: поворачиваем и перемещаем куски. В этой работе есть только один нюанс. Нельзя масштабировать отдельный кусок развертки, только все одновременно, иначе наша работа по выравниванию размера квадратиков будет испорчена! На рис. 21 можно лицезреть получившуюся у меня развертку.

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 25

Рис. 25. Финальный вид развертки тела.
_Развертка тела _ Перед нами возникает маленькая загвоздка. Как выбрать полигоны плеч, если мешают наплечники? Существует несколько способов решить данную проблему. Выберем самый логичный и простой: текстурируем наплечники и область тела вокруг наплечников, а ту часть тела, что скрыта под наплечниками, вообще не текстурируем. Важный момент: развертки плеч можно расположить даже поверх каких­то других участков, потому что плечи под наплечниками просто невидимы.

Игромодельер. Создание модели для Unreal Tournament 2003. Часть 2 - фото 26

Рис. 26. Внешний вид “развернутой” модели.
На рис. 22 отражены этапы создания развертки туловища. Ко всем участкам (фрагменты 1—5 ) мы применяем обычное планарное проектирование и, как обычно, устраняем деформации полученной развертки. Аналогично поступаем и с частями сетки, выделенными на рис. 23 (фрагменты 3—5 ). Куски каркаса, отмеченные как 1 и 2 на том же рисунке, преобразуем в развертки путем применения Top/Bottom Mapping (см. scn37.max ). Все области, обозначенные на рис. 24 числами 1—5 и 7—11 , преобразуются в двухмерную развертку точно так же. Внутреннюю ( 3 ) и внешнюю ( 6 ) части кулака помогает обработать мэппер Right/Left Mapping. Область пальцев, изображенная на фрагменте 13 , легко разворачивается с помощью Unfold Mapping. Наконец, масштабируем куски и упаковываем в текстурный квадрат ( рис. 25 ). Если отображение текстур в видовом окне отключено, включаем эту опцию и сравниваем внешний вид модели с рис.26 (см. scn38.max ). __ На CD и DVD Для удобства мы разместили на нашем компакте все скриншоты, иллюстрирующие данную статью, в большом разрешении. А также все сцены 3DS Max (расширение .max ), детально иллюстрирующие создание модели.
*** Итак, у нас уже есть качественная сглаженная модель, полностью подготовленная к двум самым, скажем так, креативным этапам нашего труда — текстурированию и анимированию. Чем мы и займемся в заключительной части цикла. Кстати, к следующей статье цикла “Игромодельер” будет прилагаться небольшой подарок… Какой? Узнаете, прочитав следующий номер журнала.

Комментарии
Чтобы оставить комментарий,Войдите или Зарегистрируйтесь