Tekniske Detaljer
Uddannelsesmæssig og historisk dokumentation om, hvordan systemet, der driver dette websted, fungerer
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-koncept
Hold musen over terningens flader eller UV-kortet for at se, hvordan 3D-overflader mappes til 2D-teksturkoordinater
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
Disse værdier anvendes uafhængigt på hvert lag med følgende logik:
Transformationsrækkefølge: Skala → Translate → Rotation(Gentaget for mønster, slid og snavs)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.
Resterende mysterium: Rotationscenter
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.
Fra Reddit til 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.
Hvad vi afklarede
Mens pattern.wikis implementering tydeligt fungerer i praksis, stemte deres beskrivelse af transformationsrækkefølgen og rotationspunktet ikke helt overens med hvordan Source opfører sig under motorhjelmen. Gennem test og debugging afklarede vi nogle subtile (men vigtige) punkter:
- Alle transformationer anvendes omkring origo (0, 0) — ikke efter translation
- Den effektive matrix-rækkefølge er: T₂ × R × S × T₁
Skabelon Transform Anvendelse (Finaliseret Model)
For at sample det korrekte område af teksturen ved hjælp af et paint seed, anvender vi en sekvens af affine transformationer — hver modificerer UV-koordinaterne før sampling af baseteksturen.
Trin-for-trin transformationskæde
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.0Sådan genereres float-baseret slitage
Højere float-værdier får en skin til at se mere slidt ud. Vi genskaber dette på samme måde som Counter-Strike gør — ved at sammensætte tre teksturer oven på Case Hardened-mønsteret i lineært lys, styret af genstandens float-værdi. Ved float 0 (Factory New) ser du det rene mønster; ved float 1 (Battle-Scarred) er metallet dæmpet, mørklagt og kornet.
Basismønster
Det farveindfarvede Case Hardened-mønster (blåt / guld / lilla), placeret af den samme seed-transformation, der er beskrevet ovenfor.
Slitagekort
Et gråtonekort, der afgør, hvilke dele af bladet der slides først — høje kanter og udsatte områder før de beskyttede.
Snavskort
Et fint snavs- og prikkekort, der tilføjer realistisk overfladenedbrydning og skidt, efterhånden som floaten stiger.
Float-værdien styrer hele effekten gennem en enkelt parameter. Når du trækker den fra 0 til 1, afmættes, mørklægges og tilsmudses mønsteret gradvist, mens det forbliver synligt — Case Hardened ældes ved at skifte farve og samle skidt, det slides ikke ned til bart metal.
worn = compose(base, wear, grunge, AO, float) // float 0 = Factory New … 1 = Battle-Scarred
Den samme float-styrede slid-engine, live — denne Karambit #387 fra Fabriksny til Kamparret.
Maserungen ('Maserung') kommer fra våbnets geometri
Hvert våben har et bagt cavity- / ambient-occlusion-kort. Slitage og skidt koncentreres i sprækkerne og langs kanterne, hvilket er det, der frembringer den karakteristiske spættede maserung, du ser på et battle-scarred blad. Hver kniv bruger sit eget AO-kort, så slitagemønsteret er unikt for det pågældende våbens form.
- Placér Case Hardened-mønsteret, slitagekortet og snavskortet ved hjælp af seed-transformationerne for hvert mønster.
- Brug float-værdien til at afgøre, hvor kraftigt hver pixel slides, vægtet af våbnets cavity- / AO-kort.
- Afmæt og mørklæg de slidte områder mod en skidttone, og tilføj fint snavs fra snavskortet.
- Sammensæt alt i lineært lys og vis det live på 3D-modellen, mens du trækker i skyderen.
Dette er den nøjagtige matematik fra Counter-Strikes egen finish-shader, gendannet og reproduceret — så det slidte udseende, du forhåndsviser, matcher, hvordan genstanden faktisk ser ud i spillet.
For bedre at forstå denne tilgang, kan du lege med vores teksturtransformationsstudio, som anvender præcis disse transformationer live i din egen browser.