Is there a sane way to project a decal to a skinned mesh?

Started by
5 comments, last by Vilem Otte 7 years, 4 months ago

My first thought was to use the regular deferred method. But then I realized later on that this... has plenty of problems. The first being that the deferred decal would need to add the object to the filter. But then suddenly, as the mesh moves around the decal is projected all over the mesh and disappears again.

My second thought was to use the old school approach, and try to generate the geometry. based on the skinned meshe's geometry. That didn't work out so well at all. There's quite a bit of Z-fighting. And trying to keep track of that data when it's generated on the GPU is messy.

My other thought was to try and paint it onto the object's UVs. But I'm not sure how to do this efficiently. If I edit one texture, it may suddenly just appear on other textures. If I create a new texture every time, it might just be eating up a lot of space. And then there's the whole history thing of progressively removing the decals.

Advertisement

you need my 10 channel weighted real time texture blender code i wrote for caveman v2.0 ground textures! <g>

modding textures sounds like the least work. assuming you can do it fast enough. lock surface, memcpy. you'd keep masters of your basic source textures: skin, dirt, scars, blood, etc. when you needed a texture with decals, you'd first check yuor blended texture cache to see if its already blended for you. if not, blend it, then cache the results, with a LRU algo for cache discard. that way all you have to do is specify you want a list of textures as the texture for the model. when you render the render queue, the cache and blender supply the required blended texture to set__texture().

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

That... went over my head completely. The most I could catch was the LRU.

I think I might settle for computing the projection geometry on the CPU and then batch render the decals as skinned batches of geom.

It is not a trivial problem and might depend how accurate you want it. For a bullet or blood splat, maybe you could do this:
  1. First you have to compute the hit point on the skinned mesh, maybe the triangle hit and the barycentric coords. You could use a low poly proxy mesh for this.
  2. Then use this to find the uv coords on the texture (you can compute this from the triangle uvs and the barycentric coords of the hit).
  3. For rough stuff, I'd just blat a source texture (bullet, blood etc) onto your 'decal texture' (matching the skin texture, see below). However, even for this you will probably want to e.g. confine the blat to only the uv island that has been hit, otherwise you will get bits of the decal landing in other parts of the character.. and you will get cutoffs at the seams unless you specifically handle this.
How you handle your 'decal texture' depends on the game, as Norman hints. If you are not reusing skinned textures, you could blat straight to the final skin texture. If you are reusing skinned textures with several models, you will want an intermediate of some kind. Either a copy of the original skinned texture (or part of it) or a transparent texture to be multitextured with it in realtime. I would have thought the former might make more sense usually, but the latter might conceivably be better in some circumstances (multi channel PBR textures maybe?).
If you wanted to do it accurately, I assume you'd have to do what I do in projection painting : calculate a matrix to get the skinned mesh into decal 'view space', then projection paint each triangle (bake). But this might be overkill and slow...
A quick search shows a guy implementing this in unity, probably using the latter accurate approach:

I'm not a graphics guy, but zfighting isn't the problem, you can always displace your materials in unity (check the offset directive/property from shaderlab), and you can displace the projected mesh along the normals. Distortion is the problem, but that's a decal problem (I don't know any method that can't distort).

I think a vertex blended material is the way to go in most cases, but that depends on the context.

Doing this from scratch, so I don't have any of Unity's materials.

It is not a trivial problem and might depend how accurate you want it. For a bullet or blood splat, maybe you could do this:
  1. First you have to compute the hit point on the skinned mesh, maybe the triangle hit and the barycentric coords. You could use a low poly proxy mesh for this.
  2. Then use this to find the uv coords on the texture (you can compute this from the triangle uvs and the barycentric coords of the hit).
  3. For rough stuff, I'd just blat a source texture (bullet, blood etc) onto your 'decal texture' (matching the skin texture, see below). However, even for this you will probably want to e.g. confine the blat to only the uv island that has been hit, otherwise you will get bits of the decal landing in other parts of the character.. and you will get cutoffs at the seams unless you specifically handle this.
How you handle your 'decal texture' depends on the game, as Norman hints. If you are not reusing skinned textures, you could blat straight to the final skin texture. If you are reusing skinned textures with several models, you will want an intermediate of some kind. Either a copy of the original skinned texture (or part of it) or a transparent texture to be multitextured with it in realtime. I would have thought the former might make more sense usually, but the latter might conceivably be better in some circumstances (multi channel PBR textures maybe?).
If you wanted to do it accurately, I assume you'd have to do what I do in projection painting : calculate a matrix to get the skinned mesh into decal 'view space', then projection paint each triangle (bake). But this might be overkill and slow...
A quick search shows a guy implementing this in unity, probably using the latter accurate approach:

Hmm... wouldn't that be a performance problem to hold multiple textures of the same kind? Then again... maybe not... 1024*1024 is only about 4mb. How do you keep a reference to that unique instance of the texture?

Hmm... wouldn't that be a performance problem to hold multiple textures of the same kind? Then again... maybe not... 1024*1024 is only about 4mb. How do you keep a reference to that unique instance of the texture?

Well, potentially, yes, it will affect performance, depending on your particular game situation (number of players etc). But if the alternative you are thinking of is reusing a decal texture, and creating geometry and skinning it to match a skinned mesh, that's going to affect performance too, and be a whole barrel of worms to get working (I wouldn't even attempt it personally).

Typically with decals you might have some game options to decrease the amount according to the performance of your machine.

Some obvious things that come to mind, (if you are using the multitexture approach) : Reduce the size of the decal texture, maybe use a texture atlas of decal textures. If either case you might decide to only use decals on the nearest e.g. 6 characters to you, and fade out after that distance e.g., and reuse the decal textures.

Once again, (I have no idea how experienced you are), I'd like to emphasise this approach won't be trivial to get working nicely (even for someone who has a clear plan), so maybe think carefully about whether you want to spend the time on it, compared to say just a few blood and explosion particle effects.

Also, this is just a suggestion of a way which could be used to get what you desire. I'm not up on the current state of the art, so you'll have to do some googling to see if there are any established solutions, there may well be a much better solution. I gather things like screen space decals are all the rage:

http://www.slideshare.net/blindrenderer/screen-space-decals-in-warhammer-40000-space-marine-14699854

However in that slideshow they just avoid drawing on skinned objects, presumably to avoid these problems. You may be able to use something like the screen space technique to quickly bake the decal textures onto a skinned mesh though, as accuracy isn't as important as with projection painting.

Humus 3D had "volume decals" and later "volume roads" demos which address the issue of z-fighting. Volume roads are kinda similar to a decal on a character, too, since the terrain they're on usually is not even (if it was, there would be no point!).

If you tesselate the volume decal a bit (not too much really, just so it's more than basically a cube) then I don't see why a volume decal couldn't also be skinned using the same bones as the body piece under it. Weights will maybe not be 100% accurate in every tiny spot since they usually vary per-vertex, but the "volume" part should make sure there are no "holes".

That's somewhat similar to how someone implemented torn off body parts in a zombie shooter some years ago (I forgot which one Left4Dead). Instead of volume decals, they basically had simple clipping volumes (scaled spheres/ellipsoids) which were skinned with the mesh. The pixel shader then checked if it was inside a clip volume, plus some noise function for a riggedy edge, and did a discard.

Quickly thinking about this at 4am:

  • Your decal will always lie on (belong to) a single triangle - you can use weights in the triangle vertices to transform it using bone and it will stay aligned on that triangle.... in this case a big decal that would cover N triangles, you would end with N decals that would be skinned. I'd say a lot of games do it like this (or at least I'd say some of older Source engine based games do ~ Coutner Strike Source)
  • Use volumetric decals (suitable for deferred rendering), you could animate the volume with the bone it belongs to (+ weighting - based on the center point), although it wouldn't be precise. Neither animating each single corner (might be more precise, but still imprecise if the decal volume is bigger).

I'd advise against painting into texture, as it might be slow (imagine a case where you have big textures painted on big textures), and not scalable (dozens of skinned characters adding decals to each other - your memory runs out, and you won't be able to paint on their textures fast enough). Although it might be viable for some cases (you've got just 1 (or few in general) skinned geometries - and/or you want to also F.e. remember the texture into next stages of game).

My current blog on programming, linux and stuff - http://gameprogrammerdiary.blogspot.com

This topic is closed to new replies.

Advertisement