Search Unity

Question How to use the Refract node

Discussion in 'Shader Graph' started by jRocket, Feb 21, 2023.

  1. jRocket

    jRocket

    Joined:
    Jul 12, 2012
    Posts:
    700
    Unity 2022.2 introduced the refract node in shader graph.

    upload_2023-2-20_19-33-50.png

    Previously, one would have to use a custom function and do the math inside there to generate a refraction effect. However, I couldn't figure out how it works. The custom function version used the refract function, which took in a view direction, normal, strength or IOR, and then was used to modify the scenecolor uv's. I tried doing the same setup, but it didn't work.

    From the documentation it sounds like Incident is the View Direction(maybe), and Normal is the surface normal, but what do I do with the output Refracted and what is Intensity used for? I'm using URP and just want to make a simple transparent refraction material on a sphere.
     
  2. wwWwwwW1

    wwWwwwW1

    Joined:
    Oct 31, 2021
    Posts:
    769
    Hi, what kind of simple refraction do you mean?

    Rays are refracted twice in a sphere, so you should use this node twice for sphere refraction.
    SphereRefraction.jpg

    Yes, I'd like to have twice refraction.
    How to get the normalWS for second refraction?

    You can check RefractionModelSphere(), a SRP's built-in function in Core RP.
    Add a shader property named thickness as the diameter of the sphere. (unit is meter by default)

    Then calculate the center of it.
    SphereCenter.jpg

    dist: The distance that the ray travels inside the sphere.
    P1 : Position of the ray's exit point.
    ExitPoint.jpg

    Use center and exit point to calculate the exit normalWS (world space direction).
    NormalForExitRefraction.jpg

    Then you can use the "OutDir2 WS" to do some scene objects intersection tests.
    • Do ray marching using scene depth.
    • Intersect with reflection probe's projection box. (HDRP does this)

    Refract once is enough.
    I suppose what you'd like to know is how to sample the scene color with the node output.

    You can pretend that the output direction is a position, and convert the "position" to screen space.

    Or you can check the first spoiler block, and pretend that the exit point is the intersection (position).

    Shader graph custom function:
    Code (CSharp):
    1. // This is actually screen space position (0-1)
    2. ScreenPosition = ComputeNormalizedDeviceCoordinates(PositionWS, GetWorldToHClipMatrix());
    WorldPositionToScreen.jpg

    If you don't want to do it yourself, you can check this repo.
     
    florianBrn likes this.
  3. wwWwwwW1

    wwWwwwW1

    Joined:
    Oct 31, 2021
    Posts:
    769
    The "Intensity" output is a factor (0-1) that tells you how strong the refraction is.

    You can use it to mix reflection and refraction.
     
  4. Arnold_2013

    Arnold_2013

    Joined:
    Nov 24, 2013
    Posts:
    287
    I'm pluggin in the View Direction in WorldSpace, the Normal Vector in WorldSpace. Then I transform the output refraction vector from World to Tangent space (Direction). Multiply this by a scaling value. Add this to the 'screen position' node and use this value to sample the 'Scene Color'.

    But what worries me is that when IORsource == IORMedium, I would expect the refraction to be equal to the ViewDirection (or inverse of the view direction) in this case. But is does not seem to be.
     
  5. wwWwwwW1

    wwWwwwW1

    Joined:
    Oct 31, 2021
    Posts:
    769
    You don't need to transform the refracted view direction (from world space) to tangent space.
     
    Arnold_2013 likes this.
  6. Arnold_2013

    Arnold_2013

    Joined:
    Nov 24, 2013
    Posts:
    287
    A benefit over the refract() HLSL seems to be that this 'refract node' also works when IOR_Medium < IOR_Source

    The custom function node methode using the HLSL refract() function, had the same issue... In this video the input of the normal vector is negated, and this fixes the issue with equal IORs (very good youtuber for shader graph!).

    So in the normal input of the node you need to input the negative Normal Vector in world space.


     
    wwWwwwW1 likes this.
  7. Arnold_2013

    Arnold_2013

    Joined:
    Nov 24, 2013
    Posts:
    287
    Thank you!, I started this by following some youtube tutorials... and it did seem to work... just not always.

    Looking at the refract node documentation it might be more correct to input the inverse of the View direction, since the view direction node is towards the camera, where the 'camera direction (towards the object)' is mentioned as an example. Now the normal vector node can be used directly (without negating) on the other input.

    ShaderGraph nodes for flat window with a thickness (replace the multiply below screen position to remove the thickness)
    upload_2023-2-22_12-36-11.png

    upload_2023-2-22_12-38-6.png
    For a thickness of 0.25m, with a IOR ambiant =1 and IOR medium = 1.5 (Glass)

    Edit: Note set renderQueue of material to 4000 (or something after all the things you want to see through the material, since they need to be in the color buffer)
     

    Attached Files:

    arepera, Oelson and jRocket like this.