IsItABlueGem LogoIsItABlueGem
Entrar

Insights Técnicos

Documentação educacional e histórica sobre como funciona o sistema que alimenta este site

Counter-Strike 2 e Counter Strike Global Offensive usam uma única textura base (como Case Hardened) para gerar centenas de variantes de skins com aparência única através de um sistema de transformações aleatórias. Isso é alcançado através de um mecanismo determinístico baseado em seed — uma chave para entender e reproduzir padrões Blue Gem fora do jogo.

Por que é chamado de "Seed" de Pintura?

Para gerar variedade de textura de forma consistente mas aleatória, a Valve emprega um gerador uniforme pseudo-aleatório incorporado ao Source Engine. Como os computadores são máquinas determinísticas, eles precisam de um valor inicial — uma seed — para produzir aleatoriedade. No CS2, cada skin recebe uma paint seed variando de 1 a 999. Esta seed inicializa o gerador de números aleatórios, que então produz um conjunto específico de valores usados para aplicar transformações à textura.

Como este algoritmo é determinístico e uniforme em todas as plataformas, uma determinada paint seed sempre produzirá a mesma transformação — garantindo que a skin pareça idêntica em todos os sistemas.

Resumo: A paint seed inicializa o gerador pseudo-aleatório da Valve para definir como a textura base é posicionada, rotacionada e escalada para as camadas de padrão, desgaste e sujeira.

Como as Transformações de Textura são Calculadas?

Para entender como o CS2 randomiza as aparências das skins, ajuda entender o mapeamento UV: cada modelo de arma tem um layout UV que define como uma textura 2D envolve a malha 3D. A Valve aplica a textura a este mapa UV e então usa a paint seed para randomizar sua translação, rotação e escala.

Isso afeta não apenas o padrão principal (como as manchas de cor do Case Hardened), mas também as sobreposições de desgaste e sujeira — texturas que adicionam arranhões, envelhecimento e sujeira.

Se o estilo de uma skin não usa deslocamento aleatório (por exemplo, possivelmente skins de cor sólida como Asiimov), ela não será afetada por este sistema.

Conceito de Mapeamento UV

Passe o mouse sobre as faces do cubo ou o mapa UV para ver como superfícies 3D mapeiam para coordenadas de textura 2D

3D Model

1
2
3
4
5
6

UV Map (Unfolded)

5
4
1
3
6
2

Passo a Passo: Paint Seed → Transformação

1. Determinar Escala Base

Cada arma e estilo de pintura tem uma escala específica, geralmente definida no items_game.txt da Valve. A escala base é calculada a partir do comprimento da arma e da escala UV, dependendo do estilo de pintura:

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

Por exemplo, o Karambit tem:

  • WeaponLength = 9.813000
  • UVScale = 0.438000
  • → resultando em uma escala base de 0.438

2. Gerar Valores Aleatórios

Uma vez que a escala base é conhecida, a paint seed é usada para gerar 11 valores float pseudo-aleatórios, que definem como cada camada de textura é aplicada:

Camada de TexturaParâmetros
Padrãoescala, translaçãoX, translaçãoY, rotação
Desgasteescala × multiplicador, translaçãoX, translaçãoY, rotação
Sujeiraescala × multiplicador, translaçãoX, translaçãoY, rotação

Esses floats são gerados em ordem e intervalos fixos:

Padrão
  • translateX → 0.0 – 1.0
  • translateY → 0.0 – 1.0
  • rotate → 0.0 – 360.0
Desgaste
  • scaleMult → 1.6 – 1.8
  • translateX → 0.0 – 1.0
  • translateY → 0.0 – 1.0
  • rotate → 0.0 – 360.0
Sujeira
  • scaleMult → 1.6 – 1.8
  • translateX → 0.0 – 1.0
  • translateY → 0.0 – 1.0
  • rotate → 0.0 – 360.0

Esses valores são aplicados independentemente a cada camada usando a seguinte lógica:

Ordem de Transformação: Escala → Translação → Rotação
(Repetido para padrão, desgaste e sujeira)

Exemplo: Karambit | Case Hardened — Paint Seed 633

Usando a lógica acima, paint seed 633 em um Karambit produz:

  • 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

As camadas de desgaste e sujeira obtêm seus próprios valores, também derivados da seed mas com diferentes multiplicadores e ângulos.

Mistério Restante: Centro de Rotação

Por muito tempo, uma questão permaneceu: onde exatamente está o pivô de rotação? Enquanto ângulos <180° pareciam girar em torno do canto superior esquerdo do UV, ângulos maiores se comportavam inconsistentemente ao tentar simular o resultado fora do jogo.

Do Reddit ao pattern.wiki

A primeira tentativa de engenharia reversa deste sistema veio do famoso post no Reddit de Step7750 em 2016. Esse post estabeleceu a ideia básica de como as transformações baseadas em seed funcionam — e por anos, serviu como a referência de facto para a comunidade.

Eventualmente, sites como Broskins e csfloat.com construíram sistemas de visualização funcionais — mas a lógica real usada pela Valve permaneceu não documentada para o público.

Isso mudou no início de 2024, quando pattern.wiki publicou uma análise completa do processo de transformação — incluindo valores específicos, matemática e exemplos visuais. Foi um grande avanço.

O Que Esclarecemos

Embora a implementação do pattern.wiki claramente funcione na prática, sua descrição da ordem de transformação e pivô de rotação não estava totalmente alinhada com o comportamento do Source por baixo dos panos. Através de testes e depuração, esclarecemos alguns pontos sutis (mas importantes):

  • Todas as transformações são aplicadas em torno da origem (0, 0) — não após a translação
  • A ordem efetiva da matriz é: T₂ × R × S × T₁

Aplicação de Transformação de Template (Modelo Finalizado)

Para amostrar a área correta da textura usando uma paint seed, aplicamos uma sequência de transformações afins — cada uma modificando as coordenadas UV antes de amostrar a textura base.

Cadeia de Transformação Passo a Passo

1. Translação Centralizada

Deslocar o padrão usando os deslocamentos da paint seed, mas centralizar a transformação em torno da origem UV:

translate(offsetX - 0.5, offsetY - 0.5)
2. Escala (em torno da origem)

Escalar uniformemente o padrão usando a escala base — em torno da origem (0, 0):

scale(scaleX, scaleY)
3. Rotação (em torno da origem)

Girar o padrão no sentido anti-horário a partir da origem:

rotate(rotation)
4. Deslocamento Extra (ajuste final)

Após rotação e escala, aplicar um deslocamento final que compensa a rotação baseada em canto:

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

Sequência Final de Matriz

Em termos afins, isso cria uma matriz de transformação completa:

A = T₂ × R × S × T₁

Ou em português simples:

  1. Centralizar deslocamento UV
  2. Aplicar escala
  3. Girar em torno da origem
  4. Corrigir com deslocamento extra

Os UVs transformados finais são então envolvidos usando módulo:

uv_final = (A × uv_coords) % 1.0

Como o desgaste baseado no float é gerado

Valores de float mais altos fazem a skin parecer mais desgastada. Recriamos isso do mesmo jeito que o Counter-Strike faz — compondo três texturas sobre o padrão Case Hardened em luz linear, conforme o valor de float do item. Com float 0 (Nova de Fábrica) você vê o padrão limpo; com float 1 (Veterana de Guerra) o metal fica apagado, escurecido e granulado.

Padrão base

O padrão Case Hardened com gradiente de cores (azul / dourado / roxo), posicionado pela mesma transformação de seed descrita acima.

Mapa de desgaste

Um mapa em tons de cinza que decide quais partes da lâmina se desgastam primeiro — bordas salientes e áreas expostas antes das protegidas.

Mapa de sujeira (grunge)

Um mapa fino de sujeira e respingos que adiciona quebras realistas na superfície e imundície conforme o float aumenta.

O valor de float controla todo o efeito através de um único parâmetro. Arrastá-lo de 0 a 1 dessatura, escurece e suja progressivamente o padrão mantendo-o visível — a Case Hardened envelhece mudando de cor e acumulando sujeira, ela não se desgasta até o metal nu.

worn = compose(base, wear, grunge, AO, float) // float 0 = Factory New … 1 = Battle-Scarred
hero.knife.alt
hero.sweep.conditions.fn · hero.sweep.floatLabel 0.000

O mesmo motor de desgaste baseado em float, ao vivo — varrendo esta Karambit #387 de Nova de Fábrica a Veterana de Guerra.

O granulado ('Maserung') vem da geometria da arma

Toda arma tem um mapa de cavidade / oclusão de ambiente (AO) pré-renderizado. O desgaste e a sujeira se concentram nas fendas e ao longo das bordas, o que produz aquele granulado mosqueado característico que você vê numa lâmina veterana de guerra. Cada faca usa seu próprio mapa de AO, então o padrão de desgaste é único para o formato daquela arma.

  1. Posicione o padrão Case Hardened, o mapa de desgaste e o mapa de grunge usando as transformações de seed de cada padrão.
  2. Use o valor de float para decidir o quão intensamente cada pixel se desgasta, ponderado pelo mapa de cavidade / AO da arma.
  3. Dessature e escureça as áreas desgastadas em direção a um tom de sujeira, e adicione sujeira fina a partir do mapa de grunge.
  4. Componha tudo em luz linear e exiba ao vivo no modelo 3D enquanto você arrasta o controle deslizante.

Esta é a matemática exata do próprio shader de acabamento do Counter-Strike, recuperada e reproduzida — então o visual desgastado que você visualiza corresponde a como o item realmente aparece no jogo.

Para entender melhor esta abordagem, você pode experimentar nosso estúdio de transformação de textura que aplica exatamente essas transformações ao vivo em seu próprio navegador.