Damage material¶
The plugin ships a wall material that draws damage in the shader:
- chips with parallax depth inside dents;
- cracks spreading from dents and holes;
- the material's interior on broken rims;
- dust around holes.
It reads everything from vertex data the wall mesh already carries, so:
- nothing travels over the network, and a player who joins mid-match sees the same wall;
- nothing is computed on the CPU when a wall is hit;
- an intact wall looks exactly like its textures.
Cost: three texture reads and about 40 ALU instructions per pixel of wall. No extra draw calls.
What ships¶
In /GridDestruction/Materials/:
| asset | what it is |
|---|---|
M_Grid_DamageWall |
a complete wall material; make instances of it |
MF_GridDamageUV |
function: UV → FaceUV with the parallax offset, and DetailUV |
MF_GridDamage |
function: your BaseColor, Roughness and Normal → the same with damage, plus AO |
T_Grid_DamageDetail, T_Grid_DamageDetail_N |
the crack and chip texture and its normal map |
MI_Grid_Damage_Brick, _Concrete, _Stone, _Wood, _Metal, _Glass |
demo instances with tuned values and placeholder textures in Materials/Surfaces/ |
The shipped GP_* presets already use the demo instances, and the CSV's
FractureWeightMask row gives brick, stone and wood their placeholder height
maps as the break pattern.
Make an instance for your surface¶
- Right-click
M_Grid_DamageWall→ Create Material Instance. Save it in your own project, for example/Game/Materials/MI_Brick_Damage, not in the plugin's Content, so a plugin update never overwrites it. - Open the instance. Under Parameter Groups you see Surface and Grid Damage. A parameter stays grey until you tick the box to the left of its name; unticked, the instance takes the parent's value.
- Set the Surface group (below), save with Ctrl+S. The preview and the walls in the level update at once.
You need one instance per wall material: MI_Brick_Damage,
MI_Concrete_Damage and so on.
Surface group¶
| parameter | what to set |
|---|---|
BaseColorMap |
the albedo, for example of your brick. sRGB on, like any colour texture |
NormalMap |
the normal map. Its texture must have Compression = Normalmap, or the parameter reports a sampler type error |
BaseTint |
a colour multiplier. White by default: the texture as it is |
Roughness |
one number: brick 0.85–0.9, concrete 0.9. For a roughness map, use the functions instead (below) |
UVTiling |
the number your old material multiplied TexCoord by. If it used TexCoord directly, leave 1 |
DamagedColorMap |
optional. A texture of the broken material: bare brick without patina, concrete with exposed aggregate, fresh wood. Shown in the damaged area and on rims when DamagedMapAmount > 0 |
DamagedNormalMap |
optional. The normal map for DamagedColorMap, Compression = Normalmap, so the relief changes too |
Check
On an intact wall the instance must look exactly like your old material. If it does not, the Surface group is set wrong; the damage part has nothing to do with it.
Put it on the walls¶
Through the CSV, so the value is not lost: write the instance's path in the
WallMaterial row of the right column of GridMaterials.csv and run the table
script (Surface presets).
Without the CSV: put the instance in the preset's WallMaterial and press
Apply Preset.
Not on the actor
A material assigned on the wall actor is overwritten by the preset the next
time it is applied. GridDestruction.CheckPresets should print MATCH.
bEmitDamageAttributes on the wall's GridWallMesh component is on by
default. If nothing reacts to hits, check it on the placed actor, not the class.
Tuning without PIE¶
- Shoot a wall in PIE and run
GridDestruction.CaptureDamageto save its damage into a damage preset (Setup → saved damage). - Place a test wall with that preset as its Initial Damage. The editor viewport shows it damaged.
- Open the instance next to the wall and turn the parameters: changes show at once.
It helps to have light dents, a deep crater and a hole through on one preset.
Grid Damage parameters, in tuning order¶
a) Crack scale: DetailTiling (default 2)¶
Crack tile size = UV Tile Cm / (UVTiling × DetailTiling). With a 100 cm UV tile
and UVTiling 1 the tile is 50 cm: a crack network cell of about 11 cm and chips
of 2–4 cm.
- For brick use 2–3, so cracks are in scale with the bricks.
- If you see a repeating pattern, use a non-integer such as 2.37, so it does not line up with the brick tile.
b) When chips appear: DentGain (default 4)¶
Chips show fully once 1 / DentGain of the thickness is gone. The rule:
DentGain ≈ ThicknessCm / the dent depth in cm at which chips should show fully
For full chips at a 4 cm dent:
| material | thickness | DentGain |
|---|---|---|
| brick | 20 | 5 |
| concrete | 25 | 6 |
| stone | 40 | 10 |
| wood | 8 | 2 |
A good target: one bullet leaves visible but not solid chipping.
c) Cracks from holes: BreachCracks (default 1), with BreachFalloffCells¶
BreachFalloffCellson the preset (brick: 2.5 cells) sets how far the zone around a hole reaches.BreachCrackssets how densely cracks fill it: 1.5–2 for more cracks at the edge, 0 for cracks only inside dents.- To make cracks reach further from a hole, change
BreachFalloffCellsin the CSV, not the material.
d) The damaged area: DamageTint, AreaSoftness, DamagedMapAmount¶
A dent is coloured as one patch, and the patch's edge is:
- ragged and chipped, like knocked-off plaster, not the shape of the cells;
- sharp, a pixel wide at any distance: neither blurry up close nor stepped far away;
- sometimes stopped by cracks, where the breakup is lower.
| parameter | default | what it does |
|---|---|---|
DamageTint |
0.8, 0.75, 0.72 | colour multiplier inside the patch. Lower is darker and more visible; 1, 1, 1 turns the patch off |
AreaSoftness |
1.5 | edge width in pixels: 1 is sharpest, 3–4 softer. Below 1 it may shimmer far away |
DamagedMapAmount |
0 | 0: the patch and rims use the face texture, tinted. 1: they show the broken material (DamagedColorMap, DamagedNormalMap, DamagedRoughness). The demo instances use 1 |
DamagedRoughness |
0.95 | roughness of the broken material |
Rims (caps and opening reveals) look exactly like the face material on an intact wall. The broken material appears on a rim only as it is damaged: at the edge of a hole through, and where a side hit chipped the rim.
Intact and broken in one material. The patch grows with the cell's damage:
the deeper the damage, the more of the surface becomes the broken material. It
works like two instances, intact and broken, blended by the damage mask, but in
one material and one pass. Hits shallower than DentStepCm leave the geometry
flat and show only here.
If you cannot see the patch, light dents are too shallow for DentGain: raise
DentGain or darken DamageTint.
e) Colours¶
| parameter | what it does |
|---|---|
CrackColor |
crack colour, near black; dark brown for brick |
ChipTint |
multiplies the surface colour inside a chip. Below 1 gives shadow and a sense of depth |
InteriorTint |
multiplies the surface colour on a hole's rims. Can go above 1: a fresh break is lighter than the surface |
DustAmount, DustTint |
dust around holes. Its colour is the average colour of the texture × DustTint (slightly lighter by default: 1.15, 1.12, 1.08). The master material reads the average from the smallest mip of BaseColorMap, so dust always matches the material |
f) Depth: ParallaxDepth (default 0.02), tune last¶
An offset in fractions of the face tile: 0.02 on a 100 cm tile is about 2 cm at grazing angles.
- Check it by walking along the wall at a sharp angle. If the texture inside chips swims, lower it.
- Working range 0.01–0.04; 0 turns parallax off.
g) Relief: NormalStrength (default 1)¶
Concrete and stone 1.2–1.5, brick 1.
Starting values¶
| Brick | Concrete | Stone | Wood | |
|---|---|---|---|---|
| DentGain | 5 | 6 | 10 | 2 |
| DetailTiling | 2.4 | 2 | 1.6 | 3 |
| BreachCracks | 1.2 | 1.5 | 1.2 | 0.5 |
| ParallaxDepth | 0.02 | 0.025 | 0.03 | 0.01 |
| CrackColor | 0.06, 0.035, 0.03 | 0.05, 0.05, 0.05 | 0.04, 0.04, 0.04 | 0.05, 0.035, 0.02 |
| ChipTint | 0.85, 0.75, 0.7 | 0.9, 0.9, 0.9 | 0.85, 0.85, 0.85 | 0.8, 0.7, 0.6 |
| InteriorTint | 1.1, 0.9, 0.8 | 1.15, 1.15, 1.15 | 1.05, 1.05, 1.05 | 1.2, 1.05, 0.85 |
| DustTint | 1.15, 1.1, 1.05 | 1.15, 1.15, 1.15 | 1.1, 1.1, 1.1 | 1.2, 1.15, 1.05 |
| DustAmount | 0.3 | 0.4 | 0.3 | 0.2 |
| NormalStrength | 1 | 1.3 | 1.5 | 0.8 |
| DamageTint | 0.8, 0.7, 0.65 | 0.85, 0.85, 0.85 | 0.8, 0.8, 0.8 | 0.75, 0.65, 0.55 |
| AreaSoftness | 1.5 | 2 | 1.5 | 1 |
The crack textures (DamageDetail, DamageDetailNormal) do not need
overriding: one pair suits brick, concrete, stone and plaster. Swap them only for
a different kind of break, such as wood splinters or torn metal. The crack
texture is made for mineral materials, so metal and glass look best with their
own detail textures.
Keep your own material: the two functions¶
If you already have a good material, for example with roughness and AO maps, keep it and wire in the two functions instead:
TexCoord[0] (× your tiling) --> MF_GridDamageUV.UV
MF_GridDamageUV.FaceUV --> the UVs input of EVERY surface Texture Sample
(colour, normal, roughness, AO)
MF_GridDamageUV.DetailUV --> MF_GridDamage.DetailUV
your albedo at its smallest mip --> MF_GridDamage.SurfaceAverage (optional)
(a Texture Sample of your albedo: MipValueMode = MipLevel, MipValue = 14,
UVs = Constant2 0.5, 0.5. Unwired, dust is neutral grey)
your broken-material texture --> MF_GridDamage.DamagedColor (optional,
with UVs = FaceUV; used when DamagedMapAmount > 0)
your BaseColor / Roughness / Normal --> the inputs of MF_GridDamage
MF_GridDamage: BaseColor / Roughness / Normal --> the material's pins
MF_GridDamage.AO --> Ambient Occlusion (multiply with your own AO)
The Grid Damage parameters appear in your material's instances, and everything above applies to them.
Without FaceUV on the textures there is no parallax: the surface textures
must take their UVs from FaceUV, or the offset has nothing to move.
Parallax: where it is and how to see it¶
The parallax is kept cheap, so it is subtle by nature:
- It works only where there is depth: in dents and open cracks. On an intact wall the offset is zero.
- It shows only at an angle. Straight on the offset is close to zero, which is physically right. Walk along the wall and look at a dent from the side.
- To check it is wired: set
ParallaxDepthto 0.1 for a moment and look at a dent at an angle. The texture inside the chips should sink and swim. Then set it back to 0.02–0.03. - If nothing changes with your own material, the textures are not taking
FaceUV.
Most of the depth still comes from the dent's geometry, the chip normal and the AO; parallax adds the sense of "inward".
The data under the material¶
Use this to write your own damage material, or to check the data is arriving. Every vertex of a wall's visual mesh carries four damage channels and a second UV set, filled on every rebuild, at 20 bytes per vertex. The collider never carries them.
Vertex colour¶
| channel | carries | range | use it for |
|---|---|---|---|
| R | remaining material at this vertex: the thickness left, or what side cuts have left of a cell's width, whichever is lower | 1 intact → 0 eaten through | crack masks, roughness, depth, tint toward the interior colour |
| G | breach proximity | 1 at an opened cell → 0 at BreachFalloffCells |
dust, soot, crack density, aggregate around a hole |
| B | interior-surface mask | 1 on rim and cap quads, 0 on the two faces | the material switch: Lerp(FaceFinish, InteriorFinish, B) |
| A | which face | 1 front, 0 back | a different finish per side. Read it only where B is 0: Lerp(Back, Front, A * (1 - B)) |
B is the one that earns the feature. A hole's rim and a capped edge are the broken thickness a player looks into. Without B a rim inherits the face's brick or plaster, and the hole reads as a cut in paper. Wire B first, then R, then G.
R always matches the geometry the player sees, and every machine computes the same values.
UV1¶
TexCoord index 1: 0..1 across the whole wall on both axes, whatever its
size, and independent of UV Tile Cm. It does not move when the wall is damaged.
Use it for anything that should stay put on the wall: a grime gradient from the
floor up, a decal atlas, a per-wall variation mask.
Seeing a channel with your own eyes¶
Make a scratch material with Shading Model: Unlit and plug VertexColor
into Emissive Color. Put it in the preset's WallMaterial (not on the
actor) and press Apply Preset. Shoot the wall: red fades toward black in craters
(R), green blooms around openings (G), and every rim and capped edge is blue (B).
For UV1, plug TexCoord index 1 into Emissive: a clean red-green gradient across
the wall, unchanged by shooting it.
- B flat: the wall has no rim to show. Check
HoleRimThicknessFractionandCapEdges. - G flat:
BreachFalloffCellsis 0, or nothing has gone through yet. - Everything flat:
bEmitDamageAttributesis off on the placed actor.
What you see → what to turn¶
| symptom | cause and fix |
|---|---|
| a light or white patch around damage | that is dust. It takes the texture's average colour, so a light patch means DustTint is too high or, with your own material, SurfaceAverage is not wired. Set DustAmount to 0 to check |
| the whole wall is white or light grey | BaseColorMap is not set: the default is a white texture |
| the whole wall is darker than before | BaseTint is not white |
a checkerboard or an error on NormalMap |
the normal texture's Compression is not Normalmap |
| nothing changes on hits | the material did not reach the wall (run CheckPresets), bEmitDamageAttributes is off, or DentGain is too low |
| one bullet chips the whole dent | lower DentGain |
| cracks are huge or tiny | DetailTiling |
| a repeating pattern shows | give DetailTiling a fractional part |
| the texture swims as the camera moves | lower ParallaxDepth |
| no parallax | see Parallax |
| a hole's rims look like the face | channel B: check HoleRimThicknessFraction |
| chips on the back opposite a dent | expected: R is the total thickness, so the back also "sees" the dent. It reads as spalling from behind |
| the chip edge follows the cell grid | the mask is interpolated between vertices. Finer cells (SubdivisionFactor) or a higher DetailTiling help |
| the patch edge is blurry | AreaSoftness is too high |
| the patch edge shimmers far away | raise AreaSoftness to 2 |
If your symptom is not here, send a close and a distant screenshot of the wall with the instance's Details panel.