Spherical Explosion Decal

I’m trying to find a way to project a decal outward from a point. With a planar decal, it looks stretched and distorted if it hits a plane oriented too differently, like an explosion hitting orthogonally against a wall but also clipping the floor. For dynamic decals, like explosions, it would ideally be projected against each plane depending on the normals in the GBuffer. I think there’s probably a way to have an image mapped spherically and projected outwards, but there’s one extra complication. An explosion decal wouldn’t be mapped spherically like you see a flattened globe, but rather by distance where points that are further from the center of the explosion will have the scratchier edges of the texture. Hopefully that explanation makes some amount of sense.

I’m not sure if I’m overthinking this or if there’s already a standard solution, but I can’t find anything online. I have an idea where I might be able to map an image based on position, after expanding the minimum radius outward from the center of the image based on the distance from the center of the explosion to the position of the pixel, but I don’t know if that will work. Does anyone have any ideas or useful links or questions that I could clarify?

The main point is that I want a realistic looking explosion decal on surfaces oriented in different directions.

Hairy ball theorem means this is not possible to solve without a 3d volume texture for the decal. It’s also not possible for there to be an analytic solution as it’s a whole surface problem.

Decals w/ proper decal-meshes

Depending on how you can constrain your decal you might be able to do different things. Options would include geodesic distance or conformal mapping.

I use least-squares conformal mapping for automatic UV chart generation - it would be plenty fast enough for relatively limited decals (say ~100-200 triangles involved).

Geodesic distance is also pretty quick (I’ve done it over the surface of volumes before) and fairly simple.

Projected / deferred / w|e decals

Depending on what your decal needs to do you might be able to fudge things.

If the decal is something like an area-of-effect blast template then you could fudge cubemap coordinates with texelFetch/Load (GLSL/HLSL respectively) based on surface normal vs the decal projector’s orientation. Fairly stupid though since you could just use a volume tex instead and it’s also the same as doing a cylindrical projection.

Or use a cylindrical projection in which everything oriented to the cylinder caps receives the decal image as-is while everything inside the projection volume but not appropriately aligned receives a cylindrical projection oriented around the center of your decal - the sum of the distances from the center-line of the cylinder and the bottom of the decal then becomes the virtual-V shift out from the center (or just use two different textures for the projections).

In fewer words that’s “map as-is inside when aligned to the caps, map in polar-coordinates when inside and not aligned using V coordinate based on Manhatten distance from ground-zero”.

Edit: or if there’s a physical process you could just store data in a cube/spherical map and update a global decal map (like a lightmap) by solving whatever your data represents.

How about something similar to shadow mapping.

How about something similar to shadow mapping.

That’d be a projector, they stretch. If I’ve interpreted it correctly what he wants would be the same as if you folded a piece of paper around a corner, which is different from the stretching that occurs if you point a slide projector at a corner (fixed surface area vs extremely variable surface area).

That’s a good way of putting it. I’ll have to read through those links and do some more research since I’m not familiar with all the topics you mentioned.

Do most games just use flat projections and accept that there will be some stretching?

I’ll have to read through those links and do some more research since I’m not familiar with all the topics you mentioned.

Conformal mapping isn’t trivial. Geodesics are much easier, but if you have the math background conformals are much more elegant. Both can be used for fire-and-forget solutions. Hairy-ball still applies and you can’t perfectly map a sphere, you still have to split it up into halves at the least.

Do most games just use flat projections and accept that there will be some stretching?

Both. Plus some correction, such as aligning the decal perpendicular to the surface normal (for fluids like blood stretching isn’t necessarily bad depending on the image). Urho3d has a reasonably robust implementation of mesh decals if you need some reference material on how to do mesh based decals in the general sense.

Deferred decals really are what @willmotil described, use the same core techniques as shadowmaps or spotlights, which are just projection. They’ve become relatively standard as their trivial to implement in a deferred renderer.

I decided to go with a bit of hack that works well for my case specifically. Since most of my wall are vertical and most of my floors are horizontal, I just angled my decal box down at a 45 degree angle so that the projection against a wall or the floor has the same stretch. Then I can pre-shrink my decal texture so that it’s the correct size after the stretch.

The problem I’m having now is that one of the diagonal seams of a geometry face is showing up darker, as shown below, and I can’t figure out why. I’m just reconstructing the world position, converting to object space, and transforming to the texture coordinates. I don’t know why pixels around the seam would behave any differently from the rest.

Have you drawn your decal box as a wireframe to be sure it’s in alignment with the decal box edges and not just some anomaly in the texture that’s getting exacerbated (like alpha filtering getting trash color)?

Are the vertices of your box being reused? You aren’t calculating unique vertices per box triangle-face that might be rounding off differently and thus overlapping a smidge?

Yes it’s definitely an edge, although it seems to only be one of the edges and only from certain angles. The one seam is visible from the angle used for the left images, but neither seam is visible on the right.

I’m reusing the same 8 vertices with a triangle strip, and the visible seam is between the 11 and 12th (final) triangles.

False alarm, I fixed it.

The problem was that I was in the middle of reformatting my GBuffer and blend states, so instead of proper alpha blending I was sampling from the albedo render target and manually blending in the shader. After changing this to normal alpha blending (the one described by IceFall Games where you can use SourceAlpha for blending, but then write BlendFactor to your alpha channel for emissive) it looks great.

2 Likes

I was thinking about this some more recently because I wasn’t quite satisfied with a planar projection that requires knowledge of which direction the walls/floor are.

I prototyped a few other implementations of spherical projections, with disappointing outcomes, but I’m glad I got closure.

  1. At first I thought a possible solution would be to draw the intersection of a bumpy sphere with the floor and walls, but this produced weird spots around the edges where the bumps intersected the wall, but the intersection was disconnected from the rest of the decal.
  2. Then I thought a more realistic way would be to project rays outward from the center at different lengths, because this would cause that streaking pattern that you see in the screenshots above, but that only works when the explosion is directly on the wall. When you’re projecting sideways towards the wall, it just looks like a dense cluster of dots.
  3. I decided awhile later that I may be able to improve this if I round my spherical coordinates, grouping individual dots into larger blobs. This is probably the best I could produce with this method, but I’m not sure it would ever look close enough to a flat decal to be worth being able to project in all directions. Another problem is that it only appears to spread radially outward so well on a vertical wall, because this is in the x,y-plane where spherical coordinates spread outward like that. On the ground, in the x,z-plane, it doesn’t look quite as nice. I’m not sure if there’s any way around that.

If anyone tinkers with this or has any ideas on how I might be able to improve it, please let me know. The jsfiddle is set up to sort of simulate projecting a 3d plane onto a 2d screen and coloring pixels, as the shader would.
http://jsfiddle.net/oochbjm4/242/

So I guess these are similar to what AcidFaucent referred to as physical process representations because they project rays outward.

I also looked into the cylindrical projection, but I think that would still have stretching issues, although not as much as planar projections. Imagine if you have a cylinder with axis normal to a wall, but some lower portion is cut off by the floor. Then your polar coordinates to those pixels on the floor would be squished. Even if you do the Manhattan distance to correct for distance from the wall, your projection from center axis to the floor will still be squished a lot below the axis and a little at the edges. Essentially, there’s no way to fit the pixels from a whole arc into the pixels of a straight line across the end cap without some squishing.