Technische Einblicke
Bildungs- und historische Dokumentation über die Funktionsweise des Systems, das diese Website betreibt
Muster-Transformationen
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 Concept
Hover over the cube faces or UV map to see how 3D surfaces map to 2D texture coordinates
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
These values are applied independently to each layer using the following logic:
Transform Order: Scale → Translate → Rotate(Repeated for pattern, wear, and grunge)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.
Remaining Mystery: Rotation Center
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.
From Reddit to 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.
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. 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.0Um diesen Ansatz besser zu verstehen, können Sie mit unserem Textur-Transformations-Studio spielen, das genau diese Transformationen live in Ihrem Browser anwendet.
