Одежда пока является очень статичной, потому что вы на самом деле ничего с ней не сделали, кроме как сохранили координаты ее точек и данные пружин. Чтобы заставить ее двигаться и развеваться, необходимо приложить силу.
На каждую точку одежды действует отдельная сила или даже набор прилагаемых и естественных сил. Эти силы могут иметь любой источник: ветер, гравитация, трение или кто-то просто потянул одежду. Пружины выступают в роли другого вида сил; как только две точки, соединенные пружиной, движутся навстречу или друг от
1. Автор шутит. Или нет? Впрочем, после окончательного реформирования нашего образования мы уже не будем задаваться таким вопросом. - Примеч. науч. ред.
друга, пружина расширяется или сжимается в соответствии с законом Гука, т. е. пока сила растяжения (сжатия) пружины не скомпенсирует внешнюю силу. Другими словами, пружины пытаются создать достаточную силу для поддержания статического равновесия.
Другим аспектом сил и движения одежды является скорость. По мере того как силы, такие как гравитация, действуют на точки одежды, эти точки приобретают скорость и момент. Это означает, что точки будут продолжать двигаться в направлении действия силы, пока что-нибудь, как например сила трения или противодействия, не остановит их. Использование скорости и ускорения делает движения одежды более реалистичными, а реализм как раз то, что мы хотим видеть в своих проектах.
Замечание. Момент вычисляется умножением массы на вектор ускорения (F=ma). Момент точки, а не векторы силы, увеличивает скорость точки, в конце концов, приводя ее в движение.
При моделировании одежды силы, такие как гравитация и скорость, представлены направленными векторами, которые используются для перемещения точек одежды. Длина каждого вектора определяет величину действующей силы. Чтобы корректно эмулировать эти силы, необходимо добавить два связанных вектора в класс точки одежды.
class cClothPoint {
D3DXVECTOR3m_vecPos; // трехмерные координаты точки float m_Mass; // Масса точки (0=прикрепленная) float m_OneOverMass; // 1 / Mass (0 = прикрепленная к месту) D3DXVECTOR3 m_vecForce; // Вектор силы (ускорения) D3DXVECTOR3m_vecVelocity; // Вектор скорости
};
Изначально сила и скорость точки устанавливаются в 0, означая, что не происходит направленного движения и приложения сил. Для каждого кадра анимации необходимо сбросить векторы силы в 0 и приложить внешние силы, такие как ветер и гравитация, и внутренние, такие как сила пружин. Равнодействующая всех сил хранится в векторе m_vecForce.
Для того чтобы очистить вектор силы, просто просмотрите их список и сбросьте значения, как я сделал тут:
for(DWORD i=0;i<NumPoints;i++)
ClothPoints[i].m_vecForce = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
В начале имитации необходимо очистить скорость каждой точки, используя следующий код:
for(DWORD i=0;i<NumPoints;i++)
ClothPoints[i].m_vecvelocity = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
После того как вы очистили векторы силы и скорости, к точкам можно прикладывать различные силы. Давайте начнем с самых простых - сил тяжести и ветра.
Применение гравитации и ветра
Гравитация является естественной силой, которая притягивает объекты друг к другу. Более тяжелые объекты притягивают более маленькие. В отношении Земли это означает, что все объекты падают на землю (еще один пример, когда здоровяки побеждают). Меш одежды не является исключением. Чтобы корректно симулировать движения одежды, каждая точка ее меша должна иметь возможность упасть на землю (за исключением тех точек одежды, которые закреплены или присоединены к другим объектам, что не позволяет им двигаться).
В реальной жизни, по мере того как объекты падают, у них увеличивается скорость. Для всех объектов ускорение является более или менее постоянной величиной, равной 9.8 м/с2. Через секунду, после того как вы уронили объект, его скорость будет 9.8 м/с. Через две секунды, скорость объекта станет равной 19.6 м/с. Причина того, что некоторые объекты падают быстрее (развивая большую скорость), чем другие, является то, что на объекты, имеющие разную форму, действует разная сила сопротивления воздуха (противодействующая сила), которая и уменьшает их ускорение. Предельная скорость - это максимальная скорость, которую может развить объект, прежде чем сила сопротивления воздуха не прекратит увеличение ускорения тела.
При моделировании гравитацию можно представить направленным вектором. Этот направленный вектор будет добавляться к вектору силы каждой точки, чтобы она могла двигаться. Для определения вектора гравитации можно использовать следующий код (полагая, что гравитация действует в отрицательном направлении оси у):
// Создать вектор силы тяжести (величина притяжения равна -9.8) ЭЗЕХУЕСТОк уесСгауілу = ВЗЕХ¥ЕСТОкЗ(0.0г, -9.8г, О.Ог);
После того как вы определили вектор гравитации, вы можете добавить его к каждой точке одежды. (Не забудьте сначала очистить векторы сил точки.) В следующем кусочке кода можно заметить, что вектор гравитации масштабируется на значение массы. Это очень важно, т. к. все силы, в конце концов, масштабируются на соответствующие массы. (Это необходимо для вычисления момента, помните, что сила, необходимая для движения объекта равна массе, умноженной на ускорение.) На данный момент масштабирование вектора гравитации позволяет убедиться, что все объекты будут падать с правильной скоростью независимо от их массы.
гог(ВЖЖЭ і = 0;і<РТшгіРоіплв;і + +)
С1оспРоіпсв[і].т_уесРогсе += (уесСгауілу * \ С1оспРоіпсв[і].т_Мавв);
Ветер, - это другая сила, которую можно часто встретить на Земле. Вы знаете, как одежда любит поймать ветер и развеваться вместе с ним? Хорошо, именно сила ветра заставляет точки одежды двигаться. Вы можете легко создать этот же эффект при моделировании одежды. Ветер также представлен с помощью направленного вектора.
Совет. Т. к. вектор гравитации является направленным, вы можете изменить его так, чтобы гравитация действовала вверх, влево, вправо или влюбом направлении, в котором вы захотите. Представьте использование обратной гравитации, которая бы заставляла взлетать одежду!
// Сделать ветер, дующий в направлении оси х Р3РХ¥ЕСТОР3 vecWind = Р3РХ¥ЕСТОР3(0.5г, 0.0г, 0.0г);
Сначала вам может показаться, что силу ветра необходимо прикладывать так же, как и гравитационные силы - прибавляя направленный вектор к силе каждой точки. Чтобы приложить силу ветра, необходимо просмотреть все грани одежды и, основываясь на нормали каждой грани, вычислить вектор направления силы, создаваемой ветром.
Как вы можете видеть на рис. 13.2, каждая грань меша имеет нормаль, которая является направлением грани. На рис. 13.2 также показано направление приложения ветра и угол между силой ветра и нормалью грани.
Угол между вектором нормали грани и вектором силы очень важен - он позволяет определить величину силы, прикладываемой к точкам. Чтобы лучше это понять, представьте, что вы едете на машине и высунули руку в окно. Если рука будет расположена параллельно земле, то ветер будет обтекать ее, не отклоняя назад. Однако, если повернуть руку, величина силы (силы ветра), которая отталкивает вашу руку назад, увеличится.
Как вы можете видеть, угол между векторами определяет величину прикладываемой силы ветра. Чтобы вычислить этот угол, используется скалярное произведение нормализованного вектора нормали грани и вектора ветра. Единственной проблемой является то, где взять эту нормаль грани?
При использовании объекта ГОЗВХВавеМеБП вы можете получить список индексов вершин, используемых каждой гранью меша. Если вы сначала получите эти индексы, а потом используете их для получения текущих координат вершин, вы можете вычислить их векторное произведение, чтобы получить нормаль грани.
Чтобы получить индексы до начала моделирования одежды, вы можете создать массив 16-битных значений (или 32-битных, в зависимости от настроек меша) и заполнить его значениями из буфера индексов меша.

Рис. 13.2. Угол между нормалью грани и вектором ветра используется для вычисления величины силы, прикладываемой к каждой точке
// pClothMesh = предварительно загруженный объект ID3DXMesh
// Буфер индексов, который будет содержать индексы граней меша unsigned short *FaceIndices = NULL;
// Создать массив индексов, основываясь на количестве граней, содержащихся
//в объекте меша.Помните,что каждая грань имеет 3 индекса.Выделяется
// место под 32-битные индексы.
DWORD NumFaces = pClothMesh->GetNumFaces();
Facelndices = new DWORD[NumFaces * 3];
// Теперь заблокируем меш, чтобы получить индексы unsigned short *pIndices;
pClothMesh->LockIndexBuffer(D3DLOCK_READONLY, (void**)&pIndices);
// Просмотреть все индексы и сохранить их for(DWORD i=0;i<NumFaces*3;i++)
FaceIndices[i] = (unsigned short)*Indices++;
// Разблокировать буфер индексов pClothMesh->UnlockIndexBuffer() ;
После выполнения предыдущего кусочка кода у вас будет массив, содержащий индексы - по три индекса на каждую грань. Используя эти индексы, вы можете просмотреть весь список граней и вычислить нормаль для каждой.
for(i=0;i<m_NumFaces;i++) {
// Получить три вершины, образующие грань DWORD Vertexl = FaceIndices[i*3]; DWORD Vertex2 = FaceIndices[i*3+1]; DWORD Vertex3 = FaceIndices[i*3+2];
// Вычислить нормаль грани
D3DXVECTOR3 vecV12 = ClothPoints[Vertex2].m_vecPos - \
ClothPoints[Vertex1].m_vecPos; D3DXVECTOR3 vecV13 - ClothPoints[Vertex3].m_vecPos - \
ClothPoints[Vertex1].m_vecPos; D3DXVECTOR3 vecNormal;
D3DXVec3Cross(&vecNormal, &vecV12, &vecV13); D3DXVec3Normalize(&vecNormal, &vecNormal) ;
После того как мы получили нормаль грани (сохраненную в объекте vecNormal), вычисляется ее скалярное произведение с вектором ветра для определения угла между ними.
// Вычислить скалярное произведение нормали и ветра float Dot = D3DXVec3Dot(&vecNormal, vecWind);
Имея результат скалярного произведения, можно масштабировать вектор нормали грани для вычисления величины силы, прикладываемой к каждой точке этой грани. (Помните, что каждой вершине соответствует точка.)
// Масштабировать нормаль на результат скалярного произведения vecNormal *= Dot;
// Применить нормаль к вектору силы точки ClothPoints[Vertex1].m_vecForce += vecNormal; ClothPoints[Vertex2].m_vecForce += vecNormal; ClothPoints[Vertex3].m_vecForce += vecNormal; }
После того как вы просмотрели все индексы грани, вы получаете векторы сил точек, заполненные соответствующими значениями, которые позволяют одежде развеваться на ветру! Теперь вы готовы перейти к вычислению следующего важного набора сил, используемого при моделировании одежды — сил растяжения пружин одежды.
Применение сил пружин
Каждая пружина меша одежды первоначально имеет длину покоя. Эта длина покоя равна расстоянию между двумя точками, которые пружина соединяет. При обработке пружин необходимо вычислить текущую длину каждой пружины и определить, каким образом каждая пружина влияет на силы, действующие на точки.
Для пружин, которые стали короче их длины покоя, необходимо растянуть пружины и оттолкнуть присоединенные к ним точки друг от друга. Для пружин, которые стали длиннее длины покоя, необходимо сжать пружины, таким образом подтолкнув соединяемые пружиной точки друг к другу.
Растяжения и сжатия пружин происходят в соответствии с законом Гука, который гласит, что сила растяжения тела пропорциональна изменению длины этого тела. Это означает, что сила, создаваемая пружиной, пропорциональна длине пружины (или даже разности текущей длины пружины и ее длины покоя). Математически, закон Гука выглядит так:
Б = к*х
Где Б представляет собой действующую силу, х - изменение размера пружины (разницу текущей длины пружины и ее длины покоя, как показано на рис. 13.3), к -константу пружины; она определяет насколько величина изменения длины пружины влияет на силу. Чем больше константа пружины, тем большая действует сила.

Рис. 13.3. Пружина, изображенная слева, находится в покое (равновесии), в то время как пружина справа — растянута. Величина силы пружины определяется из изменения длины пружины и ее константы
Например, вы хотите вычислить величину силы растяжения пружины. Эта пружина имеет длину покоя 128 единиц и в данный момент растянута до 200 единиц. Вычитая длину покоя из текущей длины, получим 200-128=72; это значение является изменением размера пружины х. Умножим полученное значение на константу пружины к. В результате получим величину прилагаемой силы (F) равной 0.4x72=28.8.
28.8 - это значение силы, используемой для сближения точек пружины. На каждую точку, находящуюся на концах пружины, действуют силы одинаковые по модулю и противоположные по направлению. После того как вы получили величину силы, вы можете добавить ее к остальным силам точки. Позже эта рассчитанная равнодействующая сила будет использована для вычисления ускорения, которое в свою очередь изменяет скорость точек.
Единственное, о чем я еще не сказал, это откуда брать значения константы пружин, используемых в вычислении силы. Помните, ранее мы определили вещественное значение, представляющее жесткость пружины? Ну, значение жесткости это и есть константа пружины! Вы можете использовать значение константы/жесткости пружины, обычно обозначаемое символом k или ks, для масштабирования прикладываемой силы пружины.
Я уверен, вас интересует, какие допустимые значения жесткости пружины можно использовать. Ну, простого ответа не существует. Чем больше жесткость, тем большая сила производится пружиной. Обычно этого достаточно - установка большого значения жесткости будет замечательно работать. Единственной проблемой при моделировании является то, что большое значение жесткости создаст слишком большую прикладываемую силу, в результате чего одежда может двигаться непредсказуемым образом. Если же используется слишком маленькое значение жесткости, то одежда вытянется и будет выглядеть как кусок резины.
Опять же, какого значения жесткости будет достаточно? Для примеров этой главы я использовал значение жесткости равной 4. При моделировании я предлагаю вам самостоятельно устанавливать жесткость в разнообразные значения и посмотреть какое значение подойдет лучше всего.
Чтобы рассчитать пружины при моделировании, необходимо просмотреть весь их список в меше, используя цикл for...next, и получить текущие их длины (расстояния между двумя их точками).
for(DWORD i=0;i<NumSprings;i++) {
// Получить значения индексов двух точек DWORD Pointl = ClothSprings[i].m_Point1; DWORD Point2 = ClothSprings[i].m_Point2;
/ / Получить вектор между точками
D3DXVECTOR3 vecSpring = ClothPoints[Point2].m_vecPos - \ ClothPoints[Point1].m_vecPos;
// Получить длину вектора между двумя точками float SpringLength = D3DXVec3Length(&vecSpring);
Текущее расстояние между двумя точками пружины является очень важным. Помните, ранее в этой главе, мы говорили, что пружина может растягиваться или сжиматься. Вычислив сначала вектор между двумя точками пружины, вы можете потом определить текущую длину пружины, используя функцию D3DXVec3Length. Для вычисления силы пружины используйте закон Гука. Он включает в себя умножение величины изменения длины пружины (длина покоя, вычтенная из текущей длины) на значение жесткости пружины для получения скаляра силы пружины.
// Вычислить скаляр прикладываемой силы float SpringForce = Spring->m_Ks *
(SpringLength - Spring->m_RestingLength);
Вектор vecSpring также является очень важным при определении направления движения точек. Нормализовав вектор текущей длины пружины и умножив его на SpringForce, вы можете быстро вычислить вектор силы, действующий на каждую точку, присоединенную к пружине.
// Нормализовать вектор пружины vecSpring /= SpringLength;
// Умножить на значение силы vecSpring *= SpringForce;
Таким образом получим вектор, представляющий собой величину силы, прикладываемой к каждой точке пружины. Добавим его к вектору суммарной силы первой точки и вычтем его из вектора суммарной силы второй точки для перемещения их в правильном направлении (т. о. либо сближая, либо отдаляя их друг от друга)
// Приложить силу к вектору сил точек ClothPoints[Point1].m_vecForce += vecSpring; ClothPoints[Point2].m_vecForce -= vecSpring; }
Вот и все, что касается пружин одежды! На данный момент вы почти готовы обновить скорость и положение каждой точки на основе результирующей силы, но сначала необходимо приложить самую важную силу - трение.
Замедление движения с помощью трения
Чтобы все выглядело реалистично, одежда должна придерживаться законов трения. По мере того как одежда движется в среде, такой как воздух, она замедляется. Трение фактически является противодействующей силой, независимо оттого является ли она гравитационной силой, турбулентностью воздуха или трением. Для упрощения, я буду называть комбинацию этих сил просто трением.
Если вы не примените трение к точкам одежды, у вас возникнет проблема -одежда никогда не перестанет двигаться, и моделирование одежды будет нестабильным (из-за скоростей ваш меш выйдет из-под контроля). Конечно, сила тяжести будет тянуть тело вниз, но горизонтальное движение никогда не прекратиться. Применив трение, вы инициируете медленное замедление движения, если против трения не действует большая сила. Также, используя амортизированное трение пружин, вы можете увеличить стабильность, сократив величину силы пружины.
Чтобы применить трение (в данном случае называемое линейной амортизацией) к точкам одежды, необходимо уменьшить вектор силы каждой точки на небольшой процент вектора ее скорости. (Амортизация на самом деле является коэффициентом пропорциональности силы к скорости, Б=КУ.) Это процентное соотношение, заданное в виде вещественного числа, обычно находится в диапазоне от -0.04 до -0.1. (Отрицательный диапазон означает, что вы уменьшаете прикладываемую силу, вместо того чтобы увеличивать ее.) Чем больше это значение, тем большая величина трения применяется. Например, при использовании значения -1 создается впечатление, что одежда находится в чане с маслом!
Предположим, что используется значение линейной амортизации, равное -0.04. Вы можете просмотреть все точки прямо сейчас. Для каждой точки необходимо прибавить вектор скорости, масштабированный на значение амортизации к вектору силы точки, как показано в следующем коде:
гог(Р«ОРР 1 = 0;1<№атРо1.псв;1 + + ) {
С1оипРо1пив[1].т_уесРогсе+= (-0.04г * \ С1оспРо1псв[1].т_уес¥е1ос1.су);
}
Что же касается трения, действующего на пружины (называемого амортизирующим трением), необходимо добавить значение амортизации в вычисление силы пружины, как было показано ранее. Значение амортизации, как вы уже, наверное, догадались, было определено в классе, содержащем данные пружины! Значение трения должно быть немного больше, чем значение линейной амортизации, и обычно лежит в диапазоне от 0.1 до 0.5. В примерах я буду использовать значение 0.5.
Чтобы применить амортизацию к пружинам, вернитесь к вычислению их сил.
for(DWORD i=0;i<NumSprings;i++) {
// Получить номера индексов двух точек DWORD Pointl = ClothSprings[i].m_Point1; DWORD Point2 = ClothSprings[i].m_Point2;
// Получить вектор, соединяющий точки
D3DXVECTOR3 vecSpring = ClothPoints[Point2].m_vecPos - \ ClothPoints[Point1].m_vecPos;
// Получить длину вектора, соединяющего точки float SpringLength = D3DXVec3Length(&vecSpring);
// Вычислить скаляр прикладываемой силы float SpringForce = Spring->m_Ks *
(SpringLength - Spring->m_RestingLength);
Теперь необходимо вычислить значения скаляра амортизации пружины на основе нормализованной относительной скорости двух точек (разности их скоростей) и значения амортизации пружины. Чтобы вычислить нормализованную относительную скорость двух точек, необходимо просто посчитать разность двух векторов скоростей и поделить ее на текущую длину пружины.
// Получить относительную скорость точек D3DXVECTOR3 vecVelocity = CState2->m_vecVelocity - \
CState1->m_vecVelocity; float Velocity = D3DXVec3Dot(&vecVelocity, \
fcvecSpring) / SpringLength; // Применить значение амортизации пружины (m_Kd) float DampingForce = Spring->m_Kd * Velocity;
Далее идет оставшийся код вычисления силы пружины, за исключением того, что к вектору пружины применяется не только сила пружины (SpringForce), но и сумма скаляров силы пружины и силы амортизации (DampingForce).
// Нормализовать вектор пружины vecSpring /= SpringLength;
// Умножить на скаляры силы (скаляры пружины и амортизации) vecSpring *= (SpringForce + DampingForce);
// Применить силу к вектору силы точки ClothPoints[Point1].m_vecForce += vecSpring; ClothPoints[Point2].m_vecForce -= vecSpring;
}
После того как вы скорректировали силы в соответствии со значением трения, вы можете прикладьшать эти силы к скорости каждой точки и вычислять их движение.
Приложение сил и передвижение точек во времени
На данный момент силы каждой точки должны быть вычислены и сохранены в векторе силы. Эти векторы сил представляют собой величины ускорений, применяемые к скоростям каждой с течением времени. Векторы скоростей также имеют направление и определяют направление и скорость движения каждой точки при моделировании.
Итак, если имеется вектор силы равный 0, -9.8, 1, ускорение будет равно 9.8м/с в отрицательном направлении оси у и 1 м/с в положительном направлении оси 2. Этот перевод силы в ускорение (использование одного и того же вектора для ускорения и силы) является немного неправильным, но зато замечательно работает при моделировании, так что пока мы проигнорируем законы физики.
Единственное, о чем необходимо побеспокоится сейчас, - это время. Видите ли, каждый раз, когда вы обновляете имитацию, необходимо получить значение прошедшего времени, чтобы точки одежды могли перемещаться в соответствии с ним. Предположим, вы хотите рассчитать движение точек только для 400 миллисекунд. Как это можно сделать, не рассчитывая имитацию 400 раз, т. е. раз в миллисекунду? Необходимо получить имитацию одежды в реальном времени, черт побери!
Теперь волнуйтесь, мой друг! Используя так называемое явное интегрирование, вы можете определить ускорение, достигнутое за промежуток времени, и как это ускорение влияет на скорость точки за тот же период времени. Так что вместо того, чтобы выполнять моделирования каждую миллисекунду, вы можете выполнять его каждые 40 миллисекунд, таким образом значительно ускоряя расчеты!
Совет. Если вы хотите задать время в миллисекундах, а не в секундах, как показано в коде примера, просто добавьте дробное десятичное значение. Чтобы его вычислить, разделите 1 на 1000 и умножьте на количество миллисекунд. Например, одна миллисекунда это 0.001, десять миллисекунд это 0.01, а сто миллисекунд это 0.1.
В данном примере я использовал интегрирование вперед, которое позволяет масштабировать вектор или значение на набор дискретных величин (время). Используя силу точки (которая представляет собой ее ускорение), вы можете вычислить, насколько изменится скорость за определенный период времени, как показано далее:
// Т1теЕ1арБео1 = количество прошедших секунд С1оиЬРо1пив[Ыит].т_уесУе1осд_иу + = Т1теЕ1арБеО * \ С1оспРо1псв[Шт].пту^есРогсе;
Используя тот же самый период времени, вы можете вычислить насколько переместится точка, используя скорость.
С1оиЬРо1пиБ[]Мит].т_уесРов += Т1теОЕ1арБеО * \ С1оспРо1псв[Кшт].т vecVe1ocity;
Итак, интегрирование вперед является не чем иным как масштабированием векторов. Просто, не так ли? Единственное, о чем я не упомянул, это то, что вам необходимо принять во внимание массы точек. Помните, чем большую массу имеет объект, тем большую силу необходимо приложить, чтобы сдвинуть его. Я имею ввиду момент, т. е. то, что комбинированная сила точки (представленная вектором силы) должна быть масштабирована на массу, чтобы вычислить фактически применяемое ускорение. Масштабирование вектора силы на значение массы (на самом деле на значение 1/масса) при интегрировании замечательно с этим справляется.
С1огпРоіпгв[Тит].т_хес¥е1осігу += ТітеЕ1арвеб * \ С1огпРоіпгв[Тит].т_0пе0хегМавв * \ С1огпРоіпгв[Тит].т_хесРогсе;
Подытожив, необходимо умножить вектор силы каждой точки на массу (1/масса) и прошедшее время, после чего добавить результирующий вектор к вектору скорости точки. Вот отрывок кода, который выполняет все это для каждой точки одежды:
// ТітеЕІарвеб = количество обрабатываемых секунд гог^ОРР і = 0;і<РТитРоіпгв;і + +) {
// Интегрировать скорость
С1огпРоіпгв[Тит].т_хес¥е1осігу += ТітеЕІарвеб * \ С1огпРоіпгв[Тит].т_0пе0хегМавв * \ С1огпРоіпгв[Тит].т_хесРогсе;
// Интегрировать положение
С1огпРоіпгв[Тит].т_хесРов += ТітебЕ1арвеб * \ С1огпРоіпгв[Тит].т_хес¥е1осігу;
}
Вот и все, мой друг! Мы успешно вычислили скорость и обновили положение каждой точки меша одежды! Далее необходимо взять данные точек и использовать их для воссоздания и визуализации меша одежды.
⇐Получение данных одежды из мешей || Оглавление || Воссоздание и визуализация меша одежды⇒