What ArmorPaint’s Architecture Makes Possible—and What It Costs
ArmorPaint’s central architectural question is now clear: how can one editable PBR project remain meaningful while it becomes a live frame, a GPU operation, a reversible history state, a saved project, an exported texture set, or an input to another renderer? The answer visible in the repository is a GPU-first dataflow. This final synthesis connects the representations and boundaries into one judgment: the integration gives ArmorPaint real leverage, but it also concentrates portability, resource, build, and evidence costs in the same system.
The useful mental model is not “an editor plus a renderer.” It is a chain that preserves surface meaning while changing form:
Each arrow changes representation, but the subject remains the same: ArmorPaint is trying to preserve the meaning of a PBR surface. The project model says which objects, layers, materials, brushes, assets, channels, and relationships exist. The runtime context decides which part is active and when derived state must change. Node parsing and shader generation turn material meaning into executable behavior. Render paths turn that behavior into a visible result. History, persistence, and export preserve or translate different parts of the result.
One edit explains the whole architecture
Take the simplest useful case: a user assigns a worn material to one object and paints a local variation on top of it. The project must retain the object selection, material graph, layer relationship, channel participation, masks, and blend behavior. It must also keep the mesh’s spatial context and the asset references used by the material or brush. That is the stable meaning of the edit.
The runtime then turns the edit into ordered work. A changed material or layer invalidates some derived state; an input event changes brush values; a camera or object change affects surface tests; a viewport mode selects a different render consumer. The update loop owns the timing of those transitions rather than allowing every UI event to mutate every GPU resource immediately.
The generated shader path translates the material graph. Linked nodes become typed PBR expressions. Required textures, constants, attributes, and helper functions are registered. A shader builder assembles stage code and pipeline information. Specialized contexts adapt the shared material meaning to mesh display, painting, picking, or previews. A brush graph contributes interaction values, but it does not replace the material graph’s job of producing surface channels.
The render path then binds the active layer targets, masks, depth or G-buffer information, and material resources. A stroke can write base, normal, and packed PBR targets together. A live layer can hold temporary results without committing them. History can snapshot the layer targets and record the structural context needed for undo. The visible surface is therefore not a lucky by-product of several unrelated systems; it is the result of a controlled chain from project meaning to GPU execution.
This explains why the architecture’s most valuable property is consistency across representations. If a user changes the material graph, the affected fill layer and previews can be regenerated. If the user moves the object, the spatial result can change without rewriting the material’s meaning. If the user paints, the stroke can update the channel targets that the viewport, history, and export path all understand. The project remains the anchor while execution changes.