Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

How to create a shader in Shader Graph that masks out the intersection of other objects?

Discussion in 'Shaders' started by josh-horsley, Mar 4, 2019.

  1. josh-horsley

    josh-horsley

    Joined:
    Jun 20, 2013
    Posts:
    39
    I am working on masking/removing parts of a plane where it intersects with other objects. The goal is to be able to remove water from inside a submarine with a big window and the submarine is surfaced, like this:



    I'll work on the underwater part later, but right now I'm just trying to keep the water plane out of objects intersecting with it. So far, I have a Shader Graph that alpha masks objects except it seems to be doing it at any level and not during intersection. This gives the look that everything is always rendered on top of the plane, but I'm pretty sure it is masking (see shader graph below). Sorry if my terminology is off - I'm pretty new at shaders/shader speak.



    The result I'm getting now:

    Capture.PNG

    Where the spheres intersect and plane should be showing instead of bottom part of spheres:

    Capture5.PNG

    Any help with this would be greatly appreciated! Like I said, I'm really new to shaders so I'm probably missing some fundamental thing! :D
     
    Neiist, jhocking and pachermann like this.
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,396
    Unfortunately it's not really quite that easy. There are a few ways to go about this, but most of the options are not particularly LWRP Shader Graph friendly as a warning.

    I'll start off by saying the camera depth buffer texture is not useful in accomplishing this effect. So we'll skip that for now.

    The first method I'd suggest requires careful ordering of multiple passes. You draw your "boat", then draw an invisible cap on top of the boat, and then draw the water. This video shows off someone doing it using the built in forward renderer:
    Direct Youtube Link since at the time I posted this the embed was broken.


    This only really works if your camera is always above the water plane and outside of the boat. If you can get your camera in a spot that's inside the boat and underwater, this technique totally fails. So the first example image would not be possible to reproduce with this technique.

    The second option would be to use signed distance fields. This requires using either simple shapes (spheres, capsules, boxes, etc.) to create 3D volumes with that you can cut into the water plane with, or a 3D texture that holds the shape you want. Spheres are pretty easy and cheap to do, but Shader Graph doesn't make this too easy since presumably you'd want multiples of these, and Shader Graph doesn't have any support creating node graphics of dynamic loops. So this would require a custom node.

    This page describes both of the above techniques, and a few other hacks.
    https://simonschreibt.de/gat/black-flag-waterplane/
     
    josh-horsley and Invertex like this.
  3. josh-horsley

    josh-horsley

    Joined:
    Jun 20, 2013
    Posts:
    39
    Wow, thank you bgolus for pointing me in the right direction. I switched over to the HDRP and I am reading up on signed distance fields now. I think I'll probably go with the second approach since it will be in a submarine, so the player could be underwater.

    Question - If I just had one big sphere for the submarine cockpit, would I be able to get away without having to do dynamic loops?
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,396
    Sure, if you just always assume a single sphere, that's easy enough. Pass in a float4 parameter to your water shader using a script to define a world position and radius. Subtract the parameter's XYZ position from the world position, get the length, subtract the radius, and set that as your alpha with a alpha clip threshold of 0.0
     
  5. josh-horsley

    josh-horsley

    Joined:
    Jun 20, 2013
    Posts:
    39
    I don't think you could have made that any easier for me! Thank you so much for your help bgolus! I got the effect I was looking for. Posting what I have for others to use:

    sphere_through_plane.PNG sphere_through_plane_graph.PNG

    And for the _domeparams property, set the position and radius of the sphere by calling this in a script attached to the sphere:
    Code (CSharp):
    1. _waterMat.SetVector("_domeparams", new Vector4(transform.position.x, transform.position.y, transform.position.z, radius));
     
    Last edited: Mar 6, 2019
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,396
    FYI, if you're using the distance node you don't need the length node. You can just pipe the output of the distance node into the subtract.
     
    matthewjameslim likes this.
  7. josh-horsley

    josh-horsley

    Joined:
    Jun 20, 2013
    Posts:
    39
    Oh ok thank you. I took it out. Were they just doing the same thing?
     
  8. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,396
    The distance node does length(vectorA - vectorB).
    Length gets you the length of a vector, but the output of the distance node is a float. The length of a float is equivalent to the abs() of the value, and the distance node is already guaranteed to be outputting a positive value, so it's just wasted cycles. Best case it's an extra abs(), which is cheap. Worse case it's a extra square root, which is not.
     
    josh-horsley likes this.
  9. josh-horsley

    josh-horsley

    Joined:
    Jun 20, 2013
    Posts:
    39
    Alright, so now I have the surface water look that I want. I might spend some more time adding detail, but for now it's working and looking alright (I think?).



    It uses gerstner waves, which I think are the more natural look, correct? I followed this very nice tutorial here: https://80.lv/articles/tutorial-ocean-shader-with-gerstner-waves

    Now I would like to start focusing on the underwater setup. What is considered the best way to do this, knowing that the camera could show a split view of above and below the water surface from inside the glass sphere? I'm looking to achieve underwater fog (what's the proper name for this, btw?) and volumetric lighting at the very least. For the volumetric lighting, in case I'm using the wrong term, I would like the surroundings to get darker the deeper you go.

    Also, since I am so new to shaders, I feel like I would do better if I learned a bit more instead of just jumping into things like this. Is there some good resources that anyone knows of that helped you learn? Or is it better to just experiment as I go?
     
    Hattoriseed likes this.
  10. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,396
    There's a lot going on there to handle.

    First thing is dealing with the water "edge" on the glass. The easiest solution is to do nothing, but some games have used either the geometry off the glass itself, or some other proxy geometry just behind the glass, to draw the water edge on. This same plane is then also used to handle the underwater fog & volumetric effects. See this presentation on water tech in Uncharted 3, starting around page 103:
    https://www.gdcvault.com/play/1015309/Water-Technology-of

    Or this presentation for Inside, around page 106:
    https://www.gdcvault.com/play/1023002/Low-Complexity-High-Fidelity-INSIDE

    There are a number of links to beginner stuff on the forums that may help you wrap your head around the ins and outs of basic shaders. Then there's a giant empty void of confusion. And then there's various talks like those I linked above as well as others of similar ilk and ShaderToy.com.

    I don't have any good answers for getting over that hump in the middle. Usually someone coming into shaders says "I have this simple effect I'd like to do that's like this:" and then they go on to show some screenshots and describe an effect from a AAA game that likely took a couple of years of trial and error by senior graphics programmers and effects artists to produce. What you're trying to do is not too far off of that. The underwater rendering is many very complex effects all being layered together, and it should be noted that Uncharted 3 faked all of it and still produced something that looks better that many games made recently.
     
    pachermann and josh-horsley like this.
  11. josh-horsley

    josh-horsley

    Joined:
    Jun 20, 2013
    Posts:
    39
    Yeah, I figure I'll just break this down into bite size chunks as best as I can.

    Using the geometry of the glass itself sounds like the direction I want to go. I found this depth shader tutorial a couple of days ago that (I'm guessing) will help with this:



    Thank you for the gdcvault links! This looks like a really good resource for learning different techniques. As for ShaderToy, I just came across this the other day when going through a beginner shader tutorial! Very helpful and very fun!

    Hahaha! I feel like this is me...right here in this thread lol. Water in games is just so interesting to me. I know this will be hard though - last year I wanted to make a submarine game and so I bought up a few of the top water assets and only one got close to having a good volume subtracted underwater effect (Playway, now deprecated). Good thing this is a hobby haha. Anyways, thank you for all your help thus far!
     
    pachermann likes this.
  12. josh-horsley

    josh-horsley

    Joined:
    Jun 20, 2013
    Posts:
    39
    Sorry to jump around, but I'm working on rendering the water depth and I think it's almost done. My issue is that the depth seems to change when the camera is moved up and down. I tried subtracting camera position from the water vertical position, but that didn't work. The depth also seems to change when the camera direction changes.

    water_depth_1.PNG water_depth_2.PNG water_depth_3.PNG
     
  13. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,396
    So, I'm not entirely sure what that above shader is doing, but it doesn't look right to me. Here's my version:
    upload_2019-3-13_17-50-25.png

    That should keep the fog consistent on when the view is rotating in place or changing its distance from the glass, but this is calculating the distance between the polygon surface and the scene depth behind it in view space, not depth of the water in world space like you might want for having it get darker as it gets deeper, vs just distance fog. For that you have to reconstruct the world space position from the scene depth. That's a bit more tricky to do, though still possible.
     
  14. CJA_888

    CJA_888

    Joined:
    Sep 12, 2019
    Posts:
    16
    Hello, I have seen your discussion is very good, I would like to ask if you can teach me how to use the geometry behind the glass to make the water volume in detail, especially how to track the uneven waves with shader
     
  15. transporter_gate_studios

    transporter_gate_studios

    Joined:
    Oct 17, 2016
    Posts:
    219
    How would you invert this? im trying to use this to fade alpha out as the tiled texture on a giant plane gets farther away. Right now its fades away everything close to the camera and i figured removing the one minus at the end of your chain would do it but.. nope.
     
  16. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,396
    I would have expected that to have worked too…
     
  17. transporter_gate_studios

    transporter_gate_studios

    Joined:
    Oct 17, 2016
    Posts:
    219
    Hmm, yeah i guess I don't understand the math happening here. Be nice if there was way to see the numbers outputting so you can troubleshoot easier.
     
  18. adamgffrd

    adamgffrd

    Joined:
    Sep 26, 2018
    Posts:
    35
    @josh-horsley

    Hi Josh,

    I am trying to replicate this effect in my own project. I tried in HRDP and URP but I can't seem to get it working. I was wondering if you have since updated this to HDRP and maybe there is some checkbox I am missing. I have a thread open here, any insight would be appreciated.

    Code (CSharp):
    1.      using UnityEngine;
    2.     [ExecuteInEditMode]
    3.    
    4.     public class CullMe : MonoBehaviour
    5.     {
    6.          public Transform culler;
    7.          public float radius = 1;
    8.          void Update()
    9.          {
    10.              if (!culler)
    11.                  return;
    12.              var renderer = GetComponent<Renderer>();
    13.              if (!renderer)
    14.                  return;
    15.              var material = renderer.sharedMaterial;
    16.              material.SetVector("_CullerParams", new Vector4 (culler.transform.position.x, culler.transform.position.y, culler.transform.position.z, radius));
    17.          
    18.          }
    19.     }
    20.  

    https://forum.unity.com/threads/cull-pixels-inside-overlapping-primitive.1248265/
     

    Attached Files:

    Last edited: Mar 4, 2022