Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Dissolve Shader (without writing a dedicated Dissolve Shader)

Discussion in 'Shaders' started by edwar496, May 7, 2020.

  1. edwar496

    edwar496

    Joined:
    Jun 28, 2016
    Posts:
    18
    Hey all. I'm trying to brainstorm something, but I really don't know how I would begin to program something like this and would love some insight as to what engine features are available to make something like this work.

    I'm trying to write a "dissolve shader system", but actually much more complex than just writing a dissolve shader. I want a dissolve shader that works additively with all the other shaders in my project, so if I have a "Tree" shader I don't have to write a "Tree - Dissolve", or a "Cloth" and a "Cloth - Dissolve". Just one dissolve effect and one dissolve shader, but it can be applied to any existing shader at runtime rather than having to code shader variants that implement it.

    From a high-level, here's what I'm thinking: The dissolve shader would only draw the glow on the actual dissolve threshhold - it would return something like (0,0,0,0) everywhere else, and it would clip the pixels that have been dissolved. I think I could render this in addition to the actual material for the object, but the problem is that the dissolve would not actually clip the underlying pixel on the standard material - it would have no knowledge of the shader.

    So, in essence - is there a way to apply a dissolve effect to multiple different types of shaders without having to hard-code a dissolve variant into each of those shaders?
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Not possible.

    There’s no way to un-render an object that’s already been rendered by rendering something else afterward. When an object is rendered it replaces the color values in the frame buffer with the output of the shader it’s rendered with, and the GPU does not keep a record of the previous color values, or even what object rendered which pixel. You can only render something else over previously rendered pixels.

    There’s no way to selectively prevent something from rendering by rendering something before it, unless the later thing is rendered with a custom shader. The popular ways to punch a hole into something would be to use an invisible depth writing pass or stencils. The depth write option would abuse the depth buffer by rendering something closer to the camera, which would cause any objects rendered afterward to skip being rendered, but it affects all objects render afterward. You could render you object after everything else, but this means where it does render it’ll render on top everything that’s already been rendered hiding any transparent effects. You could have a shader render invisible, but render the object’s depth normally, and have a later “regular” pass only render if its depth is exactly the same, but that requires the regular pass uses a custom shader. Stencils are another popular approach, where you render something to produce a screen space mask that later objects are either excluded by or will only render when over, but this again requires the object’s regular pass uses a custom shader.

    There is a case you could effectively un-render something by having a shader that runs before and after an object, but there’s a gross performance / visual implications if you need more than one of these. Basically you’d get a copy of the screen contents from before the object was rendered, render your object, and then render the old contents before hand. This is expensive, and means any complex object can’t dissolve to reveal other parts of itself, only the scene as it was before it was rendered. Supporting multiple objects doing this separately would ... drum roll ... require the object to use a custom shader. You can see where I’m going with this.

    You’re going to need to write a custom shader for all of your objects that you want to dissolve.
     
  3. edwar496

    edwar496

    Joined:
    Jun 28, 2016
    Posts:
    18
    That’s unfortunate to hear. Does the situation change if you start poking around with Scriprable Render pipelines? Something like rendering the geo to a separate buffer so it can be drawn to the main scene after the dissolve is performed?
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Nope. This isn’t a built in vs scriptable render pipeline thing. This is a how GPUs work thing. Actually basically all of the weird alternatives I listed above disappear with SRPs since they don’t support a bunch of features the built-in pipeline has available... “use custom shader with the dissolve built in” becomes the only option there, for both URP and HDRP.
     
    acnestis likes this.