When a Node Graph Becomes a Shader

ArmorPaint’s material graph is the point where editable project meaning crosses into executable GPU behavior. This chapter follows that crossing: how linked nodes and groups become typed PBR expressions, how the shader builder turns those expressions into a complete program description, and why ArmorPaint creates different shader contexts for different jobs. The practical result is a way to understand what a material edit changes—and what remains the responsibility of the renderer or target backend.

A node graph is easy to mistake for a visual diagram that the renderer reads later. In ArmorPaint, it is closer to a small program. Nodes have inputs and outputs with types, links define dependencies, groups provide reusable subgraphs, and the output node determines which values matter to the surface. The graph is still an editing experience, but it becomes useful to the GPU only after the application has resolved its dependencies and generated executable source.

The parser follows meaning, not the canvas outline

The first step is not to visit every node in the order a person sees it. ArmorPaint follows links from the material’s PBR output and asks which upstream values are needed. If the output needs base color, the parser follows the connected vector expression. If roughness or metallic is connected, it follows those value expressions. The same process handles normal input and optional height, emission, or subsurface outputs when the material configuration uses them.

This dependency-directed behavior matters because a graph can contain more than the current output needs. A disconnected node may be useful while someone is editing, but it should not automatically become a texture binding or a line of shader code. By following links, the parser keeps generated work related to the material’s actual output. The graph remains open-ended for the user while the generated program is specific to the current connections.

The parser also distinguishes value-like and vector-like data. A color, vector, and scalar cannot be substituted without a conversion rule. When a connected node supplies a vector to a value input, the parser can select an appropriate component or grayscale interpretation; when a value feeds a vector input, it can construct a vector expression. These decisions let one node family participate in different material roles without erasing type information.

Groups add another boundary. A group has its own canvas and inputs/outputs, but its result must still connect to the parent graph. The parser enters the group, resolves the group output corresponding to the linked socket, then returns to the parent context. This preserves reuse without turning the group into an opaque texture. A group is reusable graph meaning, not a pre-rendered image.

The parser’s output is therefore a set of expressions tied to the project’s PBR vocabulary. It can produce expressions for base color, roughness, metallic, occlusion, opacity, height, emission, subsurface, and tangent-space normal.