Tekniske Detaljer
Uddannelsesmæssig og historisk dokumentation om, hvordan systemet, der driver dette websted, fungerer
Mønstertransformationer
Counter-Strike 2 og Counter Strike Global Offensive bruger en enkelt basetekstur (som Case Hardened) til at generere hundredvis af unikt udseende skin-varianter gennem et system af randomiserede transformationer. Dette opnås via en deterministisk, frø-baseret mekanisme — en nøgle til at forstå og reproducere Blue Gem mønstre uden for spillet.
Hvorfor kaldes det et Paint "Seed"?
For at generere teksturvarietet på en konsistent men randomiseret måde, anvender Valve en pseudo-tilfældig ensartet generator indbygget i Source Engine. Da computere er deterministiske maskiner, kræver de en startværdi — et frø — for at producere tilfældighed. I CS2 tildeles hver skin et paint seed fra 1 til 999. Dette frø initialiserer tilfældighedsgeneratoren, som derefter producerer et specifikt sæt værdier brugt til at anvende transformationer på teksturen.
Fordi denne algoritme er deterministisk og ensartet på tværs af alle platforme, vil et givet paint seed altid give den samme transformation — hvilket sikrer, at skinnet ser identisk ud på hvert system.
TL;DR: Paint seed initialiserer Valves pseudo-tilfældige generator for at definere, hvordan baseteksturen positioneres, roteres og skaleres for mønster-, slid- og snavs-lag.
Hvordan beregnes teksturtransformationer?
For at forstå hvordan CS2 randomiserer skin-udseender, hjælper det at forstå UV-mapping: hver våbenmodel har et UV-layout, der definerer, hvordan en 2D-tekstur wrapper rundt om 3D-meshen. Valve anvender teksturen på dette UV-kort og bruger derefter paint seed til at randomisere dens translation, rotation og skala.
Dette påvirker ikke kun hovedmønsteret (som Case Hardened farve-pletter), men også slid- og snavs-overlays — teksturer der tilføjer ridser, ældning og snavs.
Hvis en skins stil ikke bruger tilfældig forskydning (f.eks. muligvis ensfarvet skins som Asiimov), vil den ikke blive påvirket af dette system.
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)
Trin-for-trin: Paint Seed → Transformation
1. Bestem basis skala
Hver våben og malestil har en specifik skala, normalt defineret i Valves items_game.txt. Basis skalaen beregnes ud fra våbenlængden og UV-skalaen, afhængigt af malestilen:
if (paint_style == 3 || paint_style == 6) {
scale = weapon_length * 0.027777778;
} else {
scale = uv_scale;
}For eksempel har Karambit:
- WeaponLength = 9.813000
- UVScale = 0.438000
- → resulterer i en basis skala på 0.438
2. Generer tilfældige værdier
Når basis skalaen er kendt, bruges paint seed til at generere 11 pseudo-tilfældige float-værdier, som definerer hvordan hvert teksturlag anvendes:
| Teksturlag | Parametre |
|---|---|
| Mønster | skala, translateX, translateY, rotation |
| Slid | skala × multiplikator, translateX, translateY, rotation |
| Snavs | skala × multiplikator, translateX, translateY, rotation |
Disse floats genereres i fast rækkefølge og områder:
Mønster
- translateX → 0.0 – 1.0
- translateY → 0.0 – 1.0
- rotate → 0.0 – 360.0
Slid
- scaleMult → 1.6 – 1.8
- translateX → 0.0 – 1.0
- translateY → 0.0 – 1.0
- rotate → 0.0 – 360.0
Snavs
- 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)Eksempel: Karambit | Case Hardened — Paint Seed 633
Ved brug af ovenstående logik giver paint seed 633 på en 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
Slid- og snavs-lagene får deres egne værdier, også afledt fra frøet men med forskellige multiplikatorer og vinkler.
Remaining Mystery: Rotation Center
I lang tid forblev ét spørgsmål: hvor præcist er rotationspunktet? Mens <180° vinkler så ud til at rotere omkring UV'ets øverste venstre hjørne, opførte højere vinkler sig inkonsistent når man forsøgte at simulere resultatet uden for spillet.
From Reddit to pattern.wiki
Det tidligste forsøg på at reverse-engineere dette system kom fra det berømte Reddit-opslag af Step7750 tilbage i 2016. Det opslag fremlagde den grundlæggende idé om, hvordan frø-baserede transformationer fungerer — og i årevis fungerede det som de facto reference for fællesskabet.
Til sidst byggede sider som Broskins og csfloat.com fungerende preview-systemer — men den faktiske logik brugt af Valve forblev udokumenteret for offentligheden.
Det ændrede sig i begyndelsen af 2024, da pattern.wiki offentliggjorde en fuld nedbrydning af transformationsprocessen — inklusiv specifikke værdier, matematik og visuelle eksempler. Det var et stort spring fremad.
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. Centreret translation
Forskyd mønsteret ved hjælp af paint seedets offsets, men centrer transformationen omkring UV-origo:
translate(offsetX - 0.5, offsetY - 0.5)2. Skala (omkring origo)
Ensartet skalering af mønsteret ved hjælp af basis skalaen — omkring origo (0, 0):
scale(scaleX, scaleY)3. Rotation (omkring origo)
Roter mønsteret mod uret fra origo:
rotate(rotation)4. Ekstra offset (endelig justering)
Efter rotation og skala, anvend et endeligt offset der kompenserer for den hjørne-baserede rotation:
invScale = 0.5 / scaleangle = -rotationDeg * (π / 180)extraX = invScale * cos(angle) - invScale * sin(angle)extraY = (extraX * sin(angle)) + (invScale * cos(angle))translate(extraX, extraY)Endelig Matrix Sekvens
I affine termer skaber dette en fuld transformationsmatrix:
A = T₂ × R × S × T₁Eller på almindeligt dansk:
- Centrer UV offset
- Anvend skala
- Roter omkring origo
- Korriger med ekstra offset
De endelige transformerede UV'er wrappes derefter ved hjælp af modulo:
uv_final = (A × uv_coords) % 1.0For bedre at forstå denne tilgang, kan du lege med vores teksturtransformationsstudio, som anvender præcis disse transformationer live i din egen browser.
