"Orient a flat decal box to the hit normal"
- A splat / impact mark on a wall lies flat on the floor instead of flush against the surface.
- Floor decals work fine, but wall and angled-surface decals are rotated 90 degrees wrong.
Rotation.FromYaw(yaw) only sets the yaw — the box's up axis stays world-up. That works for floor hits (normal is roughly world-up) but fails on walls and tilted surfaces where the decal's thin face needs to align with the hit normal.
Build the rotation so the box's thin axis (+Z) points along the surface normal:
Vector3 n = traceResult.Normal;
// Pick a reference vector that isn't parallel to the normal
Vector3 refv = MathF.Abs(n.z) > 0.99f ? Vector3.Forward : Vector3.Up;
// Build an orthonormal frame with +Z = normal
Vector3 fwd = Vector3.Cross(refv, n).Normal;
Rotation rot = Rotation.LookAt(fwd, n) * Rotation.FromYaw(yaw);Then offset the decal along the normal to clear the surface:
Vector3 position = traceResult.HitPosition + n * 0.5f;This generalizes the floor "decal-gap" rule (raise z at least 0.5 above the ground) to any surface — walls, ceilings, angled props.
Make it a FILM, not a slab — scale the thin axis to ~0.02 m so it reads as a surface mark, not a floating block.
Rotation.LookAt(forward, up) constructs a rotation where the second argument becomes the local +Z (up) direction. By passing the hit normal as the up vector, the box's thin face aligns flush with whatever surface was hit. The refv guard avoids a degenerate cross product when the normal is nearly vertical. Adding a random yaw spin via * Rotation.FromYaw(yaw) gives visual variety without breaking the alignment.