PaintForge Documentation
Paint any mesh at runtime with color, metallic and roughness, sample materials straight from the world with a 3D eyedropper, and drive it all from a ready‑made or fully customizable UMG interface — on desktop and mobile.
Overview
PaintForge turns any mesh into a paintable surface at runtime. Everything is driven by a single Actor Component plus a small family of UMG widgets.
🎨Paint anything
Drop one component on an actor and its mesh becomes paintable — characters (skeletal) and props (static) alike.
💧3D Eyedropper
Sample the exact color you see in the world, plus metallic / roughness from the hit surface.
🖌️Rich brushes
Color, metallic, roughness, opacity, hardness, size and 11 brush shapes in one tidy struct.
🧩Ready UI
A working paint panel out of the box, or compose your own from designable building blocks.
📱Mobile ready
A dedicated touch HUD with virtual joysticks, pinch‑zoom, two‑finger orbit and tap‑to‑paint.
↩️Undo & fill
Per‑surface undo history, flood‑fill and clear, all exposed to Blueprint.
Every property and function shown in this guide is exposed to Blueprint, so you can build a complete painting experience without writing a line of code.
Quick Start
Get a paintable character on screen in a few minutes.
Enable the plugin
In Edit → Plugins, make sure PaintForge is enabled (it pulls in Enhanced Input automatically). Restart the editor if prompted.
Add the Paintable component
Open your character / pawn Blueprint, click Add Component and choose PaintForge Paintable. By default it grabs the first mesh on the actor — or set Target Mesh explicitly.
Give the mesh a PaintForge material
The painted texture is fed into your material through two texture parameters. Use the included M_Paintable material (or add the parameters to your own — see Material Setup).
Press Play
With the defaults, the component auto‑initializes, spawns the paint panel, the 3D brush cursor and the eyedropper. Press Tab to open the palette and Left Mouse to paint.
Default controls
| Action | Default key |
|---|---|
| Open / close palette | Tab |
| Paint | Left Mouse (hold) |
| Orbit camera | Alt + Left Mouse |
| Resize brush (drag) | Right Mouse (drag horizontally) |
| Zoom | Mouse Wheel |
| Eyedropper (sample) | Space (hold) |
Prefer to wire your own keys? Assign your own Enhanced Input actions on the component and turn off Bind Default Keys When No Action. See Controls & Input.
Requirements
A short checklist to make sure painting, sampling and the UI all work in your project.
Support UV From Hit Results must be enabled to paint and color‑pick on static meshes / props. Without it, the log floods with “Calling FindCollisionUV but ‘Support UV From Hit Results’ is not enabled in project settings” and props won’t resolve a UV under the cursor.
| Requirement | Where | Why |
|---|---|---|
| Enhanced Input plugin | Enabled automatically with PaintForge | Drives all paint controls. No action needed. |
| Support UV From Hit Results | Project Settings → Engine → Physics | Lets line traces return a UV so the brush / eyedropper land on static meshes / props. Restart the editor after enabling. |
| Allow CPU Access on meshes | Skeletal/Static Mesh asset → Details | Required in packaged / mobile builds so PaintForge can read skinned triangles & UVs. On automatically in editor / PIE. |
| PaintForge material parameters | Your mesh material | Expose PF_BaseColor / PF_Material (or use M_Paintable). See Material Setup. |
Enable “Support UV From Hit Results”
Open Edit → Project Settings → Engine → Physics, tick Support UV From Hit Results, then restart the editor. (Equivalent config line, for reference:)
| Config file | Entry |
|---|---|
Config/DefaultEngine.ini | [/Script/Engine.PhysicsSettings]bSupportUVFromHitResults=True |
Skeletal characters are not affected by this setting — PaintForge resolves their UVs itself with a physics‑free skinned‑triangle test, so they paint and sample correctly either way.
Automatic vs Manual Setup
PaintForge can run completely hands‑off, or you can take control of every piece. Both routes use the same component.
Automatic (recommended to start)
Leave the component’s auto toggles on (they all default to ON) and everything is created for you when the game begins — no graph wiring at all:
| Toggle | Creates automatically |
|---|---|
Auto Initialize | The paint surface (render targets + material). |
Auto Setup Input | Mapping context + all paint controls. |
Auto Create Paint Widget | The paint panel for the local player. |
Auto Create Eyedropper | The 3D eyedropper, attached to the camera. |
Enable Brush Cursor | The 3D ring cursor on the surface. |
Auto Create Mobile HUD | The touch HUD (when Mobile Mode is on). |
Manual (full control)
Turn the matching toggle OFF and do that part yourself from Blueprint. You can mix and match — e.g. keep auto input but create the widget manually.
| Turn off… | …then do this in Blueprint |
|---|---|
Auto Initialize | Call Initialize Painting when you’re ready (check Is Initialized). |
Auto Setup Input | Call Bind Paint Input from your pawn’s input setup, or call the paint nodes yourself. |
Auto Create Paint Widget | Create your widget, add it to the viewport, and call Set Target Component — see Creating & Binding Widgets. |
Auto Create Eyedropper | Add a PaintForge Eyedropper component yourself and call its sample nodes. |
Recommended workflow: start fully automatic to confirm everything paints, then switch off only the pieces you want to design or control yourself.
Material Setup
PaintForge writes the paint into a texture (or vertex colors) and feeds it to your material through named parameters.
For the standard texture path, the mesh material needs two Texture Parameters. The painted base color goes into the first, and a packed metallic/roughness map (R = metallic, G = roughness) into the second:
| Parameter | Default name | Carries |
|---|---|---|
| Base color | PF_BaseColor | Painted RGB color |
| Material props | PF_Material | R = Metallic, G = Roughness |
These names are configurable in Project Settings → PaintForge. The simplest route is to start from the bundled M_Paintable material and apply it (or a child instance) to your mesh.
Overlay (keep original textures)
To paint on top of a textured mesh instead of replacing its look, enable Preserve Original Texture. Paint then accumulates in a transparent layer composited over the original through the overlay material (M_PaintableOverlay), which exposes:
| Parameter | Default name | Carries |
|---|---|---|
| Paint layer | PF_PaintLayer | RGB = paint, A = coverage |
| Original base color | PF_OriginalBaseColor | The mesh's source texture |
| Original normal (opt.) | PF_OriginalNormal | Forwarded normal map |
Vertex‑color path
For characters with mirrored or overlapping UVs, enable Use Vertex Color and assign a material that reads the Vertex Color node (RGB → base color, A → metallic), e.g. the bundled vertex material. No UV unwrap required.
In packaged / mobile builds, enable Allow CPU Access on skeletal meshes so PaintForge can resolve surface UVs and skinned triangles. This is on automatically in the editor and PIE.
Painting Modes
Pick the path that matches your asset. All three are just toggles on the component.
Texture (default)
High‑detail paint written into render textures. Needs a clean UV0 unwrap and the PF_* material parameters. Best for props and well‑unwrapped characters.
Overlay
Preserve Original Texture — paint over the existing textured look without flattening it to a solid color.
Vertex color
Use Vertex Color — UV‑independent. Detail follows mesh density; great for mirrored‑UV characters.
Plugin Classes
Everything PaintForge gives you, by its in‑editor name. Components are added via Add Component; widgets are created as Widget Blueprints or spawned for you.
Components
| Name | Add to | Role |
|---|---|---|
| PaintForge Paintable | Character / pawn | The main painter — owns the brush, input, camera, UI and eyedropper. |
| PaintForge Object Paintable | Props / static meshes | Makes a world object paintable by the player’s brush. |
| PaintForge Eyedropper | (auto, on camera) | The 3D color / material sampler. |
Widgets
| Name | Role |
|---|---|
| PaintForge Widget | Ready‑made classic paint panel. |
| PaintForge Palette | Fully designable color palette. |
| PaintForge Mobile HUD | Touch HUD with buttons and sticks. |
| PaintForge HUD Button | One‑click action button (Palette / Pick / Undo / Clear / Fill / Brush ±). |
| PaintForge Brush Slider | Single brush‑property control. |
| PaintForge Virtual Joystick | On‑screen movement stick. |
| PaintForge Camera Stick | On‑screen camera‑rotation stick. |
| Color Wheel · Value Bar · Swatch Bar · Brush Shape Selector | Designable building blocks for the palette. |
Stateless color/brush helper nodes also live in the Function Library.
Paintable Component
“PaintForge Paintable” — the heart of the plugin: drop it on an actor to make one of its meshes paintable.
Key setup properties
| Property | Default | What it does |
|---|---|---|
Target Mesh | first mesh | The mesh component to paint. Auto‑resolved if left empty. |
Material Index | 0 | Material slot the painted material is read from / written to. |
Paint All Material Slots | On | Paint every slot that shares the UV unwrap (whole character body), not just one. |
UV Channel | 0 | UV channel used to project paint. |
Paint Resolution | 0 → project default | Square render‑target resolution. 0 uses the project default (1024). |
Auto Initialize | On | Prepares the paint surface automatically when the game begins. |
Base Clear Color | White | Color the surface starts at / clears to. |
Facing Threshold | 0.1 | Rejects paint on back‑facing surfaces (stops bleed to the back of thin limbs). |
Lifecycle
With Auto Initialize on, the component prepares everything it needs when the game begins — no setup required. To control it yourself, turn the toggle off and use these Blueprint nodes on the component:
| Node | What it does |
|---|---|
| Initialize Painting | Prepares the surface for painting; returns whether it succeeded. |
| Is Initialized | True once the surface is ready to paint. |
| Rebuild Position Map | Call after a big pose change so the brush keeps landing accurately. |
Bind the component’s events — On Painted, On Toggle UI, On Eyedrop Start / Stop — in your Blueprint to react to painting (play a sound, update a counter, etc.).
Painting World Objects
“PaintForge Object Paintable” — a streamlined variant for props and level geometry.
Use the regular Paintable component on your player/character (it owns the brush, input, camera and UI), and drop the lighter Object Paintable component on static meshes and props you want the player to be able to paint. It hides the brush / input / UI / camera categories because the player’s component drives those.
To let the player’s brush reach those props, set the player component’s Target Mode to Character + World Objects or World Objects Only.
The Brush
The Paint Forge Brush is the single structure that describes what to paint. The component holds an Active Brush and exposes a setter node for every field.
| Field | Range | Meaning |
|---|---|---|
Color | Linear | Base color applied to the surface. |
Metallic | 0–1 | Metalness written to the packed map. |
Roughness | 0–1 | Roughness written to the packed map. |
Size | 0–1 | Brush diameter as a fraction of resolution. |
Opacity | 0–1 | Strength of each dab. |
Hardness | 0–1 | Edge softness (0 = feathered, 1 = crisp). |
Shape | enum | One of 11 shapes (below). |
Blend Mode | enum | Alpha Blend · Additive · Opaque. |
Brush shapes
Soft CircleHard CircleSoft SquareHard SquarePixel CirclePixel SquareDiamondCrossHorizontal LineVertical Line
Setting the brush from Blueprint
The component exposes one node per brush field, so you can drive the brush from any Blueprint event:
Set Brush ColorSet Brush MetallicSet Brush RoughnessSet Brush OpacitySet Brush HardnessSet Brush ShapeSet Brush SizeAdjust Brush Size
Brush size is clamped between Min Brush Size and Max Brush Size; Brush Size Step controls how much each up/down input changes it.
Target Modes
Target Mode decides which surfaces the brush is allowed to touch.
| Mode | Behaviour |
|---|---|
| Character Only | The brush stays locked to this actor’s own mesh. (default) |
| Character + World Objects | Paint this character and any actor carrying an Object Paintable component. |
| World Objects Only | Paint only world objects with a paintable component — never the character. |
| Specific Paintable Actors | Paint only the actors listed in Specific Paintable Actors. |
3D Eyedropper
“PaintForge Eyedropper” — the “3D Spoit”. Samples the real color you see in the world, plus metallic/roughness from the hit surface.
The component auto‑creates an eyedropper when the game begins (Auto Create Eyedropper) and attaches it to the camera. Color is read from the rendered scene pixel under the aim point — so multi‑material objects (e.g. a painting) just work, on PC and mobile. Metallic / Roughness are read from the surface material via a post‑process capture or runtime scalar parameters.
Using it
On the component, use Toggle Eyedropper to arm/disarm sampling (same as holding Space) and Is Eyedropper Active to check the state. The eyedropper itself also offers direct sampling nodes:
| Node | Samples |
|---|---|
| Sample Under Cursor | Under the current mouse cursor. |
| Sample At Crosshair | At the screen center. |
| Sample At Screen Position | At an explicit screen position. |
Each returns a Paint Forge Sample with Color, Metallic, Roughness, Has Material Props and Valid. Feed it into a paint panel with the panel’s Apply Sample node and the brush updates live.
Camera & Cursor
While the paint panel is open, PaintForge can take over the camera and show a surface‑hugging 3D brush cursor.
Camera
With Control Camera In Paint Mode on, Alt+drag orbits and the wheel zooms while painting. Tune it with Min/Max Arm Length, Zoom Step, Orbit Sensitivity, Paint Camera Orbit Speed and the pitch clamps. The spring arm is auto‑resolved from the owner, or set Camera Boom directly.
Have your pawn skip its own free‑look while IsPaintUIVisible() is true, or call HandleLookInput() from your look handler so the two don’t fight — it returns true when PaintForge consumed the input.
3D ring cursor
With Enable Brush Cursor on, two surface‑tangent rings preview the brush footprint on the mesh. Every aspect is styleable: Ring1/Ring2 Color, Thickness, Scale Mul, Ring Brightness, Surface Offset and Cursor Min Radius. You can also assign 2D cursor icons (Brush Cursor Icon, Eyedropper Cursor Icon) used as a custom mouse cursor while the panel is open.
Controls & Input
PaintForge is built on Enhanced Input, with sensible default keys so it works the moment you press Play.
When the game begins (with Auto Setup Input on) the component adds its Default Mapping Context and binds these actions. Assign your own Input Actions to remap, or leave them empty to use the built‑in fallbacks:
| Input Action | Role | Default fallback |
|---|---|---|
Paint Action | Paint while held | LMB |
Brush Size Up / Down | Resize brush in steps | Wheel |
Eyedropper Action | Sample color/material | Space |
Toggle UI Action | Open / close palette | Tab |
Orbit Action | Orbit camera | Alt+LMB |
Brush Resize Action | Drag to resize | RMB |
Zoom / Zoom In / Zoom Out | Camera zoom | Wheel |
Turn off Bind Default Keys When No Action for a pure Input‑Action setup with no built‑in key fallbacks. If you set up input on your pawn manually, the component also provides a Bind Paint Input node you can call from your pawn’s input setup.
Creating & Binding Widgets
Two ways to get a paint UI on screen: let the component build it, or design and wire your own.
Option A — Let the component do it
Keep Auto Create Paint Widget on (and assign Paint Widget Class if you made a custom design). The component spawns the widget, adds it to the viewport and binds it to itself automatically. Nothing else to do.
Option B — Create & bind it yourself
Turn Auto Create Paint Widget off and do it from your own Blueprint:
Make a Widget Blueprint
In the Content Browser: Add → User Interface → Widget Blueprint, and pick a PaintForge widget as its parent — PaintForge Widget for the classic panel, or PaintForge Palette for a designable one. Lay out your controls (for the palette, name them per the bind‑name table).
Create the widget at runtime
In your player Blueprint, use the Create Widget node (Class = your Widget Blueprint) and then Add to Viewport.
Bind it to the paintable
Call Set Target Component on the created widget and pass in your PaintForge Paintable component reference. This is the single link that connects the UI to the surface — color, brush and sample now flow both ways.
(Optional) React to edits
Bind the widget’s On Brush Changed event if you want to respond when the user changes the brush.
The self‑contained widgets — PaintForge HUD Button and the sticks — resolve the player’s paintable component on their own, so for those you usually don’t even need step 3. Use Set Target Component only to point one at a specific paintable.
Classic Paint Panel
“PaintForge Widget” — a complete, ready‑to‑use paint panel.
With Auto Create Paint Widget on, the component spawns this panel for the local player automatically (hidden until you press Tab, if Start UI Hidden is set). It shows the color picker, a brush‑shape cycler and metallic/roughness fields, and previews the brush size with a ring.
To drive a panel yourself, use its Blueprint nodes: Set Target Component to bind it to a paintable, Set Brush / Get Brush to read or write the brush, and Apply Sample to push an eyedropper result in. The On Brush Changed event fires whenever the user edits the brush.
To swap in your own design, set Paint Widget Class to a Widget Blueprint created from PaintForge Widget. Optional on‑screen movement / camera sticks can be enabled on the widget itself for touch builds.
Designable Palette
“PaintForge Palette” — a fully designable, professional color palette.
Every control is optional: design your own layout in a Widget Blueprint, include only the controls you want and name them per the table below, and the palette wires them all to the component and keeps RGB / HSV / Hex / color wheel / sliders synchronized live in both directions. Used directly with no design work, it builds a complete panel automatically.
Set the component’s Palette Paint Widget Class to use it instead of the classic panel.
Recognized element names
| Group | Bind names |
|---|---|
| Color picker | ColorWheel · ValueBar · ColorPreviewNew · ColorPreviewOld · SRGBPreviewCheck |
| RGB | RSlider/GSlider/BSlider · RText/GText/BText |
| HSV | HSlider/SSlider/VSlider · HText/SText/VText |
| Hex | HexText |
| Tools | EyedropperButton · SwatchPanel · AddSwatchButton |
| Brush | BrushShapeSelector · BrushSizeSlider · MetallicSlider · RoughnessSlider · OpacitySlider · HardnessSlider (+ matching *Text) |
| Commands | ClearButton · FillButton · UndoButton |
Style the built‑in layout with Panel Color, Accent Color and Text Color, or subclass it in UMG to restyle/relayout while keeping all the logic.
UI Building Blocks
Self‑contained, reusable widgets you can drop into any layout. The palette auto‑discovers and wires them.
Color Wheel Widget
HSV hue/saturation wheel. Pairs with the Value Bar.
Value Bar Widget
Vertical brightness (value) slider for the wheel.
Swatch Bar Widget
Row of saved color swatches; click to pick, add new ones.
Brush Shape Selector Widget
Cycles / displays the active brush shape.
Brush Slider Widget
Label + spin box bound to one brush property — see below.
Color Panel / Color Picker Widget
Internal color controls used by the classic panel.
Brush Slider
The PaintForge Brush Slider is one configurable control: a label plus a spin box (drag or type) bound to a single property you choose from a dropdown — Size · Metallic · Roughness · Opacity · Hardness. Drop several, set the Property on each, and the palette auto‑wires them — no widget naming needed. Fully styleable (label, font, accent, decimals) and Blueprint‑subclassable.
Joysticks & Camera Sticks
“PaintForge Virtual Joystick” and its camera‑tuned variant “PaintForge Camera Stick” — reusable on‑screen sticks for touch (and mouse) control.
A fixed outer ring with a draggable knob that emits a normalized 2D axis through OnAxisChanged and springs back on release. Built from standard UMG, so it runs identically in the editor, packaged desktop and on a real device — handling both touch and mouse. It knows nothing about gameplay: bind OnAxisChanged to whatever you want to drive.
| Property | Purpose |
|---|---|
Base/Knob Diameter | Sizes of the ring and knob. |
Max Travel Ratio | How far the knob can move from center. |
Dead Zone | Inner zone read as zero (kills drift). |
Dynamic Origin | Recenter the base under the finger on press. |
Hide When Idle | Show the stick only while touched. |
Base/Knob Color & Brush | Tints or custom images for a fully styled look. |
Touch & Mobile
Flip one switch and PaintForge runs a complete touch flow with its own HUD.
Turn on Mobile Mode. When the game begins the component spawns a touch HUD (the PaintForge Mobile HUD), disables the 3D ring cursor and skips the raw mouse/key bindings so nothing fights the HUD. The desktop path is completely untouched when this is off.
Gestures
| Gesture | Action |
|---|---|
| One‑finger drag | Paint |
| Two‑finger drag | Orbit camera |
| Pinch | Zoom |
| Tap a HUD button | Palette · Pick · Undo · Clear · Fill · Brush +/− |
The HUD auto‑builds its buttons and optional left/right virtual sticks, or you can inherit it as a WBP and supply your own controls by name (all BindWidgetOptional). Tunables include Mobile Paint Resolution, Mobile Orbit Sensitivity and Mobile Pinch Sensitivity.
Keep Mobile Mouse Testing on to exercise the whole mobile build right in the editor / PIE with a mouse — left = paint, right‑drag = orbit, wheel = zoom. It has no effect on a real device.
For custom flows, the mobile entry points are all available as Blueprint nodes on the component:
Mobile Begin StrokeMobile Paint AtMobile End StrokeMobile OrbitMobile Pinch ZoomMobile Sample AtSet Mobile Eyedrop ArmedMobile UndoMobile FillMobile Clear
Project Settings
Project‑wide defaults live under Project Settings → Plugins → PaintForge.
| Setting | Default | Description |
|---|---|---|
Default Paint Resolution | 1024 | Resolution for new paint render targets. |
Base Color Parameter | PF_BaseColor | Material parameter receiving the painted color. |
Material Props Parameter | PF_Material | Material parameter receiving metallic/roughness. |
Paint Layer Parameter | PF_PaintLayer | Overlay layer parameter (color + coverage). |
Original Base Color / Normal | PF_Original* | Overlay source‑texture parameters. |
Max Undo Steps | 8 | Undo snapshots retained per surface. |
Default Swatches | — | Palette swatches surfaced in the UI. |
Function Library
A set of ready‑made Blueprint helper nodes for color and brushes, available in any graph.
| Node | Does |
|---|---|
| HSV To Linear | HSV → linear color. |
| Linear To HSV | Linear color → H, S, V. |
| Hex To Linear | “RRGGBB” / “#RRGGBB(AA)” → color. |
| Linear To Hex | Color → uppercase hex string. |
| Create Brush Texture | Builds a brush mask texture. |
| Create Ring Texture | Builds a hollow ring cursor texture. |
| Read Render Target Pixel Linear | Reads one pixel from a render target. |
Online Multiplayer / Replication
PaintForge supports server-authoritative runtime painting for replicated actors. Paint, Fill and Clear actions can be synchronized across connected clients without replicating render-texture pixels every frame.
Use the network request nodes from the owning client. The server applies the authoritative change and broadcasts the same stable surface action to the other clients.
Project setup
Replicate the owning actor
The actor that owns the PaintForge Paintable component must have Replicates enabled. Player characters and pawns should also use normal network ownership.
Enable component replication
Keep Enable Network Replication enabled on the PaintForge component. It enables its replicated channel at Begin Play when the owner is replicated.
Call the network request nodes
From client input, use Request Network Paint At Local Surface, Request Network Fill and Request Network Clear. The normal mobile and ray-paint paths route through these requests when replication is enabled.
Network actions
| Action | Client call | Server result |
|---|---|---|
| Brush dab | Request Network Paint At Local Surface | Validates the brush, applies the dab, then multicasts it. |
| Flood fill | Request Network Fill | Applies the fill and multicasts the brush payload. |
| Clear | Request Network Clear | Clears the surface and multicasts the command. |
Replication synchronizes paint actions, not a continuously replicated texture. All clients need the same mesh/material setup and an initialized component. For late joiners, replay saved paint commands or apply your own saved snapshot after they join.
Blueprint API Cheat‑Sheet
The most useful component calls, grouped by what you’re doing.
Painting
Paint Under CursorPaint At RayPaint At HitPaint At UVPaint At Local SurfaceFill AllClear Paint
History
Push Undo State at stroke start
Undo to step back
Notify Stroke Start for spacing
UI
Set Paint UI VisibleToggle Paint UIIs Paint UI Visible
Brush & sample
Set Brush Color / Size / Metallic…Toggle EyedropperSet Material Scalars
Networking
Enable Network ReplicationRequest Network Paint At Local SurfaceRequest Network FillRequest Network Clear
Events you can bind
On PaintedOn Toggle UIOn Eyedrop StartOn Eyedrop Stop — on the component; On Brush Changed on the widgets.
Troubleshooting
Nothing happens when I paint
Check the mesh material exposes the PF_BaseColor / PF_Material texture parameters (or use M_Paintable), and that the component is initialized. In packaged builds enable Allow CPU Access on skeletal meshes.
Paint bleeds to the back of thin limbs
Raise Facing Threshold so only front‑facing texels accept paint.
The camera fights my own controls
Skip your pawn’s free‑look while IsPaintUIVisible() is true, or route look input through HandleLookInput().
Only part of my character paints
Keep Paint All Material Slots on, or for mirrored/overlapping UVs switch to the vertex‑color path.
Mobile HUD doesn’t paint
Make sure Mobile Mode is on; the full‑screen paint surface only activates while the palette is open.