Search Unity

How to clip the mesh inside intersection

Discussion in 'Shaders' started by Cylau, Jan 14, 2022.

  1. Cylau

    Cylau

    Joined:
    Jun 5, 2019
    Posts:
    15
    I need to display only non intersected areas when transparent bodies intersect. The intersection plane should be drawn. It is posible?

    I mean the green highlighted area of the right sphere should not be visible.
    upload_2022-1-14_17-27-48.png
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    The "trick" to accomplish this is to use an extra depth only pass. For a single object you can do it with a custom shader with two passes. There's an example of of this in Unity's old documentation (sadly removed in the latest version).
    https://docs.unity3d.com/2017.2/Documentation/Manual/SL-CullAndDepth.html
    "Transparent shader with depth writes"

    On the left is a regular transparency shader, and on the write is a shader that uses a depth only pass before the transparency pass. The HDRP's lit shader actually has this feature built in.

    However with multiple objects like what you have you'll likely need to use two materials. One material is a simple depth only shader that draws first, and the second is the material you're already using.
    Code (CSharp):
    1. Shader "DepthOnly"
    2. {
    3.     SubShader {
    4.         Tags { "Queue"="Transparent-1"  "IgnoreProjector" = "True" "RenderType" = "Transparent" }
    5.         ColorMask 0
    6.  
    7.         Pass {
    8.             CGPROGRAM
    9.             #pragma vertex vert
    10.             #pragma fragment frag
    11.  
    12.             #include "UnityCG.cginc"
    13.  
    14.             float4 vert (float4 vertex : POSITION) : SV_Position { return UnityObjectToClipPos(vertex); }
    15.             fixed4 frag () : SV_Target { return 0; }
    16.             ENDCG
    17.         }
    18.     }
    19. }
    If you add a material using that shader to the existing spheres along with the current material you'll get a warning about it being more expensive that you can ignore. But it should produce the look you want. However no other transparent object will show up behind them. If that's a problem you'll need set the queue to 3000 (
    "Queue"="Transparent")
    without the
    -1
    ), use two separate renderers for each object, a custom script to set the
    renderer.sortingIndex
    on the renderer using the depth only material to make it render before the renderer with the "normal" material on it, and a parent game object with a Sorting Group component. That'll make the entire group of objects get sorted separately from the rest in the scene, but should allow other transparent objects that are behind it to still be visible.
     
  3. Cylau

    Cylau

    Joined:
    Jun 5, 2019
    Posts:
    15
    Thanks for the answer. It worked but my main material uses vertex transofrmation and when i add a second material with depth only there are transperancy artifacts during the transformation.
    upload_2022-1-17_14-16-17.png
    upload_2022-1-17_14-16-36.png
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Then you need a depth only shader that does exactly the same vertex transformations.
     
  5. Cylau

    Cylau

    Joined:
    Jun 5, 2019
    Posts:
    15
    Oh, it's was so obvious that i'm ashamed that i did not immediatly guess. Thanks, now everything works as it should.
     
  6. Cylau

    Cylau

    Joined:
    Jun 5, 2019
    Posts:
    15
    I create a build for android and it doesnt work on it. It looks like there is a transformation desyncrhonization in two shaders or something like that. Could it be a problem that i use hlsl in the main shader but cg in depth only shader? Actually the problem looks the same as on the screenshots that i sent above.

    Vars for transformation i set in one loop

    Code (CSharp):
    1.         for (int i = 0; i < render.materials.Length; i++)
    2.         {
    3.             _render.GetPropertyBlock(_propertyBlock, i);
    4.             _propertyBlock.SetInt("_Count", CountMax);
    5.             _propertyBlock.SetFloat("_Spring", Spring);
    6.             _propertyBlock.SetFloat("_Damping", Damping);
    7.             _propertyBlock.SetFloat("_Namida", Namida);
    8.             _propertyBlock.SetVectorArray("_pAfs", pAfs);
    9.             _propertyBlock.SetVectorArray("_dAts", dAts);
    10.             _render.SetPropertyBlock(_propertyBlock, i);
    11.         }
     
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Unity doesn't support Cg, all shaders are in written in HLSL. Unity used to use Cg which is why so many things around Unity's shaders have "cg" in them, but they're all actually just HLSL code as Cg was abandoned by Nvidia a decade ago and Unity removed support shortly afterward.
    CGPROGRAM
    and
    HLSLPROGRAM
    are effectively the same thing.

    However the answer to your question is "yes", as there's one minor caveat to that previous statement.
    CGPROGRAM
    automatically adds a hidden
    #include "UnityCG.cginc"
    . If you're using one of the SRPs, or you're otherwise not using the built in rendering path's
    UnityObjectToClipPos()
    , you'll need to make your depth only shader use exactly the same transformations into clip space as the shader you're trying to match.

    You also don't need to use the per-material override for material blocks. You can use the per-renderer version to set those parameters on all materials on a renderer (assuming you don't need additional unique per-material overrides).
     
  8. Cylau

    Cylau

    Joined:
    Jun 5, 2019
    Posts:
    15
    Thanks again for the detail answer! I fixed problem with the depth only shader. Taking advantage of your responsiveness i want to ask anothe question. For the transformation i use function from the asset. It was written to standart render and when i transferred it to my urp shader there were problem with normal calculation. During the transformation the vertices normals are calculated incorrectly that are involved in the transformation and it looks like this:
    upload_2022-1-19_17-45-41.png

    Function which i use
    Code (CSharp):
    1. struct result
    2. {
    3.     float4 resPos;
    4.     float3 resNormal;
    5. };
    6.  
    7. result WaveModify(float4 pos, in float3 normal)
    8. {
    9.     result r;
    10.     float3 v;
    11.     float3 n = normal;
    12.  
    13.     for (int i = 0; i < _Count; i++) {
    14.         dataBuff data = getData(i);
    15.         float3 dir = pos.xyz - data._WorldForcePos.xyz;
    16.         float3 wdir = mul((float3x3)UNITY_MATRIX_M, dir);
    17.         float distance = dot(dir, dir);
    18.         float time = _Time.y - data._StartTime;
    19.         float singleForce = data._Force / (1 + distance * 5);
    20.         float A = lerp(singleForce, 0, saturate(((_Damping)*time) / abs(singleForce)));
    21.         float x = time - distance / data._Namida;
    22.         float speed = data._Namida * (4 * 3.14 * 3.14) / _Spring;
    23.         A = (speed * speed * time * time) > distance ? A : 0;
    24.         float h = -A * (cos(_Spring * (x))) * 0.1;
    25.         v += h * normal;
    26.         float3 binormal = cross(normal, wdir);
    27.         float3 tangent = cross(binormal, normal);
    28.         n += h * tangent * 20;
    29.     }
    30.  
    31.     float3 vn = cross((pos.xyz + v) * n, pos.xyz * n);
    32.     r.resPos = half4(pos.xyz + v, 1);
    33.     r.resNormal = normalize(n);
    34.     return r;
    35. }
    And vertex function
    Code (CSharp):
    1. VertexDescription VertexDescriptionFunction(VertexDescriptionInputs IN)
    2. {
    3.     VertexDescription description = (VertexDescription)0;
    4.  
    5.     float3 normal = mul((float3x3)UNITY_MATRIX_M, IN.ObjectSpaceNormal);
    6.     result w = WaveModify(IN.ObjectSpacePosition, normal);
    7.     description.Position = w.resPos;
    8.     description.Normal = normalize(mul(w.resNormal, (float3x3)UNITY_MATRIX_M));
    9.     description.Tangent = IN.ObjectSpaceTangent;
    10.  
    11.     return description;
    12. }

    I have tried several options for setting the normal and none of them work as it should. So my question is: does this function count normals incorrectly or is it due to the nuances of urp shaders?
     
  9. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    No idea!

    Though I do find it odd the function is taking an object space position and world space normal. I would expect them both to be in world space or object space.

    Also there's a vn variable near the end that gets calculated and never used. Not sure if that was there in the original asset's function or a typo on your part somewhere.
     
  10. Cylau

    Cylau

    Joined:
    Jun 5, 2019
    Posts:
    15
    Okay, I fixed it simply by using an unmodified normal and turning off shadow retrieval. I think this is far from the best solution to the problem, but it worked and so far I'm happy with it.
    Yep, this is my mistake. Forgot to delete this line
     
  11. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    That sounds like you're not doing the vertex modifications to the other passes. Like the depth pre-pass, you should be doing this to all the other passes the shader has. For a transparent shader you'll really only need to modify the ForwardLit and ShadowCaster passes, but if you ever have an opaque shader you're doing these kinds of modifications to you'll need to do it to all of the other passes.
     
  12. Cylau

    Cylau

    Joined:
    Jun 5, 2019
    Posts:
    15
    Thank you for the clarification! And if you modify the vertices in all passes, will it somehow affect performance? Or maybe not even think about it?
     
  13. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Of course, you're adding more code.

    But will it affect it meaningfully? Unlikely. I wouldn't expect you to be able to even profile a difference in performance using Unity's profiling tools.
     
    Cylau likes this.