Technische Einblicke
Bildungs- und historische Dokumentation über die Funktionsweise des Systems, das diese Website betreibt
Counter-Strike 2 und Counter Strike Global Offensive verwenden eine einzige Basistextur (wie Case Hardened), um Hunderte von einzigartig aussehenden Skin-Varianten durch ein System randomisierter Transformationen zu erzeugen. Dies wird durch einen deterministischen, Seed-basierten Mechanismus erreicht — ein Schlüssel zum Verständnis und zur Reproduktion von Blue Gem-Mustern außerhalb des Spiels.
Warum heißt es Paint "Seed"?
Um Texturvielfalt auf konsistente und dennoch randomisierte Weise zu erzeugen, verwendet Valve einen in die Source Engine integrierten Pseudo-Zufallsgenerator. Da Computer deterministische Maschinen sind, benötigen sie einen Anfangswert — einen Seed — um Zufälligkeit zu erzeugen. In CS2 wird jedem Skin ein Paint Seed von 1 bis 999 zugewiesen. Dieser Seed initialisiert den Zufallszahlengenerator, der dann eine spezifische Menge von Werten produziert, die zur Anwendung von Transformationen auf die Textur verwendet werden.
Da dieser Algorithmus deterministisch und auf allen Plattformen einheitlich ist, liefert ein gegebener Paint Seed immer dieselbe Transformation — wodurch sichergestellt wird, dass der Skin auf jedem System identisch aussieht.
TL;DR: Der Paint Seed initialisiert Valves Pseudo-Zufallsgenerator, um zu definieren, wie die Basistextur für Muster-, Abnutzungs- und Schmutzschichten positioniert, gedreht und skaliert wird.
Wie werden Texturtransformationen berechnet?
Um zu verstehen, wie CS2 das Aussehen von Skins randomisiert, hilft es, UV-Mapping zu verstehen: Jedes Waffenmodell hat ein UV-Layout, das definiert, wie eine 2D-Textur auf das 3D-Mesh gewickelt wird. Valve wendet die Textur auf diese UV-Map an und verwendet dann den Paint Seed, um deren Translation, Rotation und Skalierung zu randomisieren.
Dies betrifft nicht nur das Hauptmuster (wie die Case Hardened-Farbflecken), sondern auch die Abnutzungs- und Schmutz-Overlays — Texturen, die Kratzer, Alterung und Schmutz hinzufügen.
Wenn der Stil eines Skins keine zufällige Verschiebung verwendet (z.B. möglicherweise einfarbige Skins wie Asiimov), wird er von diesem System nicht beeinflusst.
UV-Mapping-Konzept
Fahre über die Würfelflächen oder die UV-Karte, um zu sehen, wie 3D-Oberflächen auf 2D-Texturkoordinaten abgebildet werden
3D Model
UV Map (Unfolded)
Schritt für Schritt: Paint Seed → Transformation
1. Basisskalierung bestimmen
Jede Waffe und jeder Paint-Stil hat eine spezifische Skalierung, die normalerweise in Valves items_game.txt definiert ist. Die Basisskalierung wird aus der Waffenlänge und der UV-Skalierung berechnet, abhängig vom Paint-Stil:
if (paint_style == 3 || paint_style == 6) {
scale = weapon_length * 0.027777778;
} else {
scale = uv_scale;
}Zum Beispiel hat das Karambit:
- WeaponLength = 9.813000
- UVScale = 0.438000
- → was zu einer Basisskalierung von 0.438 führt
2. Zufallswerte generieren
Sobald die Basisskalierung bekannt ist, wird der Paint Seed verwendet, um 11 Pseudo-Zufalls-Float-Werte zu generieren, die definieren, wie jede Texturschicht angewendet wird:
| Texturschicht | Parameter |
|---|---|
| Muster | Skalierung, TranslateX, TranslateY, Rotation |
| Abnutzung | Skalierung × Multiplikator, TranslateX, TranslateY, Rotation |
| Schmutz | Skalierung × Multiplikator, TranslateX, TranslateY, Rotation |
Diese Floats werden in fester Reihenfolge und Bereichen generiert:
Muster
- translateX → 0.0 – 1.0
- translateY → 0.0 – 1.0
- rotate → 0.0 – 360.0
Abnutzung
- scaleMult → 1.6 – 1.8
- translateX → 0.0 – 1.0
- translateY → 0.0 – 1.0
- rotate → 0.0 – 360.0
Schmutz
- scaleMult → 1.6 – 1.8
- translateX → 0.0 – 1.0
- translateY → 0.0 – 1.0
- rotate → 0.0 – 360.0
Diese Werte werden unabhängig auf jede Ebene mit folgender Logik angewendet:
Transformationsreihenfolge: Skalierung → Translation → Rotation(Wiederholt für Muster, Abnutzung und Schmutz)Beispiel: Karambit | Case Hardened — Paint Seed 633
Mit der obigen Logik ergibt Paint Seed 633 auf einem 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
Die Abnutzungs- und Schmutzschichten erhalten ihre eigenen Werte, die ebenfalls vom Seed abgeleitet werden, jedoch mit anderen Multiplikatoren und Winkeln.
Verbleibendes Mysterium: Rotationszentrum
Lange Zeit blieb eine Frage offen: Wo genau ist der Rotationspunkt? Während Winkel <180° scheinbar um die obere linke Ecke der UV rotieren, verhielten sich höhere Winkel inkonsistent bei dem Versuch, das Ergebnis außerhalb des Spiels zu simulieren.
Von Reddit zu pattern.wiki
Der erste Versuch, dieses System zu reverse-engineeren, kam vom berühmten Reddit-Post von Step7750 im Jahr 2016. Dieser Post legte die Grundidee dar, wie Seed-basierte Transformationen funktionieren — und diente jahrelang als De-facto-Referenz für die Community.
Schließlich bauten Seiten wie Broskins und csfloat.com funktionierende Vorschausysteme — aber die tatsächliche von Valve verwendete Logik blieb für die Öffentlichkeit undokumentiert.
Das änderte sich Anfang 2024, als pattern.wiki eine vollständige Aufschlüsselung veröffentlichte des Transformationsprozesses — einschließlich spezifischer Werte, Mathematik und visueller Beispiele. Es war ein großer Fortschritt.
Was wir geklärt haben
Während pattern.wikis Implementierung in der Praxis eindeutig funktioniert, stimmte ihre Beschreibung der Transformationsreihenfolge und des Rotationspunkts nicht vollständig mit dem Verhalten von Source unter der Haube überein. Durch Tests und Debugging haben wir einige subtile (aber wichtige) Punkte geklärt:
- Alle Transformationen werden um den Ursprung (0, 0) angewendet — nicht nach der Translation
- Die effektive Matrixreihenfolge ist: T₂ × R × S × T₁
Template-Transformationsanwendung (Finalisiertes Modell)
Um den korrekten Bereich der Textur mit einem Paint Seed abzutasten, wenden wir eine Sequenz affiner Transformationen an — jede modifiziert die UV-Koordinaten vor dem Abtasten der Basistextur.
Schritt-für-Schritt-Transformationskette
1. Zentrierte Translation
Verschiebe das Muster mit den Paint Seed-Offsets, aber zentriere die Transformation um den UV-Ursprung:
translate(offsetX - 0.5, offsetY - 0.5)2. Skalierung (um Ursprung)
Einheitliche Skalierung des Musters mit der Basisskalierung — um den Ursprung (0, 0):
scale(scaleX, scaleY)3. Rotation (um Ursprung)
Rotiere das Muster gegen den Uhrzeigersinn vom Ursprung:
rotate(rotation)4. Extra-Offset (finale Anpassung)
Nach Rotation und Skalierung wende einen finalen Offset an, der die eckenbasierte Rotation kompensiert:
invScale = 0.5 / scaleangle = -rotationDeg * (π / 180)extraX = invScale * cos(angle) - invScale * sin(angle)extraY = (extraX * sin(angle)) + (invScale * cos(angle))translate(extraX, extraY)Finale Matrixsequenz
In affinen Begriffen erzeugt dies eine vollständige Transformationsmatrix:
A = T₂ × R × S × T₁Oder in einfachen Worten:
- UV-Offset zentrieren
- Skalierung anwenden
- Um Ursprung rotieren
- Mit Extra-Offset korrigieren
Die final transformierten UVs werden dann mit Modulo umgeschlagen:
uv_final = (A × uv_coords) % 1.0Wie die float-gesteuerte Abnutzung erzeugt wird
Höhere Float-Werte lassen einen Skin abgenutzter aussehen. Wir bilden das genauso nach wie Counter-Strike – indem wir drei Texturen in linearem Licht über das Case-Hardened-Muster legen, gesteuert vom Float-Wert des Items. Bei Float 0 (Factory New) siehst du das saubere Muster; bei Float 1 (Battle-Scarred) wirkt das Metall matt, dunkel und körnig.
Basismuster
Das farblich abgestufte Case-Hardened-Muster (Blau / Gold / Lila), platziert durch dieselbe Seed-Transformation wie oben beschrieben.
Wear-Map
Eine Graustufen-Map, die festlegt, welche Teile der Klinge zuerst abnutzen – erhöhte Kanten und freiliegende Bereiche vor geschützten.
Grunge-Map
Eine feine Schmutz- und Sprenkel-Map, die für realistischen Oberflächenverfall und Dreck sorgt, je höher der Float steigt.
Der Float-Wert steuert den gesamten Effekt über einen einzigen Parameter. Zieht man ihn von 0 auf 1, wird das Muster nach und nach entsättigt, abgedunkelt und verschmutzt, bleibt aber sichtbar – Case Hardened altert, indem es seine Farbe verschiebt und Dreck ansetzt, es kratzt nicht bis aufs blanke Metall durch.
worn = compose(base, wear, grunge, AO, float) // float 0 = Factory New … 1 = Battle-Scarred
Dieselbe float-gesteuerte Wear-Engine, live — dieses Karambit #387 von Fabrikneu bis Kampfspuren.
Die Maserung ('Maserung') kommt aus der Geometrie der Waffe
Jede Waffe hat eine vorgebackene Cavity- / Ambient-Occlusion-Map. Abnutzung und Dreck sammeln sich in den Vertiefungen und entlang der Kanten an, und genau das erzeugt die charakteristische, fleckige Maserung, die man auf einer Battle-Scarred-Klinge sieht. Jedes Messer nutzt seine eigene AO-Map, sodass das Abnutzungsmuster einzigartig für die Form dieser Waffe ist.
- Platziere das Case-Hardened-Muster, die Wear-Map und die Grunge-Map mithilfe der Seed-Transformationen pro Muster.
- Nutze den Float-Wert, um zu bestimmen, wie stark jeder Pixel abnutzt, gewichtet durch die Cavity- / AO-Map der Waffe.
- Entsättige und verdunkle die abgenutzten Bereiche in Richtung eines Schmutztons und füge feinen Dreck aus der Grunge-Map hinzu.
- Setze alles in linearem Licht zusammen und zeige es live am 3D-Modell, während du den Regler ziehst.
Das ist exakt die Mathematik aus Counter-Strikes eigenem Finish-Shader, rekonstruiert und nachgebildet – sodass der abgenutzte Look in der Vorschau genau dem entspricht, wie das Item tatsächlich im Spiel aussieht.
Um diesen Ansatz besser zu verstehen, können Sie mit unserem Textur-Transformations-Studio spielen, das genau diese Transformationen live in Ihrem Browser anwendet.