Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Cross Section — only show the intersection

Discussion in 'Shaders' started by VojtaKoci, Oct 22, 2023.

  1. VojtaKoci

    VojtaKoci

    Joined:
    Oct 12, 2020
    Posts:
    5
    Hello everyone!

    Sorry for reaching out about a topic that was discussed many times. I'm obviously not great with shaders, but I've studied all the major threads throughout, I promise. My problem is slightly specific though... I'm not gonna bother you with the broader problem I'm trying to solve and will present just the basic roadblock I've bumped into.
    In the most simple words possible, I'm attempting to display only the intersection of an object and a plane, not including half of the cut object. There I'm all set with no problems:

    <iframe width="560" height="315" src="
    " title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

    I use this sort of simple, rather primitive fragment shader:
    Code (CSharp):
    1. half4 frag(v2f i, float facing : VFACE) : SV_Target
    2.             {
    3.                 half4 customColour = half4(0,0,0,1);
    4.  
    5.                 float dotProd = dot(i.worldPos.xyz - _PlanePosition.xyz, _PlaneNormal.xyz);
    6.                 clip(-dotProd);
    7.  
    8.                 if(facing < 0){
    9.                     customColour = _InnerColour;
    10.                 }
    11.                 return customColour;
    12.  
    13.             }
    Now, what I'm trying to do is to get rid of the black parts (front faces) and only leave the pink bits (back faces). When I try to set the front face colour to fully transparent (in the video below I keep the alpha to 0.35, just for reference), some of the back faces are fully visible:

    <iframe width="560" height="315" src="
    " title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

    Code (CSharp):
    1.  half4 frag(v2f i, float facing : VFACE) : SV_Target
    2.             {
    3.                 half4 customColour = half4(0,0,0,0.35);
    4.  
    5.                 float dotProd = dot(i.worldPos.xyz - _PlanePosition.xyz, _PlaneNormal.xyz);
    6.                 clip(-dotProd);
    7.  
    8.                 if(facing < 0){
    9.                     customColour = _InnerColour;
    10.                 }
    11.                 return customColour;
    12.  
    13.             }
    As you can see in the attached video, weirdly at some rotations it works as it should (ignoring the 0.35 alpha for reference). For most of you pros this behaviour is probably expected, but I really couldn't understand why that happens. I do understand that all backfaces are drawn as I've set the Cull to Off, however I don't understand why some back faces are drawn and some are not. So my questions are:
    • Why does this happen?
    • Is it possible to bypass it? Could it be just a wrong set of shader commands?
    • Is there a way to achieve such effect in one shader (working in URP so also in a single pass)? I plan to later use this effects in render features for multiple objects at once so achieving this effect in a single shader would be brilliant.
    • If such solution is not available, is it possible to use the front faces to generate a stencil, later applying it on the back faces?
    Any tips or references for similar problems would be much appreciated. I've read and tried many things how to solve the more complex effect I'm working towards, this is a dumb first roadblock I've hit... If necessary, I'll of course happily depict the larger goal of mine, but I don't want to bother you with it for now.

    Thank you very much for any help! Have a great day!
    Cheers,
    Vojta
     
  2. Appleguysnake

    Appleguysnake

    Joined:
    Jan 9, 2015
    Posts:
    19
    I don't know that I have any solution for you, but I'm a bit unclear on the question itself. You have the intersection working to show a slice, but the backface part is confusing me. My two interpretations of what you're looking for are:
    1. Show the slice (in your first video) as if slicing through a solid cube. Either the cube is visible or invisible when not intersecting the quad. Your second example seems to show you have this working too, just by making the cube transparent.
    2. Have the slice act as if cutting through a box, so the slice lets you see the inside. When not sliced, the box would look like a normal cube
    I assume option 2 is a job for a stencil shader, but I'm not sure. For option 1, if you want the back faces there to determine the color of the slice itself (which will be solid), then you don't need to actually render the back faces, you just need the color property.
    Sorry I can't be more help!
     
  3. VojtaKoci

    VojtaKoci

    Joined:
    Oct 12, 2020
    Posts:
    5
    Hey Appleguysnake (what a biblical nickname),

    I'm very sorry for a confusing lengthy description. English is my second language to I might lack some better words, hehehe.
    Anyway, the effect I'm going for is slicing through a solid cube. The problem is I need the shader to only show the cross section itself (the pink bit in the videos) and discard the black bits representing surface of the one half of the sliced cube. Therefore I'm trying to make the black pixels transparent and only keep the pink bits. But when I change the cube surface colour to have alpha 0, the pixels don't become transparent, because you can see some back faces of the cube (the pink bits, again).
    I think it happens because the cube's triangles calculate in irregular order. If the front faces got solved before the back faces, I think it might work fine.

    Anyway, thank you very much for your reply and sorry about my confusing cry for help, hehehe. I think I will try to post the more complex description of the problem to see whether anyone has any broader tips, I'll just create some visualization to avoid confusion...

    Cheers!
     
  4. tomekkie2

    tomekkie2

    Joined:
    Jul 6, 2012
    Posts:
    966
    It is a long time and I guess you have found the solution - if no - I have answered this question a very long time ago here: https://forum.unity.com/threads/crosssection.223790/#post-3353965
    This can be easily achieved by putting two stencil materials on the object.
    You can create two shaders just by adding the stencil sections to your code and two materials.
    The first one, name it SaveFrontToStencils, will use shader whose stencil section could look like this:
    Code (CSharp):
    1.         Stencil{
    2.             Ref [_StencilMask]
    3.             Comp never
    4.             Fail Replace
    5.         }
    The stencil section of the second shader could look like:
    Code (CSharp):
    1.         Stencil{
    2.             Ref [_StencilMask]
    3.             Comp NotEqual
    4.             Pass Zero
    5.         }
    (The stencil mask values of both material have to be the same)