Voltar ao portfolio

Ferramentas de produção · 3D para 2D

SpriteBaker

Um editor para transformar modelos, animações e cenas 3D em sprites direcionais prontos para um pipeline 2D.

Produzir sprites a partir de 3D exige consistência entre poses, câmera, iluminação e enquadramento. O SpriteBaker reúne essas escolhas num fluxo de composição, inspeção e bake: os PNGs carregam a aparência, e o JSON descreve precisamente como cada frame deve ser usado.

A proposta inicial era rodar o SpriteBaker no navegador, o que motivou a escolha de WebGL2 e Three.js. Depois, migrei o projeto para desktop devido às limitações do navegador. Hoje, o editor React/TypeScript e o renderizador Three.js/WebGL2 são integrados a um host Windows em C#/.NET com WebView2. Os assets são processados localmente, e as regras de captura permanecem independentes da interface e das capacidades nativas.

A renderização usa WebGL2, com Three.js para organizar a cena e shaders GLSL para os estilos e passes de imagem na GPU. Viewport, Sprite Preview e captura compartilham as estratégias de aparência, mantendo a inspeção alinhada ao resultado exportado.

  • TypeScript
  • React
  • Three.js
  • WebGL2
  • C# / .NET
  • WebView2
Personagem na viewport com moldura de captura e anel de direções, hierarquia do modelo no Outliner, propriedades da cena e Timeline com frames de bake.

Visão geral

Uma cena, um plano de captura, saídas verificáveis

O trabalho começa com um modelo GLB, glTF ou FBX, seus materiais e clips. A cena pode combinar personagem, equipamento e props, acompanhar um bone e acrescentar keys de transformação. Imagens PNG/JPEG também podem receber os estilos, outline e fundo em uma captura de frame único.

Layout, Animate, Materials e Bake & Export organizam as etapas de criação. A viewport serve para explorar; o Sprite Preview mostra a câmera e o pipeline da captura. Antes de gerar, a ferramenta calcula sprites, páginas e orçamento de memória. Seis frames em oito direções representam 48 sprites únicos, mesmo quando cada um aparece em várias saídas.

  1. Compor e preparar

    Importar assets locais, ajustar relações, materiais e transformações sem alterar os arquivos de origem.

  2. Selecionar e inspecionar

    Escolher clips, frames, direções e estilo; conferir o enquadramento e o sprite que será capturado.

  3. Capturar e entregar

    Executar o plano e exportar folhas PNG, metadata JSON, ZIP ou arquivos para uma pasta local.

01 · Fronteiras do código

Domínio puro, GPU e interface com responsabilidades próprias

O monorepo do Frontend separa três pacotes: core, renderer e web. O core calcula amostragem, direções, layout, orçamento e metadata sem React, Three.js, DOM ou rede. O renderer possui os loaders, a avaliação de poses, a câmera e os recursos WebGL2. A aplicação organiza interação, seleções e jobs.

As dependências seguem web → renderer → core, com acesso direto de web ao core. Entrypoints públicos impedem que um pacote dependa dos detalhes internos de outro. Composição e interfaces pequenas sustentam Strategy para estilos, Factory para loaders e uma fachada de captura, sem uma classe central responsável por toda a cena.

CamadaResponsabilidadeDecisão
core · TypeScriptFrames, ângulos, CapturePlan, folhas e JSONRegras de domínio independentes da GPU
renderer · Three.js / WebGL2Importação, pose, materiais e pixelsLifecycle explícito para recursos
web · ReactWorkspaces, estado e orquestraçãoCena/GPU fora do render do React
Desktop · C# / WPFWebView2, arquivos e otimizaçãoPorta DesktopHost e mensagens versionadas
API · ASP.NET CoreFundação de serviços e health checksIndependente do editor e do bake

02 · Editor DCC

Quatro workspaces para um fluxo contínuo

Cada workspace reorganiza áreas com editor e header próprios. Layout reúne viewport, Timeline, Outliner e Properties. Animate acrescenta clips, Sprite Preview e Dope Sheet. Materials aproxima biblioteca de texturas, slots e preview. Bake & Export coloca a inspeção do sprite ao lado do Sheet Viewer e das propriedades de saída.

As áreas são redimensionáveis por ponteiro e teclado. Menus, foco e campos numéricos seguem contratos acessíveis; as keys usam forma e cor para comunicar estados. Uma edição válida é aplicada imediatamente, e um gesto de arraste vira um passo de undo. Trocar workspace reaproveita renderers em vez de recriar contextos WebGL.

Clip de animação na Dope Sheet, com oito frames de bake amostrados a cada quatro frames e o resultado da pose no playhead ao lado.

03 · Composição e tempo

Assets relacionados, animações sincronizadas

Cada asset mantém seus recursos e clips, com um wrapper para transformação e anexo opcional a um nó de outro asset. Uma arma pode seguir a mão do personagem enquanto outro prop toca um clip próprio no mesmo tempo absoluto. Keys de transformação de assets e peças são distintas dos frames escolhidos para exportar.

A amostragem usa FPS global e tempos absolutos: um clip de um segundo a 30 FPS tem amostras de 0 a 29, sem repetir o endpoint do loop. A velocidade de playback muda somente a inspeção. Clips externos exigem tracks resolvíveis e compatibilidade do skeleton; retargeting permanece uma evolução planejada.

04 · Contrato de saída

Planejar antes de renderizar

O CapturePlan é imutável: congela settings normalizados, amostras, direções, enquadramento, células e estimativas durante o job. A ordem lógica é animação, frame e ângulo; nas folhas, cada direção inicia uma linha e seus frames avançam da esquerda para a direita. Combined e Separate compartilham capturas quando possível.

As saídas podem incluir composição e folhas por asset. Whole mostra o asset inteiro; Cut out mantém a oclusão dos outros objetos. Todas usam rects e câmera compatíveis. O JSON versionado registra tempo, duração, direção, pivot e placements; arquivos, dimensões reais dos PNGs, referências e sobreposições são conferidos antes dos downloads.

Resultado do bake no Sheet Viewer: oito frames em oito direções, totalizando 64 sprites, com grade e controles de exportação PNG e JSON.
PNG exportado em Brushstroke: oito frames × oito direções = 64 sprites de 128 × 128 px, com padding de 2 px, em uma folha de 1056 × 1056 px. Cada linha corresponde a uma direção de 0° a 315°; as colunas mostram os frames 0, 4, 8, 12, 16, 20, 24 e 28.
Crouch_Move_Loop · primeiro sprite no JSON exportado
{
    "id": "clip-0_f0_a0",
    "animationId": "clip-0",
    "frameIndex": 0,
    "timeSeconds": 0,
    "durationSeconds": 0.13333333333333333,
    "angleDegrees": 0,
    "pivot": {
        "x": 0.5,
        "y": 0.7324728096403346
    },
    "placements": [
        {
            "sheetId": "combined-001",
            "x": 2,
            "y": 2,
            "width": 128,
            "height": 128
        }
    ]
}

Entrada real do primeiro sprite da folha acima: frame 0, direção 0°, tempo, duração, pivot e posição na folha. As coordenadas são em pixels, a partir do canto superior esquerdo. O JSON completo também registra os 64 sprites, a câmera, o estilo Brushstroke, a iluminação e as configurações do bake.

05 · Estabilidade visual

Um enquadramento para todas as poses e direções

O auto-fit mede vértices deformados por skinning e morphs nas poses e direções selecionadas, incluindo root motion. Um pivot de referência fixo e uma câmera resolvida para o plano inteiro evitam que o personagem pulse de tamanho ou mude de apoio entre frames. Ortográfica e perspectiva compartilham essa regra.

Frente, elevação, zoom e offsets pertencem à captura; orbit, pan e zoom da viewport pertencem à exploração. Moldura, anel de direções e grid ajudam a conferir a cena, sem entrar no PNG. Ângulos são explícitos, sem impor nomes de bússola à orientação importada, e cortes intencionais aparecem no preview.

Personagem Crouch_Move_Loop na câmera de captura, com oito direções em passos de 45°, Outliner, propriedades e Timeline visíveis.

06 · Estratégias de aparência

Estilos com contratos de cor e alpha

Cada estilo declara seu render e pós-processamento. Materiais derivados são aplicados temporariamente e restaurados ao terminar, inclusive em falha. Pixelated usa resolução interna e ampliação inteira por nearest-neighbor; paleta e Bayer estáveis evitam uma quantização diferente a cada frame. Hand Painted combina material, luz e gradação.

Normal Map captura dados lineares em espaço de câmera, com inversão opcional dos canais vermelho e verde. Emissive isola a emissão e trata áreas não emissivas. O pipeline distingue dados de cor sRGB, mantém alpha reto e zera RGB sob alpha zero; o fundo sólido é composto depois dos efeitos.

EstiloEstratégia
OriginalMateriais suportados pelo loader sob iluminação de captura
PixelatedBaixa resolução, gradação, Bayer opcional e paleta fixa
Hand PaintedLuz em bandas, textura suavizada e controle de realces
Normal MapNormais codificadas como dados para iluminação 2D
EmissiveEmissão do material com máscara por threshold
BrushstrokePinceladas procedurais com cor e fluxo da forma

Estilos · a mesma pose em diferentes renderizações

Selecione um estilo para ver seu resultado. Cada opção apresenta uma imagem própria do mesmo modelo e pose.

Sprite renderizado no estilo Original
Sprite renderizado no estilo Pixelated
Sprite renderizado no estilo Hand Painted
Sprite renderizado no estilo Normal Map
Sprite renderizado no estilo Emissive
Sprite renderizado no estilo Brushstroke

07 · Coerência temporal

Pinceladas que acompanham a superfície

Brushstroke repinta a captura com pincéis procedurais, uma base suavizada e sementes determinísticas. Nos modelos, as sementes são distribuídas na superfície de repouso e acompanham skinning e morphs. O fluxo segue a tangente UV ou a orientação da superfície, mantendo a relação entre tinta e forma ao animar ou mudar de direção.

Dry, Fat, Feathery, Streaky e Grunge ampliam a biblioteca, com camadas, impasto, alinhamento à luz e pickup de cor em RYB. Imagens, outline e sombra usam sementes em espaço de imagem. O planejamento e a composição da viewport ficam na GPU; a captura exportada aplica o estilo nas dimensões escolhidas para o sprite.

Brushstroke · superfície e pincéis

Selecione um pincel para comparar seu resultado em Brushstroke.

Preview de Brushstroke com o pincel Default
Preview de Brushstroke com o pincel Dry
Preview de Brushstroke com o pincel Fat
Preview de Brushstroke com o pincel Feathery
Preview de Brushstroke com o pincel Streaky
Preview de Brushstroke com o pincel Grunge

08 · Edição reversível

Materiais editáveis sem perder a origem

O workspace Materials permite atribuir texturas por slot, selecionar canais de mapas empacotados e ajustar a convenção de normal. Metallic e Roughness também aceitam valores numéricos sem textura. O preview pode mostrar esfera ou modelo, sob luz Studio ou Capture, junto de uma miniatura do resultado no sprite.

As edições entram no histórico da cena, invalidam o resultado anterior e podem voltar ao material original. Texturas comprimidas KTX2 ganham miniaturas pintadas pela GPU no renderer do preview de material, com cache por textura. Esse caminho preserva orientação e encoding dos dados sem abrir um contexto WebGL adicional.

Material da personagem na esfera de preview com iluminação Studio, biblioteca de texturas e slots de cor, roughness e normal visíveis.
O mesmo material com Capture light selecionado: o preview usa a iluminação da captura, enquanto o resultado do sprite aparece ao lado.

09 · Direção de arte

Luz de cena com controle sobre a estilização

Até oito luzes point ou spot complementam a iluminação de captura. Cor, intensidade, raio, suavidade e cone são ajustáveis, com gizmos e volumes de debug na viewport. A opção Affected by render style decide se a contribuição é quantizada ou repintada junto do sujeito, ou somada depois do estilo.

God rays usam cobertura da silhueta para criar feixes em espaço de tela; precisam de espaço livre no enquadramento e não equivalem a volumetria com profundidade. A sombra de chão é uma camada independente, junto do sprite ou em folhas separadas. Marcadores e volumes de debug ficam restritos à viewport.

Luzes · gizmo, alcance e resultado

Selecione um tipo de luz para ver seu gizmo e alcance.

Gizmo e alcance da luz Spotlight
Gizmo e alcance da luz Point light

10 · Interação e custo

Evitar trabalho e sincronização desnecessários

Os passes de estilo da viewport ficam na GPU, incluindo Brushstroke, evitando transferências de pixels para a CPU a cada quadro. Targets são reutilizados, e o custo de aquecimento de shaders é tratado separadamente. Materiais derivados comparam seu estado efetivo para evitar reconstruções provocadas apenas pela versão interna de um material compartilhado.

O Sprite Preview usa o caminho de captura, mas agrupa rajadas de edição: uma captura em andamento e um pedido final com os settings mais recentes. O scheduler do bake cede controle entre lotes de preparação, sprites e páginas. Essas estratégias reduzem bloqueios sem confundir preview interativo com a entrega final.

11 · Memória e I/O

Ler o que o asset precisa, por intervalos

O host Windows oferece I/O nativo pela porta DesktopHost; renderer e core continuam trabalhando com contratos de arquivo. No GLB, cabeçalho e JSON são lidos primeiro, e cada bufferView chega por intervalo. glTF aplica o mesmo caminho aos buffers locais. No desktop, MemoryMappedFile entrega esses intervalos em SharedBuffers somente leitura.

A concorrência limita leituras e bytes em voo. A ponte valida versão, origem, pedido e tamanho, entrega IDs opacos e libera buffers em todos os caminhos. Os arrays de geometria e as texturas necessários a bounds, captura e recuperação de contexto permanecem na CPU. Leitura por intervalos reduz intermediários; não elimina o custo de GPU de uma cena grande.

12 · Cópias locais

Otimização para GPU com integridade e cache controlado

Optimize for GPU gera uma cópia de GLB/glTF com gltfpack fixado por versão e hash: geometria meshopt e texturas KTX2, com UASTC ou ETC1S para base color. O original é preservado. A chave do cache inclui conteúdo, ferramenta, receita e parâmetros, e o sidecar verifica tamanho e SHA-256 da cópia antes de reutilizá-la.

O cache tem limite configurável, padrão de 10 GiB, remoção por uso mais antigo e arrendamentos que protegem cópias em uso. Decoders vêm no bundle. O instalador por usuário preserva preferências e cache nas atualizações; ao desinstalar, pergunta se os dados também devem ser removidos. A otimização consome memória própria e não garante reduzir o pico do renderer.

13 · Continuidade do trabalho

Gerar sem perder o trabalho anterior

Importação e geração têm estados separados. Ao substituir um asset, uma falha mantém o anterior disponível; quando várias importações são solicitadas, apenas a mais recente pode ocupar a cena. Durante o bake, o plano fica congelado e as edições da cena aguardam o término, com cancelamento disponível.

Cancelar ou interromper uma geração descarta as saídas parciais e preserva o último resultado completo. Mudanças de câmera, materiais ou settings sinalizam que a folha precisa de um novo bake. Problemas de contexto WebGL permitem reiniciar o renderer e retomar o trabalho, com mensagens que identificam o que precisa ser corrigido.

14 · Extensão do produto

Serviços preparados sem acoplar o bake

A API em ASP.NET Core e PostgreSQL estabelece uma fundação para serviços futuros. Ela expõe informação do aplicativo e health checks, distingue processo ativo de banco acessível e responde falhas com Problem Details.

O editor e a aplicação desktop não dependem dessa API para importar, renderizar ou exportar. Assets continuam locais, e preferências pequenas e presets próprios são versionados separadamente. Persistência de cena, biblioteca de assets, contas e cloud storage precisam de contratos e entregas específicos antes de fazerem parte do produto.

Próximos passos

O que está consolidado e o que queremos melhorar

A base consolidada reúne os quatro workspaces, composição de modelos, keys por peça, materiais editáveis, seis estilos, luzes, folhas por asset, exportação PNG/JSON/ZIP e presets Unity RTS. No Windows, soma diálogos nativos, leitura por intervalos, cópias otimizadas e cache gerenciado. Cada capacidade mantém contratos de captura e arquivos de origem preservados.

As melhorias planejadas incluem projetos e recipes persistidos, biblioteca de assets, retargeting, OBJ, packing mais avançado e exportadores específicos de engines. O objetivo é recuperar configurações de produção, reutilizar assets e ampliar integrações mantendo a previsibilidade de tempo, câmera e metadata.

Outras melhorias incluem reduzir o trabalho síncrono da captura, melhorar o uso de memória em cenas grandes e ampliar a compatibilidade. WebGPU é uma possibilidade para necessidades concretas de compute. Essas frentes são planejadas; o backend de storage e a restauração completa de projetos ainda exigem implementação própria.

Contato

Cidade de Québec, QC, Canadá / Disponível para oportunidades

Estou aberto a oportunidades em desenvolvimento de software, programação de ferramentas e gameplay, além de vagas de artista 3D júnior. Se minha experiência fizer sentido para sua equipe, será um prazer conversar pelos meus perfis nas redes sociais.