← Back to Insights

September 22, 2026

Custom Primitive Data in Unreal Engine: Breaking Environment Repetition Without Asset Bloat

Table of contents

The short answer

Custom Primitive Data, usually shortened to CPD, lets an Unreal Engine material read values stored on an individual scene primitive. An artist can place the same wall mesh fifty times, keep one shared material setup, and still vary paint color, grime amount, roughness, emissive strength, or another exposed control from one placement to the next.

That makes CPD useful for a familiar environment-art problem: repeated assets are efficient, but repetition is easy to spot. The technique gives artists more variation without demanding a unique texture set or a separate dynamic material instance for every object. It is not magic, and it does require planning. Used with a focused master material, though, it can make a modular scene feel less copied while keeping the asset library manageable.

Why environment teams are talking about it

The September 2026 production coverage of Hell Let Loose: Vietnam put Custom Primitive Data beside PCG as one of the tools that changed the team's UE5 worldbuilding workflow. The project spans six launch maps and roughly 24 square kilometres of terrain. At that scale, duplicated vegetation and modular assets have to vary, but every extra asset or material permutation creates more work to author, review, and maintain.

CPD has been available for years. What makes this example useful is seeing a large environment team apply it to visible repetition while working inside real optimization limits. Epic's Unreal Engine 5.8 documentation explains the same production case: CPD stores values on primitives rather than on material instances, which can reduce draw calls for similar geometry through Unreal's dynamic instancing path.

What Custom Primitive Data actually changes

In a standard material workflow, a parent material exposes parameters and child material instances hold different values. That is still the right setup when an asset needs a clear, reusable material variant. CPD moves selected values to the mesh component instead. Each parameter receives a numbered index, and the actor can set the corresponding value in the editor, through Blueprint, or through code.

A scalar uses one index. A vector occupies four consecutive indices for its RGBA channels. The material reads those values and uses them in ordinary shader logic. A float might control wetness from 0 to 1. Another could select among a few tint ranges. A vector could define an emissive color. Because the variation belongs to the placed object, the Content Browser does not fill up with one-off material assets.

Where CPD earns its place

Modular architecture is an obvious fit. Repeated walls can receive restrained paint shifts, dirt intensity, edge wear, or leak masks without turning one wall kit into dozens of nearly identical material instances. Industrial environments can vary warning colors, panel states, light intensity, or surface age. Roads and sidewalks can change stain levels or repair markings. Foliage can use per-instance data for color and health variation when the placement system supports it.

The best controls solve something viewers can actually see. If a city block has twenty copies of the same facade, a narrow hue range and a few weathering states may help. If a prop appears twice in a dark room, a complicated CPD system probably will not earn back the setup time. Keep the variation controlled and resist adding every possible knob to the material graph.

CPD, material instances, and per-instance data are different tools

A material instance is easy to preview, name, approve, and reuse. It is often the better choice for deliberate variants such as clean concrete, burned concrete, and painted concrete. CPD works well for placement-level differences that would otherwise produce a long tail of one-off instances. Many projects need both: a small set of approved material instances for major looks, plus CPD for local variation within each look.

Instanced Static Mesh and Hierarchical Instanced Static Mesh components also have Per Instance Custom Data. That distinction matters. Custom Primitive Data applies to the primitive or component, while Per Instance Custom Data can address members of an instanced component. A foliage cluster that needs a different value on each tree should be designed around per-instance data rather than assuming component-level CPD will separate them.

Performance claims need a real test

Epic's documentation shows CPD reducing mesh draw calls for repeated geometry when dynamic instancing can combine compatible primitives. That is a good reason to test the workflow, not a promise that every scene will become faster. Mesh, material, render state, pass count, visibility, and the shader itself still affect the result. A costly branch or a stack of texture samples does not become cheap because a float arrived through CPD.

Test a representative slice in the target build. Unreal's stat scenerendering command provides a useful first look at mesh draw calls, and Unreal Insights or a platform profiler can answer the larger performance question. Compare the current setup against the CPD version with the same camera, lighting, scalability settings, and content. If the material becomes harder to maintain without a measurable production or runtime gain, simplify it.

The limits that catch teams later

CPD values are numbers, not a replacement for all material authoring. Epic currently documents a 32-float limit. Defaults also need attention because an unset value reads as zero. If zero means fully wet, fully emissive, or an invalid variation, a newly placed mesh can look wrong until someone fills its data. Design zero as a safe state or translate the stored range inside the material.

Multiple material slots are another trap. The data lives on the component, so materials on that component read the same CPD values. A single index cannot quietly mean blue paint to one slot and dry wood to another unless the shader includes an intentional packing or decoding scheme. That can be done, but it adds complexity. Sometimes a mask, layered material, separate component, or conventional material instance is clearer.

How to build a CPD system artists can use

Start with a short index map before wiring the graph. For example: index 0 for tint selection, index 1 for weathering, index 2 for wetness, and index 3 for emissive intensity. Keep the same meaning across related master materials where possible. Changing index meanings from one asset family to another saves little and makes debugging miserable.

Expose artist-facing controls through an actor, Blueprint, PCG graph, or editor utility instead of asking everyone to memorize raw array positions. Give controls readable names, clamp unsafe ranges, and provide a reset state. Build three or four approved presets that show what the system is meant to produce. Artists can still tune individual placements, but they begin from a visual target rather than a blank set of floats.

How CPD fits with PCG and modular kits

PCG can place a large number of repeated assets; CPD or per-instance data can stop those assets from reading as exact clones. A rule can derive variation from biome, height, distance, seed, building zone, or an art-directed attribute. A wet area might raise a wetness value. A damaged district might bias wall wear. A forest edge might use a different foliage range than its interior.

Random values alone usually look like noise. Good variation follows the logic of the place. Water collects low. Sun exposure affects color. Traffic marks particular surfaces. Repairs happen in patches. When the data comes from world logic, a small set of controls can create a more believable result than dozens of arbitrary texture swaps. Artists should still be able to override the result around hero shots, traversal paths, and gameplay landmarks.

What clients should expect in a handoff

A delivered Unreal environment should not hide its variation system inside an undocumented master material. The handoff should identify the materials that use CPD, list every occupied index, explain valid ranges, and show where values are set. If PCG, Blueprint, or construction scripts write the data, those dependencies belong in the notes too.

At Skyroid Studios, that documentation is part of making an environment useful after the beauty shots are approved. A client may need to change a district palette, add a gameplay state, move the scene to a lower hardware tier, or hand the project to another team. A small index table and a few tested presets can save hours of graph tracing later.

The practical takeaway

Custom Primitive Data is a focused production tool. It gives repeated Unreal assets enough local variation to avoid the copy-paste look, and it can reduce the material-instance clutter that builds up in large scenes. Its value is strongest when the team knows which differences matter and keeps the controls narrow.

Use material instances for named, reusable looks. Use CPD for object-level values on compatible primitives. Use Per Instance Custom Data when individual instances inside an ISM or HISM component need separate values. Then profile the real scene. That division keeps the material system understandable while giving environment artists room to break repetition where players will notice it.