Runtime Mesh Painting Toolkit

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.

Category · Rendering Modules · PaintForge + Demo Depends · Enhanced Input Blueprint · Fully exposed Platforms · PC · 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.

1

Enable the plugin

In Edit → Plugins, make sure PaintForge is enabled (it pulls in Enhanced Input automatically). Restart the editor if prompted.

2

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.

3

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).

4

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

ActionDefault key
Open / close paletteTab
PaintLeft Mouse (hold)
Orbit cameraAlt + Left Mouse
Resize brush (drag)Right Mouse (drag horizontally)
ZoomMouse 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.

RequirementWhereWhy
Enhanced Input pluginEnabled automatically with PaintForgeDrives all paint controls. No action needed.
Support UV From Hit ResultsProject Settings → Engine → PhysicsLets line traces return a UV so the brush / eyedropper land on static meshes / props. Restart the editor after enabling.
Allow CPU Access on meshesSkeletal/Static Mesh asset → DetailsRequired in packaged / mobile builds so PaintForge can read skinned triangles & UVs. On automatically in editor / PIE.
PaintForge material parametersYour mesh materialExpose 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 fileEntry
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:

ToggleCreates automatically
Auto InitializeThe paint surface (render targets + material).
Auto Setup InputMapping context + all paint controls.
Auto Create Paint WidgetThe paint panel for the local player.
Auto Create EyedropperThe 3D eyedropper, attached to the camera.
Enable Brush CursorThe 3D ring cursor on the surface.
Auto Create Mobile HUDThe 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 InitializeCall Initialize Painting when you’re ready (check Is Initialized).
Auto Setup InputCall Bind Paint Input from your pawn’s input setup, or call the paint nodes yourself.
Auto Create Paint WidgetCreate your widget, add it to the viewport, and call Set Target Component — see Creating & Binding Widgets.
Auto Create EyedropperAdd 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:

ParameterDefault nameCarries
Base colorPF_BaseColorPainted RGB color
Material propsPF_MaterialR = 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:

ParameterDefault nameCarries
Paint layerPF_PaintLayerRGB = paint, A = coverage
Original base colorPF_OriginalBaseColorThe mesh's source texture
Original normal (opt.)PF_OriginalNormalForwarded 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

NameAdd toRole
PaintForge PaintableCharacter / pawnThe main painter — owns the brush, input, camera, UI and eyedropper.
PaintForge Object PaintableProps / static meshesMakes a world object paintable by the player’s brush.
PaintForge Eyedropper(auto, on camera)The 3D color / material sampler.

Widgets

NameRole
PaintForge WidgetReady‑made classic paint panel.
PaintForge PaletteFully designable color palette.
PaintForge Mobile HUDTouch HUD with buttons and sticks.
PaintForge HUD ButtonOne‑click action button (Palette / Pick / Undo / Clear / Fill / Brush ±).
PaintForge Brush SliderSingle brush‑property control.
PaintForge Virtual JoystickOn‑screen movement stick.
PaintForge Camera StickOn‑screen camera‑rotation stick.
Color Wheel · Value Bar · Swatch Bar · Brush Shape SelectorDesignable 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

PropertyDefaultWhat it does
Target Meshfirst meshThe mesh component to paint. Auto‑resolved if left empty.
Material Index0Material slot the painted material is read from / written to.
Paint All Material SlotsOnPaint every slot that shares the UV unwrap (whole character body), not just one.
UV Channel0UV channel used to project paint.
Paint Resolution0 → project defaultSquare render‑target resolution. 0 uses the project default (1024).
Auto InitializeOnPrepares the paint surface automatically when the game begins.
Base Clear ColorWhiteColor the surface starts at / clears to.
Facing Threshold0.1Rejects 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:

NodeWhat it does
Initialize PaintingPrepares the surface for painting; returns whether it succeeded.
Is InitializedTrue once the surface is ready to paint.
Rebuild Position MapCall 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.

FieldRangeMeaning
ColorLinearBase color applied to the surface.
Metallic0–1Metalness written to the packed map.
Roughness0–1Roughness written to the packed map.
Size0–1Brush diameter as a fraction of resolution.
Opacity0–1Strength of each dab.
Hardness0–1Edge softness (0 = feathered, 1 = crisp).
ShapeenumOne of 11 shapes (below).
Blend ModeenumAlpha 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.

ModeBehaviour
Character OnlyThe brush stays locked to this actor’s own mesh. (default)
Character + World ObjectsPaint this character and any actor carrying an Object Paintable component.
World Objects OnlyPaint only world objects with a paintable component — never the character.
Specific Paintable ActorsPaint 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:

NodeSamples
Sample Under CursorUnder the current mouse cursor.
Sample At CrosshairAt the screen center.
Sample At Screen PositionAt 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 ActionRoleDefault fallback
Paint ActionPaint while heldLMB
Brush Size Up / DownResize brush in stepsWheel
Eyedropper ActionSample color/materialSpace
Toggle UI ActionOpen / close paletteTab
Orbit ActionOrbit cameraAlt+LMB
Brush Resize ActionDrag to resizeRMB
Zoom / Zoom In / Zoom OutCamera zoomWheel

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:

1

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).

2

Create the widget at runtime

In your player Blueprint, use the Create Widget node (Class = your Widget Blueprint) and then Add to Viewport.

3

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.

4

(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

GroupBind names
Color pickerColorWheel · ValueBar · ColorPreviewNew · ColorPreviewOld · SRGBPreviewCheck
RGBRSlider/GSlider/BSlider · RText/GText/BText
HSVHSlider/SSlider/VSlider · HText/SText/VText
HexHexText
ToolsEyedropperButton · SwatchPanel · AddSwatchButton
BrushBrushShapeSelector · BrushSizeSlider · MetallicSlider · RoughnessSlider · OpacitySlider · HardnessSlider (+ matching *Text)
CommandsClearButton · 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.

HUD Button

“PaintForge HUD Button” — a self‑contained action button: drop it anywhere, pick its job, done.

Choose the command from the Action dropdown and it just works — no naming, no graph, no wiring. The paintable component is resolved automatically from the owning player’s pawn (or point it at a specific one with SetTargetComponent).

ActionRuns
Palette (Open/Close)Toggles the color palette.
Eyedropper (Pick)Arms the eyedropper for the next tap.
UndoSteps back one stroke / fill / clear.
ClearRemoves all paint.
FillFlood‑fills the surface with the current brush.
Brush + / Brush −Increases / decreases brush size.

Style via Button Height, Accent Color, Label Color and an optional custom font, or subclass in Blueprint to redesign the look.

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.

PropertyPurpose
Base/Knob DiameterSizes of the ring and knob.
Max Travel RatioHow far the knob can move from center.
Dead ZoneInner zone read as zero (kills drift).
Dynamic OriginRecenter the base under the finger on press.
Hide When IdleShow the stick only while touched.
Base/Knob Color & BrushTints 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

GestureAction
One‑finger dragPaint
Two‑finger dragOrbit camera
PinchZoom
Tap a HUD buttonPalette · 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.

SettingDefaultDescription
Default Paint Resolution1024Resolution for new paint render targets.
Base Color ParameterPF_BaseColorMaterial parameter receiving the painted color.
Material Props ParameterPF_MaterialMaterial parameter receiving metallic/roughness.
Paint Layer ParameterPF_PaintLayerOverlay layer parameter (color + coverage).
Original Base Color / NormalPF_Original*Overlay source‑texture parameters.
Max Undo Steps8Undo snapshots retained per surface.
Default SwatchesPalette swatches surfaced in the UI.

Function Library

A set of ready‑made Blueprint helper nodes for color and brushes, available in any graph.

NodeDoes
HSV To LinearHSV → linear color.
Linear To HSVLinear color → H, S, V.
Hex To Linear“RRGGBB” / “#RRGGBB(AA)” → color.
Linear To HexColor → uppercase hex string.
Create Brush TextureBuilds a brush mask texture.
Create Ring TextureBuilds a hollow ring cursor texture.
Read Render Target Pixel LinearReads 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

1

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.

2

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.

3

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

ActionClient callServer result
Brush dabRequest Network Paint At Local SurfaceValidates the brush, applies the dab, then multicasts it.
Flood fillRequest Network FillApplies the fill and multicasts the brush payload.
ClearRequest Network ClearClears 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.