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

Overlay material over a specific material in the scene

Discussion in 'Shaders' started by imagedrealityjake, Sep 21, 2018.

  1. imagedrealityjake

    imagedrealityjake

    Joined:
    May 8, 2018
    Posts:
    17
    Hi,

    Calling stencil shader pros! I want to get a specific material (my paint) to draw over another specific material (my terrain). I don't want to use ZTest Always because I don't want the paint to render over anything else in the scene, just my terrain. I also want to stay away from multiple cameras.

    I have tried to achieve this with Stencil shaders but I'm really not having any luck. From my understanding, the paint geometry would need to act as a mask for the terrain and hide the bits of terrain the paint appears on. But if the paint is the mask wouldn't it itself not render?



    As you can see above, I need the white paint to always render over the terrain, but only the terrain. I'm sure this must be doable via the shader.

    Thanks for any help!
     
  2. brownboot67

    brownboot67

    Joined:
    Jan 5, 2013
    Posts:
    375
    Just sample your paint texture and overlay it inside your terrain shader. You don't need to stencil.
     
  3. imagedrealityjake

    imagedrealityjake

    Joined:
    May 8, 2018
    Posts:
    17
    Hey thanks for the help @brownboot67. I'm not sure what that is or how to go about implementing that. Do you have any resources or examples of this?

    Could some version of stenciling also do the trick?

    Thanks!
     
  4. imagedrealityjake

    imagedrealityjake

    Joined:
    May 8, 2018
    Posts:
    17
    Could anyone provide some help on this? Its been an issue we've had for quite some time now.
     
  5. MSplitz-PsychoK

    MSplitz-PsychoK

    Joined:
    May 16, 2015
    Posts:
    1,278
    Only if you set the paint to blend mode "Blend Zero One" so it's fully transparent.

    Depending on what else you've got going on in your project, I would do the reverse. Have your terrain write a stencil value first, then have objects that should render over your paint (trees, people, etc.) overwrite the terrain stencil value. Lastly, draw your line with no ZTest, but only where the terrain values were stenciled.


    This method will only work if you have a texture for the paint and you want to "paint" that texture on the terrain by rendering that texture on top of others within the terrain shader. Based on your screenshot, I would guess that you are not painting using a texture, which would mean this method will not work for you.
     
  6. imagedrealityjake

    imagedrealityjake

    Joined:
    May 8, 2018
    Posts:
    17
    @Gambit-MSplitz Thank you for your help with this, it is something I've tried multiple times to get running without any luck. I'm going to have another crack at it with your pointers.

    You are correct, we paint by generating quads between hitpoints.
     
  7. imagedrealityjake

    imagedrealityjake

    Joined:
    May 8, 2018
    Posts:
    17
    @Gambit-MSplitz that was it, thank you so much. That has plagued us for a while now and now working flawlessly. Thank you!
     
    MSplitz-PsychoK likes this.
  8. MSplitz-PsychoK

    MSplitz-PsychoK

    Joined:
    May 16, 2015
    Posts:
    1,278
    Glad to hear =) stenciling is always tricky, but can have some pretty amazing results.
     
  9. imagedrealityjake

    imagedrealityjake

    Joined:
    May 8, 2018
    Posts:
    17
    We've run into an edge case with this approach:



    We can see our paint through the terrain which makes total sense. Not sure if there could be any way around this with our stencil approach. Gah!
     
    Last edited: Oct 11, 2018
  10. MSplitz-PsychoK

    MSplitz-PsychoK

    Joined:
    May 16, 2015
    Posts:
    1,278
    Maybe instead of stencil, your could try depth testing again, but with an offset so that the terrain has to be a certain distance from the line to render above it. Check out the "Offset" section of this page: https://docs.unity3d.com/Manual/SL-CullAndDepth.html

    Good luck!
     
  11. imagedrealityjake

    imagedrealityjake

    Joined:
    May 8, 2018
    Posts:
    17
    @Gambit-MSplitz this was actually our original implementation but we had issues with other drawing tools requiring a mega offset. However, we should be able to continue to use stencils for these tools and an offset for paint, I can see that working. Thanks for the help once again!
     
  12. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    So stencils, depth settings, offsets etc. None of these will really solve the problem. Together they can be used to get something kind of working, but there will always be something a little off when trying to solve the problem this way.

    ZWrite Always can be used to prevent the line from intersecting or being occluded by another object. But now it it draws over everything that's been drawn before it. You saw this already.

    Stencils can be used to ensure the line only renders where something else has already rendered. Together with ZWrite Always you can make sure something always renders over a particular object, but not other objects. But if there are situations where the particle object should sometimes occlude the thing you're rendering, there's no solution to this when using ZWrite Always.

    Offsetting the line geometry instead of using ZWrite Always can prevent it from intersecting with the terrain by putting some space between the terrain and the line, while still allowing it to be occluded. It may even remove the need for using a stencil. However the line will be obviously floating above the geometry, and at some angles you'll be able to see the line in places the terrain is not. Stencils can help from preventing it from showing the line over the sky, but it won't prevent the base problem of the line not being on the terrain. Also the amount you need to offset by may not be consistent and may still intersect unless you use a very large offset making the problem worse.


    So the solution is to not do any of this. There are two much better, but more complicated solutions.

    Option 1: Decals.
    Render the lines as boxes that intersect with the geometry and project against the screen space camera depth texture. You can even still use stencils if need be to prevent it from rendering on things not the terrain. There are a couple of real time decal assets on the store, or you can look at the Deferred Decals example here:
    https://blogs.unity3d.com/2015/02/06/extending-unity-5-rendering-pipeline-command-buffers/

    Option 2: Render texture.
    Render the lines into a render texture from a top down view. This doesn't need another camera, and in fact using an extra camera would be slower, though it could be easier. Then render the terrain again with a material that just renders with that texture. This ensures the lines only appear on the terrain, and exactly on the terrain. See the various real time painting examples out there.
     
  13. imagedrealityjake

    imagedrealityjake

    Joined:
    May 8, 2018
    Posts:
    17
    @bgolus Thank you for taking the time to think about our problem and to explain in such detail. We have pretty much encountered every issue you identified and I'm in agreement that with our current implementation will never be perfect.

    Out of the 2 options you suggest, it looks to me like Option 1: Decals would be the way to go. With Option 2, wouldn't there be an issue with the top down render texture when painting onto surfaces that aren't visible from this view point?
     
  14. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    If your terrain is a model with overhangs, yes, option 2 would have problems. The line would simply render across the entire vertical projection. So if you draw a line in a cave, it would also appear on the ground above. The more advanced version of option 2 is to implement on-model painting in UV space. This gets complicated quickly, and usually ends up effectively being the same as decals, just cached to a texture.

    I would definitely say decals are your best bet, but they’ll still have problems with overhangs or significant angles. Generally decals are box projections of some kind, and that’ll have problems with cliff edges and the like. You also have to be careful with how “thick” the projection is as too thin and it might miss some terrain. Too thick and you’ll start projecting through things. You can also try using other tricks like non-orthogonal projections, or line or plane distance calculations.

    Really, projectors don’t solve the base problem of the geometry you’re drawing for the lines aren’t as tessellated as the mesh you’re drawing on. It just gives you some extra wiggle room to be sloppy in.