IsItABlueGem LogoIsItABlueGem
Zaloguj

Szczegóły Techniczne

Dokumentacja edukacyjna i historyczna dotycząca działania systemu obsługującego tę stronę

Transformacje Wzorów

Counter-Strike 2 i Counter Strike Global Offensive używają pojedynczej tekstury bazowej (jak Case Hardened) do generowania setek unikalnie wyglądających wariantów skinów poprzez system losowych transformacji. Osiąga się to za pomocą deterministycznego mechanizmu opartego na ziarnie — klucz do zrozumienia i odtworzenia wzorów Blue Gem poza grą.

Dlaczego nazywa się to Paint "Seed"?

Aby generować różnorodność tekstur w spójny, ale losowy sposób, Valve wykorzystuje pseudolosowy generator równomierny wbudowany w silnik Source. Ponieważ komputery są maszynami deterministycznymi, wymagają wartości początkowej — ziarna — do produkcji losowości. W CS2 każdemu skinowi przypisywane jest paint seed od 1 do 999. To ziarno inicjalizuje generator liczb losowych, który następnie produkuje określony zestaw wartości używanych do zastosowania transformacji do tekstury.

Ponieważ ten algorytm jest deterministyczny i jednolity na wszystkich platformach, dane paint seed zawsze da tę samą transformację — zapewniając, że skin wygląda identycznie na każdym systemie.

TL;DR: Paint seed inicjalizuje pseudolosowy generator Valve, aby określić, jak tekstura bazowa jest pozycjonowana, obracana i skalowana dla warstw wzoru, zużycia i brudu.

Jak są obliczane transformacje tekstur?

Aby zrozumieć, jak CS2 losuje wygląd skinów, pomocne jest zrozumienie mapowania UV: każdy model broni ma układ UV, który definiuje, jak tekstura 2D owija się wokół siatki 3D. Valve nakłada teksturę na tę mapę UV, a następnie używa paint seed do losowania jej translacji, rotacji i skali.

Wpływa to nie tylko na główny wzór (jak kolorowe plamy Case Hardened), ale także na nakładki zużycia i brudu — tekstury dodające zarysowania, starzenie i brud.

Jeśli styl skina nie używa losowego przemieszczenia (np. prawdopodobnie jednokolorowe skiny jak Asiimov), nie będzie podlegał temu systemowi.

UV Mapping Concept

Hover over the cube faces or UV map to see how 3D surfaces map to 2D texture coordinates

3D Model

1
2
3
4
5
6

UV Map (Unfolded)

5
4
1
3
6
2

Krok po kroku: Paint Seed → Transformacja

1. Określenie skali bazowej

Każda broń i styl malowania ma określoną skalę, zwykle zdefiniowaną w pliku items_game.txt Valve. Skala bazowa jest obliczana z długości broni i skali UV, w zależności od stylu malowania:

if (paint_style == 3 || paint_style == 6) {
    scale = weapon_length * 0.027777778;
} else {
    scale = uv_scale;
}

Na przykład, Karambit ma:

  • WeaponLength = 9.813000
  • UVScale = 0.438000
  • → co daje skalę bazową 0.438

2. Generowanie wartości losowych

Po określeniu skali bazowej, paint seed jest używany do generowania 11 pseudolosowych wartości float, które definiują, jak każda warstwa tekstury jest stosowana:

Warstwa teksturyParametry
Wzórskala, translacjaX, translacjaY, rotacja
Zużycieskala × mnożnik, translacjaX, translacjaY, rotacja
Brudskala × mnożnik, translacjaX, translacjaY, rotacja

Te wartości float są generowane w stałej kolejności i zakresach:

Wzór
  • translateX → 0.0 – 1.0
  • translateY → 0.0 – 1.0
  • rotate → 0.0 – 360.0
Zużycie
  • scaleMult → 1.6 – 1.8
  • translateX → 0.0 – 1.0
  • translateY → 0.0 – 1.0
  • rotate → 0.0 – 360.0
Brud
  • 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)

Przykład: Karambit | Case Hardened — Paint Seed 633

Używając powyższej logiki, paint seed 633 na Karambit daje:

  • 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

Warstwy zużycia i brudu otrzymują własne wartości, również pochodzące z ziarna, ale z różnymi mnożnikami i kątami.

Remaining Mystery: Rotation Center

Przez długi czas pozostawało jedno pytanie: gdzie dokładnie znajduje się punkt obrotu? Podczas gdy kąty <180° wydawały się obracać wokół lewego górnego rogu UV, wyższe kąty zachowywały się niespójnie przy próbie symulacji wyniku poza grą.

From Reddit to pattern.wiki

Najwcześniejsza próba inżynierii wstecznej tego systemu pochodziła ze słynnego posta na Reddit od Step7750 w 2016 roku. Ten post przedstawił podstawową ideę działania transformacji opartych na ziarnie — i przez lata służył jako de facto odniesienie dla społeczności.

Ostatecznie strony takie jak Broskins i csfloat.com zbudowały działające systemy podglądu — ale faktyczna logika używana przez Valve pozostawała nieudokumentowana publicznie.

To zmieniło się na początku 2024 roku, kiedy pattern.wiki opublikował pełną analizę procesu transformacji — w tym konkretne wartości, matematykę i przykłady wizualne. To był znaczący krok naprzód.

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. Wyśrodkowana translacja

Przesunięcie wzoru przy użyciu przesunięć paint seed, ale wyśrodkowanie transformacji wokół początku UV:

translate(offsetX - 0.5, offsetY - 0.5)
2. Skala (wokół początku)

Jednolite skalowanie wzoru przy użyciu skali bazowej — wokół początku (0, 0):

scale(scaleX, scaleY)
3. Rotacja (wokół początku)

Obracanie wzoru przeciwnie do ruchu wskazówek zegara od początku:

rotate(rotation)
4. Dodatkowe przesunięcie (ostateczna korekta)

Po rotacji i skali, zastosuj ostateczne przesunięcie, które kompensuje rotację opartą na narożniku:

invScale = 0.5 / scale
angle = -rotationDeg * (π / 180)
extraX = invScale * cos(angle) - invScale * sin(angle)
extraY = (extraX * sin(angle)) + (invScale * cos(angle))
translate(extraX, extraY)

Ostateczna sekwencja macierzy

W kategoriach afinicznych tworzy to pełną macierz transformacji:

A = T₂ × R × S × T₁

Lub prostym językiem:

  1. Wyśrodkuj przesunięcie UV
  2. Zastosuj skalę
  3. Obróć wokół początku
  4. Skoryguj dodatkowym przesunięciem

Ostateczne przekształcone UV są następnie zawijane przy użyciu modulo:

uv_final = (A × uv_coords) % 1.0

Aby lepiej zrozumieć to podejście, możesz pobawić się naszym studiem transformacji tekstur, które stosuje dokładnie te transformacje na żywo w twojej przeglądarce.

© 2025 isitabluegem. Non-commercial CS2 pattern analysis tool.

Not affiliated with Valve Corporation. CS2 skins and related content are property of Valve Corporation.