[RELEASED] Dynamic Decals

@Fairennuff - Apologies, entering and exiting play mode should fix the Assert Order bug. If your still unable to see projections afterwards, then this is an unrelated bug, please send me an email immediately. (Support@LlockhamIndustries.com)

I've one last bug to fix before I submit the next patch. Also going to try merge 2017.1 and 5.6, I'll be sending out copies and uploading to the store asap .

@mrBeam - Decals use sorting id's within the default layer to order themselves. I believe this takes priority over renderQueue, though not over render loop order. ie. a semi-transparent object will always render after an opaque/alpha-test object, but an alpha-test object with a higher sorting id/layer will render after an alpha-test object with a lower sorting id/layer, even if it has a lower renderQueue. If you wish to guarantee objects showing before or after, you would have to put them on layers above or below the default sorting layer. I might be able to expose the option to have decals use an optional specifiable sorting layer, would this be helpful in your use-case?

@unitynewb - I'd rather release the next patch when I'm confident I have all the known bugs, nothing like a few hundred new customers to stress test the system. What Unity version are you using? Mac or windows? build platform? Deferred or Forward rendering? Send me an email (Support@LlockhamIndustries.com) and I'll send you a build once it's done.

So I've bought this in the sale to see whether or not it works better than the other deferred decal asset I have. My apologies for not having caught up on this thread yet. I'm still crunching on freelance work and don't get to spend much gamedev related time atm.

When I try the showcase scenes, 2 of them are broken because I have non-default physics layer settings, but that's easily fixed (though I don't think having objects that need to collide with stuff on the UI layer is a good idea, when they could be on e.g. the default layer).
What worries me more is that I see a whole lot of GC allocations, where I was expecting to see 0 kb of per frame allocations. The goo demo is the worst, where while firing I see roughly 100kb GC alloc per frame, which tanks the framerate to unusable depths. I'm guessing the pooling isn't working as expected?
In the showcase scene where nothing actively happens I see 1.2 kb GC alloc per frame, even if I disable everything except the camera. Can that be fixed?
It's great to see you have masking implemented already, because the other system I'm using doesn't have that yet, and I see you have interesting unique types of decals like the 9-slice. But if we can't get the per frame GC alloc to 0 kb I probably can't use it.
What surprises me, is that just having dynamic decals imported in the project does seem to set up the hook in the render events that cause the GC alloc, even in my own scene where I haven't even used a single one of your decals yet. I'm not the biggest fan of that. I'd prefer if I had a visible component on the camera that I can turn on or off at will, even if that means one more step required to set decals up.

I think I'll wait for future updates and see whether these things change, I don't need to pick a decal solution right this moment and can work on other things, so no rush. And I do remember that we spoke about my specific usecase a long while ago and you recommended that a custom solution tailored to my usecase would likely give me the best results, and I still think that is true. I have some ideas for solving decal-like effects on some of my assets without actually using decals, but for terrain deferred decals are still up for consideration and I'd really like to avoid doing much custom work on this aspect because I feel like I can create much more value for my game with spending time on other things. So I remain hopeful that one day one of the assetstore decal solutions will solve all my needs. On paper your's already does , but I don't think the performance is where I need it to be yet.

Hi @Llockham-Industries , I have scenes which use static batching, I have lots of tiny tile meshes which are marked as static so they are rendered in the same batch.

for some reason when I enable a projection renderer on the scene, the batch count goes to hell, looks like enabling the projection forces unity to Re-render all static marked meshes but individually, and I go from 250 batches to 1900 in just a click.

I'm using deferred rendering so this shouldn't happen right? the decal shouldnt trigger a re render of the depths if the depths are already there in the deferred buffer, so what's going on?

by the way I tried different settings, removing all lights in scene, removing the water plane, etc etc, the decal always produces at least twice batches when on

Okay 2.02 has been submitted to the store. It will fix the infamous AssertOrder() bug as well as a tonne of others. VR with and without Single Pass rendering will now work in Deferred as well as forward, and the technique has been unified across 5.6 and 2017.1. Android should build and render correctly and any MacOSX editor issues should be solved now. There are still a tonne of optimizations and features I want to add but priority will always be on a stable release, appreciate your patience everyone.

Edit - I've also added the old demo scenes, compiled into a new Demo scene .

If you want a build before it hits the store hit me up at (Support@LlockhamIndustries.com) and I'll send out early copies. If you've already emailed me, I'll be sending out fixes shortly .

@Martin_H - Layers are used for masking now, and Unity only has so many built in, so options are limited in the demo scenes.

The 1.2kb memory allocations are 2 GetComponent() calls, checking for ProjectionBlockers. GetComponent calls only allocate memory in editor (Internally creating Debug strings), in actual builds they have no memory allocation cost, so can safely be ignored. Other allocations are likely from co-routines in the fade components (Definitely fits the goo scene), which is adding up when you have a lot of fading decals. That might warrant a redesign, I'll experiment a little, moving into update might be more performant, or registering all fade scripts into a single universal routine so we don't have 2000 projections calling update each frame .

In editor the system is initialized whenever you place a projection, even if it's deleted before play, the system will then carry over into play mode. In builds the system will be initialized whenever your first projection lands and stay until close. However, shader replacement, ordering etc. essentially everything bar checking the count of projections each frame, is only performed if you have active projections in your scene. It's essentially poll the count of a list each update, or have the system completely shut down/ reinitialize each time your projection count dips to 0.

I'll continue optimizing. If scriptable render-loops ever come into being, and they're everything their current documentation suggests they will be, check back. I'll be able to optimize the system like crazy.

@Cleverlie - Shader replacement is required to render the mask layers into the mask buffer. I'm grabbing depth and normals at the same time where possible as well (In the same pass, so free). Using the deferred buffers would be nice, but it would limit us to rendering only on objects that are rendered in the deferred loop (A lot of custom shaders only support forward rendering, anything created by shader forge for example). It would also require we have those buffers complete before we start rendering, as we are rendering in the deferred loop itself, we can't pull from and draw to those buffers at the same time.

As for batching, could you try disabling static batching and leaning on dynamic batching? I'm certain shader replacement in it's current form supports dynamic batching at least, static batching is unfortunately questionable. Especially as the way I'm rending masking buffers is splitting up the render queue.

The 1.2kb memory allocations are 2 GetComponent() calls, checking for ProjectionBlockers. GetComponent calls only allocate memory in editor (Internally creating Debug strings), in actual builds they have no memory allocation cost, so can safely be ignored.

Click to expand...

I didn't know that was possible, but it's good to hear it won't happen in a build!

Other allocations are likely from co-routines in the fade components (Definitely fits the goo scene), which is adding up when you have a lot of fading decals. That might warrant a redesign, I'll experiment a little, moving into update might be more performant, or registering all fade scripts into a single universal routine so we don't have 2000 projections calling update each frame .

Click to expand...

Based on my own tests it's definitely a good idea not to have Update() on every decal and would be much better to register them in a central place and handle fading from that one Update() on a manager object.

I'll continue optimizing. If scriptable render-loops ever come into being, and they're everything their current documentation suggests they will be, check back. I'll be able to optimize the system like crazy.

(A lot of custom shaders only support forward rendering, anything created by shader forge for example).

Click to expand...

Shaderforge has options for forward or deferred shaders. What exactly does it do when I select deferred, that would lead to it being still rendered in forward? Or how could I verify in which queue my custom Shaderforge shaders are being rendered? When in the framedebugger I see my shader being rendered before per pixel lighting is applied, does that mean it was correctly put in the deferred queue?

@Martin_H - I guess it does it does support deferred then. I confess, I was going off a lot of the shaders that where sent to me by customers made in shader forge . Nevertheless anything with a custom lighting setup, ie. custom snow shaders/ sand shaders etc. need to be rendered in forward.

Digital ApeModerator

Based on my own tests it's definitely a good idea not to have Update() on every decal and would be much better to register them in a central place and handle fading from that one Update() on a manager object.

Click to expand...

This is the perfect choice for a manager as the the update overhead gets a bit too high if we are working with hundreds).

I'll continue optimizing. If scriptable render-loops ever come into being, and they're everything their current documentation suggests they will be, check back. I'll be able to optimize the system like crazy.

Click to expand...

And this is why this system is worth investing in, can't put a price on dev hearts

As I understand it a lot of design decisions (not the one putting Update on every pixel ) are basically Unity's fault due to lack of flexibility.

As for batching, could you try disabling static batching and leaning on dynamic batching? I'm certain shader replacement in it's current form supports dynamic batching at least, static batching is unfortunately questionable. Especially as the way I'm rending masking buffers is splitting up the render queue.

Click to expand...

Have you tried instancing as well? I guess this is one of the SRP fixable issues.

-

Anyway, recommending people to just try this asset out, it's rather good so far!

I have another challenge that I am trying to find a way around without hacking your code again. Using a Ray Positioner and/or printer, the decal takes the rotation of the ray, not the rotation of the surface it collided with. So if I am close to the surface I wish to project to, and look down and to the left for example, the decal rotates to match that look rotation. If this was by design then I get it and will just have to hack the code. However, it seems that from a ray positioner standpoint that this might not have been the intent. What I need is for the decal to maintain it's rotation relative to the collided object plus any rotation offset entered in the parameters.

Also, on line 62 of your positioner code, you cast the ray at Mathf.Infinity which completely ignores the cast length set in the parameters. I'm fairly certain this should be set to the CastLength passed in the call.

Truly not trying to be a pain. Just trying to use your system in a way not intended but one which it should be really well suited to. I hope you added functionality for printing on demand such as mouse click, or key press in the latest update. I know you mentioned some work-arounds, but since you are updating regularly, you should consider adding this as a default condition if you didn't already.

Attached Files:

@Cleverlie - Shader replacement is required to render the mask layers into the mask buffer. I'm grabbing depth and normals at the same time where possible as well (In the same pass, so free). Using the deferred buffers would be nice, but it would limit us to rendering only on objects that are rendered in the deferred loop (A lot of custom shaders only support forward rendering, anything created by shader forge for example). It would also require we have those buffers complete before we start rendering, as we are rendering in the deferred loop itself, we can't pull from and draw to those buffers at the same time.

As for batching, could you try disabling static batching and leaning on dynamic batching? I'm certain shader replacement in it's current form supports dynamic batching at least, static batching is unfortunately questionable. Especially as the way I'm rending masking buffers is splitting up the render queue.

Click to expand...

but if your asset needs to do a drawcall per mesh touched, then what's the difference between this and using the Unity default projectors which create a new drawcall of each object affected (besides all the other nice features your asset has)? we bought the asset just to get rid of that problem, because the asset is announced to have a deferred decals system, the logic thinking would be that it uses the deferred buffers to render the projections , and not that it increases your batches almost 8x times, I'm not using the mask layers at all, so how does that affect your system that it needs to do the replacement shader thing? I'm using static batching because my scenes are made of tons of tileable meshes made for TD-like games, these tons of meshes are reduced to a very few static with static batchinig, dynamic batching instead is a cpu intensive runtime task and doesn't lead to the same results, it creates way more draw calls because the batching gets broken when different lights affect different tiles, also because z-ordering, and what not. so dynamic batchiing is a suboptimal solution for me, unless I'm missing something.

I even tried with disabling static batching and the results are pretty much the same, without projection renderer: 404 batches, with proejction 1388.

Even in the most minimalistic scene its creating about 9x times batches.
in this scene i just dropped a bunch of cubes, three point lights, and nothing else, no static batching or funny stuff, just an empty scene with cubes.

the results: with projection renderer the batch count goes to 132 (almost 9 times the original 15 batch count) , interesting thing, if I disable all the point lights and keep the directional light only, the batch count goes from 9 to 12, so effectively the point lights are forcing your asset to rebatch stuff, I cannot afford having no point lights in my scene, that was the whole reason of going for deferred rendering instead of forward.

any suggestions? is this a bug? it can't be the normal behaviour having 9x times batches in the most simplistic scenario or is it?

Hello! I'm looking into this asset for a particular use case. I want to use it for road decals in a map editor system. They must apply to game objects with mesh colliders that do not have a mesh filter or a mesh renderer. I feel like this would not be possible with this asset, due to the decals being screen space.

I even tried with disabling static batching and the results are pretty much the same, without projection renderer: 404 batches, with proejction 1388.

Even in the most minimalistic scene its creating about 9x times batches.
in this scene i just dropped a bunch of cubes, three point lights, and nothing else, no static batching or funny stuff, just an empty scene with cubes.View attachment 247179

the results: with projection renderer the batch count goes to 132 (almost 9 times the original 15 batch count) , interesting thing, if I disable all the point lights and keep the directional light only, the batch count goes from 9 to 12, so effectively the point lights are forcing your asset to rebatch stuff, I cannot afford having no point lights in my scene, that was the whole reason of going for deferred rendering instead of forward.

any suggestions? is this a bug? it can't be the normal behaviour having 9x times batches in the most simplistic scenario or is it?

Click to expand...

That looks like a problem that could affect me as well.

@Llockham-Industries: Is there maybe a way to use the stencil buffer for masking instead of rendering objects again? Since limiting decals to terrain would cover like 90% of my decal needs, and I'll use custom shaders for that anyway, I'm thinking maybe I could just add a stencil write to my shader and a stencil read to your shader and get layer-independent masking "for free" from that? I know the stencil buffer had some problems in deferred, and I'm not sure if they got solved.

@E-Cone - Nice work! I have a better fix for the assert order bug in the next patch if your interested. Fixes the cause of the issue, saves a null check. Nice sprite picker extension .

@Cleverlie - The asset doesn't draw per object touched, it creates a buffer of everything once. So you can have 10,000 projections and you only incur the shader replacement once, and have the projections be instanced. While 10,000 of Unity's projectors would kill any machine, as they can't be batched and draw copies of everything hit.

Dynamic batching with point lights should work in Deferred, it definitely won't be as effective in forward. I agree, static batching would definitely be more ideal. I'm not sure why RenderWithShader() doesn't support using the statically batched content with the replacement material. It may and I might be doing something to break it, I'll do some experiments with simpler replacement setups and get back to you if I get some positive results.

@ThomAThomson - You are correct, you need visible meshes to project upon. You could theoretically create a custom shader that writes to depth and accepts replacement, whilst clipping every pixel? And then have these invisible meshes support you roads? But honestly roads are static, they don't need to move and are pretty simple to construct procedural. If your using an asset for roads alone, I would either generate procedurally or a mesh based decal solution .

@bigmonkgames - It might be possible, but what is your use-case? What are you trying to achieve with invisible projections?

@Martin_H - If your in forward, you will still need high-precision depth and normals (The combined 16bit depth 8 bit normals Unity provides from in-built shader replacement is not precise enough) so your doing the custom replacement pass regardless.

If your one of the few people in deferred that know they're only going to render deferred objects, and don't require any masking whatsoever I could give you a copy of 1.6, which did run off the deferred buffers. Though deferred uses the stencil buffer so you would need another solution to masking. You'll be limited by the number of projections though. Re-constructing command buffers and manually culling your projections each frame gets quite expensive, I wouldn't go above 500. Send me an email if your interested.

Thanks for well made asset, it works out of the box with little time and efforts to implement.

Still not clear for us, how can we display decals on meshes of only certain layers? Like in culling mask in lights.
Currently we're getting this when we select unit: http://prntscr.com/gmns0y
...while the spot-light should be only on the ground.

@AbyssWanderer - Hey, You can setup the masking options in settings (Window>Decals>Settings). If you only want your projection to project onto the ground, set Layer1 to the ground. Then in your Projection Renderer set the masking options to "OnlyRenderOn" and Layer1 .

@AbyssWanderer - Hey, You can setup the masking options in settings (Window>Decals>Settings). If you only want your projection to project onto the ground, set Layer1 to the ground. Then in your Projection Renderer set the masking options to "OnlyRenderOn" and Layer1 .

@Cleverlie - The asset doesn't draw per object touched, it creates a buffer of everything once. So you can have 10,000 projections and you only incur the shader replacement once, and have the projections be instanced. While 10,000 of Unity's projectors would kill any machine, as they can't be batched and draw copies of everything hit.

Dynamic batching with point lights should work in Deferred, it definitely won't be as effective in forward. I agree, static batching would definitely be more ideal. I'm not sure why RenderWithShader() doesn't support using the statically batched content with the replacement material. It may and I might be doing something to break it, I'll do some experiments with simpler replacement setups and get back to you if I get some positive results.

@ThomAThomson - You are correct, you need visible meshes to project upon. You could theoretically create a custom shader that writes to depth and accepts replacement, whilst clipping every pixel? And then have these invisible meshes support you roads? But honestly roads are static, they don't need to move and are pretty simple to construct procedural. If your using an asset for roads alone, I would either generate procedurally or a mesh based decal solution .

@bigmonkgames - It might be possible, but what is your use-case? What are you trying to achieve with invisible projections?

@Martin_H - If your in forward, you will still need high-precision depth and normals (The combined 16bit depth 8 bit normals Unity provides from in-built shader replacement is not precise enough) so your doing the custom replacement pass regardless.

If your one of the few people in deferred that know they're only going to render deferred objects, and don't require any masking whatsoever I could give you a copy of 1.6, which did run off the deferred buffers. Though deferred uses the stencil buffer so you would need another solution to masking. You'll be limited by the number of projections though. Re-constructing command buffers and manually culling your projections each frame gets quite expensive, I wouldn't go above 500. Send me an email if your interested.

Click to expand...

Hi, thanks for the reply, I confirm that you are right, the extra thousand batches are done only once, and not for every projection you have in place (I placed dozens of the same projector and each creates only one extra drawcall above the already made drawcalls for the replacement shader thing), so there is a trade off in your asset since if you plan to have enough decals going on at the same, enough for the number of extra batches created by the replacement shader to be lower, then the asset is the best solution, but for my use case I initially need only one projector for a tower range visualization (in a tower defense game), I need a big sphere projector to show the range of the tower, and your asset with the omni directional projection is perfect, but I cannot afford the extra hundreds of batches only for that, will it be too hard to add a boolean in your asset to turn it to use deferred buffers with stencil buffer as a mask instead of the replacement shader technique? you would cover a lot more of use cases adding that option, besides this problem the asset seams to be great, and I would love to use it instead of a custom solution if you can workaround this. cheers

@Cleverlie - The technique required to use the deferred buffers is completely different (You essentially copy them in a command buffer, so you can read from the copies and write to the actual buffers). But I can give you a copy of 1.6 which uses this technique. Your one of the few use cases in which it might actually be beneficial to use the old system. Send me an email (Support@LlockhamIndustries.com) and I'll send you a copy .

Masking via stencil buffers won't work in Deferred but it has another solution to masking that involves declaring individual objects to be masked. It's a lot slower, but if your not doing much masking (Judging from your original image) and not making extensive use of the system, it should be faster.

If your one of the few people in deferred that know they're only going to render deferred objects, and don't require any masking whatsoever I could give you a copy of 1.6, which did run off the deferred buffers. Though deferred uses the stencil buffer so you would need another solution to masking. You'll be limited by the number of projections though. Re-constructing command buffers and manually culling your projections each frame gets quite expensive, I wouldn't go above 500. Send me an email if your interested.

Masking via stencil buffers won't work in Deferred but it has another solution to masking that involves declaring individual objects to be masked. It's a lot slower, but if your not doing much masking (Judging from your original image) and not making extensive use of the system, it should be faster.

Click to expand...

Thanks for the offer but in that case I should probably use the other decal asset I already have, since that sounds like pretty much exactly the approach it is taking. The problem with rendering the masking objects separately is that my terrain might very well end up being 4+ million polygons.

I use some forward shaders, but I think those are all particles and similar stuff. When it comes to "hard objects" like terrain, structures and vehicles, I think all is deferred indeed.

Oh well, for the time being I'll just keep working on the 4th version of my custom terrain shader that handles damage effects at shader-level by reading a rendertexture onto which I paint damaged areas using particle systems. It's just that decals offer a kind of detail I just can't get with this approach. I'll wait and see and maybe one day one of the available solutions will fit my usecase better.

Would there maybe be a way to draw draw things in stages -> terrain -> decals -> other deferred objects -> forward objects? I think it was recommended to me in another thread to do that with multiple cams, but that didn't work because there still was a bug in Unity preventing it. Not sure if it is still present in 5.6. Maybe I should try again, although I'm sure that will cause me some other kind of headache...

Okay 2.02 has been submitted to the store. It will fix the infamous AssertOrder() bug as well as a tonne of others. VR with and without Single Pass rendering will now work in Deferred as well as forward, and the technique has been unified across 5.6 and 2017.1. Android should build and render correctly and any MacOSX editor issues should be solved now. There are still a tonne of optimizations and features I want to add but priority will always be on a stable release, appreciate your patience everyone.

Click to expand...

Hey,

First thanks for this asset. Do you know when this version will be available on the assetstore ? i'm still seing the 2.01.

I'm waiting for spsr correction as i'm experiencing rendering problems with the 2.01

@Unityraptor81 - It's in the asset store queue, how long it takes depends on how busy the asset-store team is at the moment. Send me an email (Support@LlockhamIndustries.com) I'll send you a build immediately . This goes for anyone else waiting for an update.

@RPGia - If your rendering many, definitely. If you only need 1 or 2, Unity's projectors should suit you well enough .

@Martin_H - That's a really good idea! Render your terrain and all your projections with 1 camera at Camnera Depth 0, then everything else at Camera Depth 1 with a projection blocker attached. The system respects culling masks, so you would only need to draw depth and normals for your terrain in forward. If your using deferred I can send you a copy of 1.6 so you can pull off the deferred buffers, though if your planning on having a lot of projections, I would still recommend stomaching the cost of drawing your terrain once with the new system, and get the benefits of not manually filling command buffers/culling projections (Pretty significant performance increase).

@sacmanis - Nice find! fixed the cast length bug . As for the intent, you are correct, the positioner should rotate the normals to be opposite of the collision normal (ie. facing directly into the surface hit). eg. -

If your not getting this behavior, and the objects are very close, is it possible the positioner is hitting the object it's attached too? thus having it face backwards? You certainly wouldn't be the first.

It's not the Normal that is the issue. It needs that part. The problem is that it rotates with the ray. In other words, from a distance, it appears that the decal is aligned to the surface it is colliding with in the z rotation. As you approach the collided surface, as long as you are still looking straight ahead, the rotation still appears fine. However, as you look away from straight, the decal rotates. It is less obvious at a distance but even at a distance it will be obvious if you have a large enough surface. The top is the intended rotation. As you can hopefully see in the bottom image, the decal rotates relative to the ray. While I can see that this would make since for some applications, in my case I am trying to actively apply the decal in a specific location and rotation.

I even tried with disabling static batching and the results are pretty much the same, without projection renderer: 404 batches, with proejction 1388.

Even in the most minimalistic scene its creating about 9x times batches.
in this scene i just dropped a bunch of cubes, three point lights, and nothing else, no static batching or funny stuff, just an empty scene with cubes.View attachment 247179

the results: with projection renderer the batch count goes to 132 (almost 9 times the original 15 batch count) , interesting thing, if I disable all the point lights and keep the directional light only, the batch count goes from 9 to 12, so effectively the point lights are forcing your asset to rebatch stuff, I cannot afford having no point lights in my scene, that was the whole reason of going for deferred rendering instead of forward.

any suggestions? is this a bug? it can't be the normal behaviour having 9x times batches in the most simplistic scenario or is it?

Click to expand...

You've got 4 lights touching things, the chances of you having anything batched at all is pretty minimal. You should look at the Frame Debugger - as of 5.6 this now actually shows you why a static batch stop. I suspect you're going to see a lot of 'touched by a different number of lights'

@djarcas - Ah, I think your spot on. The thing is, shader replacement doesn't require any lighting, so it shouldn't theoretically make a difference, It'd be damn swell if Unity had an unlit render path, it makes no sense to use Deferred, just to ignore forward lights breaking batching. I might try testing disabling all lights before rendering the replacement pass, then re-enabling after, see how expensive it is. Theoretically, this should allow them to batch together. If it's not too expensive I'll add an option. Thanks for posting, nice find!

@sacmanis - On the same page now. The issue is that if you had the reference up (defines the rotation) set to say Vector3.up, and your positioner hit a roof, it would then not know which way to rotate. So the upward direction needs to be relative to the direction. The component is designed to be used with moving parts, ie. selection circles or shadows under a character. In your use case seems more appropriate to just place a projection and parent it to your wall, there's no need to have the overhead of constantly re-positioning it. You seem a pretty capable programmer, could roll your own custom solution to do that pretty easily or inherit from the in-built printer class. Projection renderers can be instantiated and moved like any other gameObject, so it's just instantiating and positioning a prefab like any other .

I know at least at high level how batching works, dynamic batching works good when there is not so many different lights going on because these usually break batches, also z-ordering and a couple more events. what is a shame is that this asset forces to generate this replacement shader thing, which at least duplicates the batch count, no matter what scene you have, no matter how many lights, static or dynamic batching or whatsoever, it doesn't even have frustrum culling or distance culling at all for what I've seen, it forces to generate lots of batches in scene to do the layer masking thing. I'm not an expert senior shader programmer but for what I understand, you need to create your "own depth map" instead of using the deferred depth G-buffer because that's the only way you find out to mask diffferent decals to different layers, but doing that you force this extra hundreds or thousands batches (depending on scene complexity), no matter if I use one or 20000 decals in my scene, the batches are there and they are not culled to create only the needed ones since I tried moving the decal object around the scene and the batch count doesn't change, so I assume its regenerating the entire scene. Decalicius has the same problem, I think he called this step the "limitTo pass", and he somewhat did a frustrum culling to at least reduce the batches to only what is under the camera view, next step would be to reduce the batches to only the meshes affected by decals, and a further step would be to have compatibility with static batching.

now, maybe I'm not that expert, maybe I don't understand the intrinsics and complications of each technique or algorithm, I'm still learning about shaders, command buffers, and what not, but that's why my studio bought this asset, to not have to think about the low level, to have an already production ready solution at hand, but if I know the asset forces your scene to generate thousands of batches for only one decal I would not even tried to buy it, there is no single documentation or word about it, about it not working with static batching, or the shader replacement thingy, the only accesible documentation is an code API and a quickstart guide of 3 pages, I was hoping the asset will work good with my project because I use deferred rendering and it is advertised as a deferred decal solution, that to me sounds like 1 decal = ~1 batch, not 1 decal = 9x times batches, would have been great if the developer at least had the intention to put a workaround or solution to static batching into the roadmap instead of offering me an old version of the asset plus I need to do wizardry I dont understand to workaround the masking without stencil buffers.

now correct me if I'm wrong, but in that simple scenario with cubes I made, the decal only affects about 9x12 cubes, considering the initial 15 batches (with dynamic batching), plus having to re render the cubes with replacement shader, that would be 123, but there shows 132 batches, so my understanding is that the asset is not taking advantage of either static or dynamic batching, or a good culling optimization to save batches in the replacement shader pass, I wasn't expected that behaviour because the demo videos look great, but how well this perform in real production games with lots of different objects that doesn't batch at all because different materials for example?

I know at least at high level how batching works, dynamic batching works good when there is not so many different lights going on because these usually break batches, also z-ordering and a couple more events. what is a shame is that this asset forces to generate this replacement shader thing, which at least duplicates the batch count, no matter what scene you have, no matter how many lights, static or dynamic batching or whatsoever, it doesn't even have frustrum culling or distance culling at all for what I've seen, it forces to generate lots of batches in scene to do the layer masking thing. I'm not an expert senior shader programmer but for what I understand, you need to create your "own depth map" instead of using the deferred depth G-buffer because that's the only way you find out to mask diffferent decals to different layers, but doing that you force this extra hundreds or thousands batches (depending on scene complexity), no matter if I use one or 20000 decals in my scene, the batches are there and they are not culled to create only the needed ones since I tried moving the decal object around the scene and the batch count doesn't change, so I assume its regenerating the entire scene. Decalicius has the same problem, I think he called this step the "limitTo pass", and he somewhat did a frustrum culling to at least reduce the batches to only what is under the camera view, next step would be to reduce the batches to only the meshes affected by decals, and a further step would be to have compatibility with static batching.

now, maybe I'm not that expert, maybe I don't understand the intrinsics and complications of each technique or algorithm, I'm still learning about shaders, command buffers, and what not, but that's why my studio bought this asset, to not have to think about the low level, to have an already production ready solution at hand, but if I know the asset forces your scene to generate thousands of batches for only one decal I would not even tried to buy it, there is no single documentation or word about it, about it not working with static batching, or the shader replacement thingy, the only accesible documentation is an code API and a quickstart guide of 3 pages, I was hoping the asset will work good with my project because I use deferred rendering and it is advertised as a deferred decal solution, that to me sounds like 1 decal = ~1 batch, not 1 decal = 9x times batches, would have been great if the developer at least had the intention to put a workaround or solution to static batching into the roadmap instead of offering me an old version of the asset plus I need to do wizardry I dont understand to workaround the masking without stencil buffers.

now correct me if I'm wrong, but in that simple scenario with cubes I made, the decal only affects about 9x12 cubes, considering the initial 15 batches (with dynamic batching), plus having to re render the cubes with replacement shader, that would be 123, but there shows 132 batches, so my understanding is that the asset is not taking advantage of either static or dynamic batching, or a good culling optimization to save batches in the replacement shader pass, I wasn't expected that behaviour because the demo videos look great, but how well this perform in real production games with lots of different objects that doesn't batch at all because different materials for example?

Click to expand...

You're basing WAY too much on that stupid-ass 'batching' number in the corner. You *really* need to use the Frame Debugger in order to make any clear statements at all. It's about as useful and reliable as the frametime counter under the Stats dialogue.

Followed your suggestion and just wrote my own solution and it is working exactly how it I needed it to work.

This was made with 3 quickly thrown together projections. I am considering using a GUI to allow for setting up complex decals that could be saved as a single projection but made up of several. This is three wall sections that snap together.

Now I am going to have to reload the asset to undo all the changes and learn how it is supposed to work for other purposes.

You're basing WAY too much on that stupid-ass 'batching' number in the corner. You *really* need to use the Frame Debugger in order to make any clear statements at all. It's about as useful and reliable as the frametime counter under the Stats dialogue.

Click to expand...

I'm using the frame debugger since I stated the first post in this thread, this are the results of multiple tests I did:

in a scene with 100 cubes the step that renders stuff with the shader Projection/Internal/DepthNormalMask does an effective dynamic batching, and in a single batch renders all the cubes.

the moment I add a single point light to the scene this happens:

the RenderForward.RenderLoopJob event which shows the batches of the DepthNormalMask shader takes 57 batches to render the depths needed for dynamic decals, this means even when the shader is a depth mask, the dynamic batching somehow is broken by a single point light, I don't understand why any lights would break the dynamic batching since this shader doesn't use lighting information (or at least that I can tell by looking at the frame debugger).

even more, the deferred render pass for opaque geometry still renders perfectly and batches all the cubes in a single dynamic batch, the same goes for the shadowmaps pass, they both render in a single batch, so the only thing that has got the dynamic batching broken from adding the new point light was the DepthNormalMask pass, even when it doesn't take lighting into calculations. this is either a bug from unity or a limitation that has no workaround yet, a bug from the asset, or a bad design choice, why adding a light to the scene would break the dynamic batching on the depthmasking shader pass?

here are some pictures to show what I encountered while testing

is this experiment good enough to assume I'm experiencing a bug in my editor or in my version of the asset (2.0.1)? or this is the expected behaviour?

You're basing WAY too much on that stupid-ass 'batching' number in the corner. You *really* need to use the Frame Debugger in order to make any clear statements at all. It's about as useful and reliable as the frametime counter under the Stats dialogue.

@Martin_H - That's a really good idea! Render your terrain and all your projections with 1 camera at Camnera Depth 0, then everything else at Camera Depth 1 with a projection blocker attached. The system respects culling masks, so you would only need to draw depth and normals for your terrain in forward. If your using deferred I can send you a copy of 1.6 so you can pull off the deferred buffers, though if your planning on having a lot of projections, I would still recommend stomaching the cost of drawing your terrain once with the new system, and get the benefits of not manually filling command buffers/culling projections (Pretty significant performance increase).

Click to expand...

What is a "projection blocker" and why would it be needed in that case?

I appreciate the offer of sending me a 1.6 copy, but I'm all but certain it's just a matter of time till Unity breaks it with a future update, and I'd feel bad bothering you for bugfixes on an approach you've dropped months or years ago. I'm sure you're not looking to double your maintenance effort for zero benefit to you, because I sure as hell wouldn't want to in your position .

@Cleverlie - I don't believe this is a bug, this is the correct behavior. Unity doesn't have an unlit rendering path, the closest is forward. So unfortunately it automatically assumes all shaders rendered are to be lit, so all batching performed assumes the objects being rendered will be lit, even if the shaders don't require lighting. It does at least check to see if shadows are required, which thankfully saves a bunch of draw calls.

I've just tried adding a function to disable all of the lights before rendering the shader replacement, and then re-enable them afterwards, but this doesn't seem to affect the static batching. I believe (Though I can really only speculate) Unity creates batched meshes in respect to the current lighting setup only. As your in deferred, it batches everything for deferred lighting, ie. everything together, possibly as well variants for different culling scenarios (Not sure how it divides it up for culling).

At the end of the day your your draw/set pass calls should be judged in respect to how much of an impact they have on your Main thread/ Render thread and GPU frame times. Gpu's will chew through them so it shouldn't be too much of an issue their. The calls themselves, if I understand correctly, should be issued from the render thread, so if the render thread is your bottleneck, then you definitely have to start worrying about them.

In the last patch you can disable the entire system, or just the shader replacement via the Decal Settings menu (During play-mode a debug menu will appear). You can use this to check how much of an impact the system is having on each of these times. ie. compare frame times with/without the system enabled.

At the end of the day, if your not happy with the system, you are entitled to a refund. If you do decide you want one, send me an email at Support@LlockhamIndustries.com with your invoice number.

okay, so yeah the problem was what I expected, you can't control how unity interprets what you want to render, so it assumes it receives lighting and breaks the batching, maybe if you do a combination of disabling all lights before render as you did, and a cull system so it doesn't render everything (example, in the 100 cube scene the last rows of cubes are not touched by the omni decal) the results could be improved, maybe you have a solution in the roadmap with the scriptable render loop? I will dowload the version you said that has debug buttons to check if the system actually consumes too much miliseconds of compute time, in my case my scenes get 1600 extra batches so probably this will hit the performance, I know that batches are not a linear unit of measurement for performance, it depends on how much the internal state is changed etc, so maybe hundreds of batches doesn't represent a high dropdown in fps, have to test more to really tell, thanks for the clarifications.

@sbmhome - If your updating from pre 2.0 I would definitely recommend a clean install (Delete old then install new). Also back up before upgrading, a lot of 2.0 is unfortunately not backwards compatible.

Attached Files:

When I´m using the Decal system, i get Camera.FireOnPreRender call in the profiler that takes about 3-5ms ( pretty much doubles my Camera.Render time), disabling the Decal System removes this. Is there anyway to improve this at all? Right now I can´t use it in my project because of that.

Hello, I'm using Unlit decals to paint transparent footsteps/shadows. When they overlap with transparent water, it seems like alpha of both water and decals are added together like how they look in the above screenshot. ( the footsteps in the water look darker ). Is there any way to fix this? Great asset btw.

I just purchased this tool a few minutes ago. I'm using it for a VR game. I keep getting spammed with this error. And using even one decal on a high poly wall is causing me to go from 90fps to 75fps. Using multiple makes it far worse.

Code (CSharp):

Attempting to release RenderTexture that were not gotten as a temp buffer

@sbmhome - Ah, the shader replacement setting has been removed and is now automated. It should automatically detect the required type, per camera. Got the bug reproduced and fixed as well, nice find. Will be in the next patch .

@Filhanteraren - I'm working on optimizations now (General and corner cases). Should help reduce the shader replacement time, as well as prepping scenes for bug reports preventing rendering to multiple render textures working in different scenarios (Older Graphics Api's (obviously some shouldn't support this and I have a low-precision replacement method for these scenarios), VR etc.). In these situations shader replacement has to be split into multiple passes which is horribly inefficient. Keep your eyes peeled for an update.

@KamiKaze425 - As stated above, the system is compatible with VR, but still has a bit to be optimized, and ideally, the requisite replacement should be done in a single pass. Where possible, use as few masking layers as possible, and if you have additional cameras that don't need to render projections, add projection blockers to them.

@noanoa - The projections should be rendered before your water, so neither should influence each other. Are you using a custom shader for your water? If so any chance you could send me a copy? (Support@LlockhamIndustries.com)

- Do you support vertex color out of the box ? So you can define a custom color per decal, to prevent from breaking Unity batch

- Do you support putting decals on an edge? Like if you put a large decal on a smaller surface, what happens? Is the decal quad always fully rendered and bleeds on surface edges? Or do you nicely cut the decal quads to prevent these glitches from happening? (the screenshot highlights the behavior I don't want)

@Filhanteraren - I'm working on optimizations now (General and corner cases). Should help reduce the shader replacement time, as well as prepping scenes for bug reports preventing rendering to multiple render textures working in different scenarios (Older Graphics Api's (obviously some shouldn't support this and I have a low-precision replacement method for these scenarios), VR etc.). In these situations shader replacement has to be split into multiple passes which is horribly inefficient. Keep your eyes peeled for an update.

Sounds good, it still seems to expensive for "just" a decal system. 3-4ms is a lot, i guess if you plan to use many decal that cost could work, but for just using it for bullet holes and some blood stuff it´s not really possible.

Oops...

"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.