Технічні Деталі
Освітня та історична документація про те, як працює система, що підтримує цей сайт
Трансформації Патернів
Counter-Strike 2 та Counter Strike Global Offensive використовують одну базову текстуру (наприклад, Case Hardened) для генерації сотень унікальних варіантів скінів через систему рандомізованих трансформацій. Це досягається за допомогою детерм інованого механізму на основі сіду — ключ до розуміння та відтворення патернів Blue Gem поза грою.
Чому це називається Paint "Seed"?
Для генерації різноманітності текстур послідовним, але рандомізованим способом, Valve використовує псевдовипадковий рівномірний генератор, вбудований у Source Engine. Оскільки комп'ютери є детермінованими машинами, вони потребують початкового значення — сіду — для створення випадковості. У CS2 кожному скіну призначається paint seed від 1 до 999. Цей сід ініціалізує генератор випадкових чисел, який потім створює певний набір значень для застосування трансформацій до текстури.
Оскільки цей алгоритм є детермінованим і однаковим на всіх платформах, заданий paint seed завжди дасть ту саму трансформацію — гарантуючи, що скін виглядає ідентично на кожній системі.
TL;DR: Paint seed ініціалізує псевдовипадковий генератор Valve для визначення позиції, обертання та масштабу базової текстури для шарів патерну, зносу та бруду.
Як обчислюються трансформації текстур?
Щоб зрозуміти, як CS2 рандомізує вигляд скінів, корисно розуміти UV-розгортку: кожна модель зброї має UV-макет, який визначає, як 2D-текстура обгортається навколо 3D-сітки. Valve застосовує текстуру до цієї UV-карти, а потім використовує paint seed для рандомізації її переміщення, обертання та масштабу.
Це впливає не лише на основний патерн (як кольорові плями Case Hardened), але й на накладки зносу та бруду — текстури, які додають подряпини, старіння та забруднення.
Якщо стиль скіну не використовує випадкове зміщення (наприклад, можливо, однотонні скіни як Asiimov), він не буде підпадати під цю систему.
UV Mapping Concept
Hover over the cube faces or UV map to see how 3D surfaces map to 2D texture coordinates
3D Model
UV Map (Unfolded)
Покроково: Paint Seed → Трансформація
1. Визначення базового масштабу
Кожна зброя та стиль фарбування мають певний масштаб, зазвичай визначений у файлі items_game.txt від Valve. Базовий масштаб обчислюється з довжини зброї та UV-масштабу, залежно від стилю фарбування:
if (paint_style == 3 || paint_style == 6) {
scale = weapon_length * 0.027777778;
} else {
scale = uv_scale;
}Наприклад, Karambit має:
- WeaponLength = 9.813000
- UVScale = 0.438000
- → що дає базовий масштаб 0.438
2. Генерація випадкових значень
Після визначення базового масштабу, paint seed використовується для генерації 11 псевдовипадкових float-значень, які визначають, як застосовується кожен шар текстури:
| Шар текстури | Параметри |
|---|---|
| Патерн | масштаб, зміщенняX, зміщенняY, обертання |
| Знос | масштаб × множник, зміщенняX, зміщенняY, обертання |
| Бруд | масштаб × множник, зміщенняX, зміщенняY, обертання |
Ці float-значення генеруються у фіксованому порядку та діапазонах:
Патерн
- translateX → 0.0 – 1.0
- translateY → 0.0 – 1.0
- rotate → 0.0 – 360.0
Знос
- scaleMult → 1.6 – 1.8
- translateX → 0.0 – 1.0
- translateY → 0.0 – 1.0
- rotate → 0.0 – 360.0
Бруд
- scaleMult → 1.6 – 1.8
- translateX → 0.0 – 1.0
- translateY → 0.0 – 1.0
- rotate → 0.0 – 360.0
These values are applied independently to each layer using the following logic:
Transform Order: Scale → Translate → Rotate(Repeated for pattern, wear, and grunge)Приклад: Karambit | Case Hardened — Paint Seed 633
Використовуючи наведену вище логіку, paint seed 633 на Karambit дає:
- Base Scale: 0.438
- Translate X: 0.471 → shifts the pattern ~47% left
- Translate Y: 0.624 → shifts the pattern ~62% up
- Rotation: 96.7° counterclockwise
Шари зносу та бруду отримують власні значення, також похідні від сіду, але з іншими множниками та кутами.
Remaining Mystery: Rotation Center
Довгий час залишалося одне питання: де саме знаходиться точка обертання? Хоча кути <180° начебто оберталися навколо верхнього лівого кута UV, вищі кути поводилися непослідовно при спробі симулювати результат поза грою.
From Reddit to pattern.wiki
Найранніша спроба зворотної інженерії цієї системи прийшла з відомого посту на Reddit від Step7750 у 2016 році. Цей пост виклав основну ідею роботи трансформацій на основі сіду — і роками він слугував де-факто довідкою для спільноти.
Згодом сайти як Broskins та csfloat.com створили робочі системи попереднього перегляду — але фактична логіка, яку використовує Valve, залишалася недокументованою для публіки.
Це змінилося на початку 2024 року, коли pattern.wiki опублікував повний розбір процесу трансформації — включаючи конкретні значення, математику та візуальні приклади. Це був значний крок вперед.
What We Clarified
While pattern.wiki's implementation clearly works in practice, their description of the transform order and rotation pivot didn't fully align with how Source behaves under the hood. Through testing and debugging, we clarified a few subtle (but important) points:
- All transforms are applied around the origin (0, 0) — not after translation
- The effective matrix order is: T₂ × R × S × T₁
Template Transform Application (Finalized Model)
To sample the correct area of the texture using a paint seed, we apply a sequence of affine transformations — each one modifying the UV coordinates before sampling the base texture.
Step-by-Step Transform Chain
1. Центроване зміщення
Зміщення патерну за допомогою зсувів paint seed, але центрування трансформації навколо початку UV:
translate(offsetX - 0.5, offsetY - 0.5)2. Масштаб (навколо початку)
Рівномірне масштабування патерну за допомогою базового масштабу — навколо початку (0, 0):
scale(scaleX, scaleY)3. Обертання (навколо початку)
Обертання патерну проти годинникової стрілки від початку:
rotate(rotation)4. Додатковий зсув (фінальне налаштування)
Після обертання та масштабу застосувати фінальний зсув, який компенсує обертання на основі кута:
invScale = 0.5 / scaleangle = -rotationDeg * (π / 180)extraX = invScale * cos(angle) - invScale * sin(angle)extraY = (extraX * sin(angle)) + (invScale * cos(angle))translate(extraX, extraY)Фінальна послідовність матриць
В афінних термінах це створює повну матрицю трансформації:
A = T₂ × R × S × T₁Або простою мовою:
- Центрування UV-зсуву
