Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

clipping objects with a plane

Discussion in 'Shaders' started by pitibonom, Jun 20, 2018.

  1. pitibonom

    pitibonom

    Joined:
    Aug 17, 2010
    Posts:
    188
    Hi all.

    Many topics about this but lots of them are misty.
    I know all things are simple to those who have keys ;-)
    I just want to clip an object with a plane.
    Then i wrote a lil shader:
    Code (GLSL):
    1. Shader "Custom/clipeux" {
    2.     Properties {
    3.         _Color ("Color", Color) = (1,1,1,1)
    4.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    5.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    6.         _Metallic ("Metallic", Range(0,1)) = 0.0
    7.           _a ("_a",Float) = 0.0
    8.           _b ("_b",Float) = 0.0
    9.           _c ("_c",Float) = 0.0
    10.           _d ("_d",Float) = 0.0      
    11.     }
    12.     SubShader {
    13.         Tags { "RenderType"="Opaque" }
    14.         LOD 200
    15.  
    16.         CGPROGRAM
    17.         // Physically based Standard lighting model, and enable shadows on all light types
    18.         #pragma surface surf Standard fullforwardshadows
    19.  
    20.         // Use shader model 3.0 target, to get nicer looking lighting
    21.         #pragma target 3.0
    22.  
    23.         sampler2D _MainTex;
    24.         float _a,_b,_c,_d;  
    25.        
    26.         struct Input {
    27.             float2 uv_MainTex;
    28.             float3 worldPos;
    29.         };
    30.  
    31.         half _Glossiness;
    32.         half _Metallic;
    33.         fixed4 _Color;
    34.  
    35.         // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
    36.         // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
    37.         // #pragma instancing_options assumeuniformscaling
    38.         UNITY_INSTANCING_BUFFER_START(Props)
    39.             // put more per-instance properties here
    40.         UNITY_INSTANCING_BUFFER_END(Props)
    41.  
    42.         void surf (Input IN, inout SurfaceOutputStandard o)
    43.         {
    44.  
    45.              clip (_a *IN.worldPos.x +
    46.                     _b *IN.worldPos.y +
    47.                     _c *IN.worldPos.z +
    48.                     _d > 0 ? -1 :1);
    49.  
    50.        
    51.             // Albedo comes from a texture tinted by color
    52.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    53.             o.Albedo = c.rgb;
    54.             // Metallic and smoothness come from slider variables
    55.             o.Metallic = _Metallic;
    56.             o.Smoothness = _Glossiness;
    57.             o.Alpha = c.a;
    58.         }
    59.         ENDCG
    60.     }
    61.     FallBack "Diffuse"
    62. }
    63.  
    a quite simple shader......
    I used worldPos because ObjPos gives only the coordinates of the object origin and
    results in a binary ( On / OFF ) state of the whole object.

    a b c and d are the values for a plane equation.

    i set them up through a CS script this way:

    Code (CSharp):
    1.     void shader_setup(Vector3 v,float dist)
    2.     {
    3.             mat.SetFloat("_a",v.x);
    4.             mat.SetFloat("_b",v.y);
    5.             mat.SetFloat("_c",v.z);
    6. //            mat.SetFloat("_d",dist);
    7.  
    8.     }
    9.    
    10.    
    11.    
    12.    
    13.     // Update is called once per frame
    14.     void Update ()
    15.     {
    16.         shader_setup((Vector3)(plan_de_coupe.transform.localToWorldMatrix*Vector3.up),0);
    17.     }
    things work properly till the object i want to clip is located at (0,0,0) coordinates.
    As soon as i move it from there, it's completely clipped of not.

    I think i hardly need a objectToWorldMatrixToObjectToThePizzaOnMyDesk expert ;)

    please help !!!

    Thanks in advance for your answers :)

    regards.
     
    unity_aica01 likes this.
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    I would suggest not using the localToWorldMatrix directly, but rather use the built in transform.Transform* functions. You could also use the built in Plane class to help calculate things.

    Code (csharp):
    1. void shader_setup(Plane p)
    2. {
    3.     // pass plane as a Vector4 instead of as 4 floats
    4.     mat.SetVector("_p", new Vector4(p.normal.x, p.normal.y, p.normal.z, p.distance));
    5. }
    6.  
    7. void Update()
    8. {
    9.     // world position of plane's game object
    10.     Vector3 planePos = plan_de_coupe.transform.position;
    11.     // world direction of plane's local up
    12.     Vector3 planeNormal = plan_de_coupe.transform.TransformDirection(Vector3.up);
    13.     shader_setup(new Plane(planeNormal, planePos));
    14. }
    Then in the shader:
    Code (csharp):
    1. // uniform declaration
    2. float4 _p;
    3.  
    4. // in the surf function
    5. clip(-(dot(_p.xyz, IN.worldPos.xyz) + p.w));
    The shader code likely functionally identical to what you already had, but streamlines it a little.
     
    unity_aica01 likes this.
  3. pitibonom

    pitibonom

    Joined:
    Aug 17, 2010
    Posts:
    188
    Hi bgolus !

    i definetely love your avatar !!!! :D if it's got a bro i want it !!! :p

    i'll soon post what i found out wich now works fine. ( hoping shaderlab ppl won't rewrite things and change what
    is assumed today... )

    Thanks a lot bgolu for you answer !!!
    I didn't know about the plane class !!! for sure it will help a lot !!!!
    but not till am sure that my "normal-distance" works propely ;)

    regards to all and also to unity ppl who really do a great job even if docs are sometimes lacking info :p
     
    Last edited: Jun 21, 2018
    unity_aica01 likes this.
  4. pitibonom

    pitibonom

    Joined:
    Aug 17, 2010
    Posts:
    188
    Okay.... now that i have a DAAAAMN SIMPLE WORKING plane clip shader..... ;)

    clip.jpg

    i'd like to grab pixels normals ( i mean interpolated normals ) wich in surface shaders are NOT
    interpolated !
    In fact i know they are !!! but to grab then i guess i have to do some
    mul(UNITY_MATRIX_OF_THE_PIZZA_ON THE_CODER_DESK+BlackMagicNumber, v.normals);
    :D
    examples in shader docs talkin about normals work as-is but dont work at all
    with the # pragmas in 2018 shaderlab....

    Why i need the normals ?
    I just wanna check it's sign from the viewpoint and do things like
    if > 0
    albedo=my_awesome_texture
    else
    albedo=my_ugly_color_for_filled_volumes

    As you guess i love simple things !!!! ( at least the ones i can understand... )

    I'll post a complete simple project for memory and help of others :)
    Share is the base.

    regards !
    and thanks in advance for your help !


    EDIT:
    owwwww damn on me !!!!! i just forgot the vertex:vert pragma in the pragma line !!!!
    It's been too long since i've not written shaders..... 7 years..... enough to have to
    relearn everything !!!!
    okay..... things are getting fine. cya all soon and if you got ideas/advices/anything
    about a plane clipping shader, just leave a post here ;)
     
    Last edited: Jun 21, 2018
    unity_aica01 likes this.
  5. pitibonom

    pitibonom

    Joined:
    Aug 17, 2010
    Posts:
    188
    Perfect !!!! i got it !!!!
    was just a lil dot product between normals and viewdir.....
    quite simple.....
    In fact, shadelab is just like cold water. Hard to dive in but when you're immersed, it's comfortable XD lol
    The hard part is to get into the water :p

    things work exceeeeept.... errr.... this lil crappy thingie appearin on the rim of curved surfaces.....
    just like here:

    rim.jpg

    You see this lil crappy yellow rim ?????
    I absolutely don't know where it comes from :(
    mebe some floating point accuracy artifact ?

    I confess i cheated for getting rid of this.

    In shader code, for knowing wether a face is front or back i use this dot product:
    Code (csharp):
    1.          
    2. if (dot(IN.worldNormal, IN.viewDir) > 0.0)
    3.     o.Albedo = c.rgb;
    4. else
    5.     o.Albedo = float3(1,1,0);
    6.  

    now for hiding those ugly yellow pixels i just set the 0.0 limit to something a lil bit higher
    like 0.07. and it does the thing. however i wonder what's going on when you change the
    camera projection factors..... :/
    The bad part for this "solution" is that now external texture appears inside.... in the yellow
    part...

    unrim.jpg

    does anyone have an idea ?

    lemme just post the full shader here ;)
    Code (CSharp):
    1.  
    2. // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    3.  
    4. // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
    5. // Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
    6.  
    7. Shader "Custom/clipeux" {
    8.     Properties {
    9.         _Color ("Color", Color) = (1,1,1,1)
    10.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    11.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    12.         _Metallic ("Metallic", Range(0,1)) = 0.0
    13.           _a ("_a",Float) = 0.0
    14.           _b ("_b",Float) = 0.0
    15.           _c ("_c",Float) = 0.0
    16.           _d ("_d",Float) = 0.0      
    17.           _e ("_e",Float) = 0.0      
    18.     }
    19.     SubShader {
    20.         Tags { "RenderType"="Opaque" }
    21.         LOD 200
    22.         Cull OFF
    23.        
    24.        
    25.         CGPROGRAM
    26.         // Physically based Standard lighting model, and enable shadows on all light types
    27.         #pragma surface surf Standard fullforwardshadows
    28.  
    29.         // Use shader model 3.0 target, to get nicer looking lighting
    30.         #pragma target 3.0
    31.        
    32.  
    33.  
    34.         sampler2D _MainTex;
    35.         float _a,_b,_c,_d,_e;  
    36.        
    37.         struct Input {
    38.             float2 uv_MainTex;
    39.             float3 worldPos;
    40.             float3 worldNormal;
    41.             float3 viewDir;
    42.         };
    43.  
    44.         half _Glossiness;
    45.         half _Metallic;
    46.         fixed4 _Color;
    47.  
    48.         // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
    49.         // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
    50.         // #pragma instancing_options assumeuniformscaling
    51.         UNITY_INSTANCING_BUFFER_START(Props)
    52.             // put more per-instance properties here
    53.         UNITY_INSTANCING_BUFFER_END(Props)
    54.  
    55.  
    56.         void surf (Input IN, inout SurfaceOutputStandard o)
    57.         {
    58.        
    59.         float3 localPos = IN.worldPos -  mul(unity_ObjectToWorld, float4(0,0,0,1)).xyz;
    60.        
    61.         float norm_calc = _a *localPos.x +
    62.                           _b *localPos.y +
    63.                           _c *localPos.z +
    64.                           _d;
    65.        
    66.             clip (norm_calc > 0 ? -1 :1);
    67.  
    68.        
    69.             // Albedo comes from a texture tinted by color
    70.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
    71.            
    72.             if (dot(IN.worldNormal, IN.viewDir) > _e)
    73.                 o.Albedo = c.rgb;
    74.             else
    75.                 o.Albedo = float3(1,1,0);
    76.                
    77.                
    78.             // Metallic and smoothness come from slider variables
    79.             o.Metallic = _Metallic;
    80.             o.Smoothness = _Glossiness;
    81.             o.Alpha = c.a;
    82.         }
    83.         ENDCG
    84.     }
    85.     FallBack "Diffuse"
    86. }
    87.  
     
    Last edited: Jun 21, 2018
    unity_aica01 likes this.
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    Yeah, you don't want normals.

    For exactly this reason.

    Vertex normals have no direct relation to the tri's facing. They're usually similar, but there's no rule that they match. If your model was using faceted normals where each tri had unique vertices with the vertex normals matching the tri's facing perfectly then using a dot product would do what you want. But since that's usually not the case you get the artifacts you're seeing.

    What you would really want is whatever the GPU uses to determine front and back culling, as that is actually based on the tri's facing and not the normals. Luckily GPUs pass that data to the fragment shader already, and you can use this value in Surface Shaders.

    What you want is VFACE.

    Code (csharp):
    1. // add this to the Input struct
    2. fixed facing : VFACE;
    3.  
    4. // do this in the surface function
    5. if (IN.facing > 0)
    6.     // front face
    7. else
    8.     // back face
    The IN.facing variable will always be a 1 or -1 value depending on if you're viewing the front or back face of the tri. Additionally you may not want to only set the albedo color as the surface normals are going to be pointing out when you're looking at the interior faces.

    // flip the normals if viewing the back face
    o.Normal *= IN.facing;


    Alternatively you could use the clipping plane's normal instead, but the normal you output from the surface shader is always in tangent space so you would have to convert the plane's world space normal into tangent space before outputting it. That's a little annoying, but still possible.
     
    unity_aica01 likes this.
  7. grobonom

    grobonom

    Joined:
    Jun 23, 2018
    Posts:
    335
    hi bgolus :)

    wow VFACE is the thing !!!! i harly hop unity will keep this data in vert to frag to pixel structure !!!!!
    please could you tell me where you got this info ?
    I had no idea this float existed in base ( hidden ) surf shaders structs !

    now things are getting almost perfect, and am happy as i got a one pass shader instead of a two pass one !
    BUT.....
    ahahah yes there's always a 'but'

    now i want the color choosen for backfaces tu be unlit !
    see:
    unwanted_lights.jpg


    I'd like the blue part of this model to be totally unlit. Only the base blue....
    but i think that in a surface shader and in one pass this is'nt possible....
    mebe by 'delighting' faces that will be lit by the base surface shader ?????
    :/

    would you have an idea on how this could be done ?
    If not my solution will be a two pass, front and back shader with front lit and back unlit....

    thanks a bunch for your great help !!! :)
     
    unity_aica01 likes this.
  8. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    I knew of VFACE from reading the HLSL documentation, and the GLSL documentation before that when writing shaders outside of Unity.
    I found out it can be used in Surface Shaders when it was in the release notes for 5.1.
    https://unity3d.com/unity/whats-new/unity-5.1

    That’s what the Emission color is for. Front faces you use o.Albedo, back faces set o.Albedo to black and set o.Emission to blue.
     
    unity_aica01 likes this.
  9. pitibonom

    pitibonom

    Joined:
    Aug 17, 2010
    Posts:
    188
    bgolus ! you're definetely my shaderlab mentor ;)

    your answers are simple and straight. i like it !!!

    now this shader works fine ! just like it did some few years ago except for the ambient but it's not that important....
    I'll post the final shader here soon for community help purpose.

    and maybe.... the webgl url on wich am really unhappy....... tho it's better than nothing....
    thanks a bunch for your great help !!!!
     
    unity_aica01 likes this.
  10. grobonom

    grobonom

    Joined:
    Jun 23, 2018
    Posts:
    335
    For the one that could be interrested, here is the whole shader code:
    Code (ShaderLab):
    1.  
    2. Shader "Custom/plane clipping" {
    3.     Properties {
    4.         _Color ("Color", Color) = (1,1,1,1)
    5.         _MainTex ("Albedo (RGB)", 2D) = "white" {}
    6.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    7.         _Metallic ("Metallic", Range(0,1)) = 0.0
    8.       _cutting_plane_norm ("cutting plane normal",Vector) = (1,0,0,0)
    9.  
    10.     }
    11.     SubShader {
    12.         Tags { "RenderType"="Opaque" }
    13.         LOD 200
    14.         Cull OFF
    15.        
    16.        
    17.         CGPROGRAM
    18.         // Physically based Standard lighting model, and enable shadows on all light types
    19.         #pragma surface surf Standard fullforwardshadows
    20.  
    21.         // Use shader model 3.0 target, to get nicer looking lighting
    22.         #pragma target 3.0
    23.        
    24.  
    25.  
    26.         sampler2D _MainTex;
    27.       float4 _cutting_plane_norm;
    28.        
    29.         struct Input {
    30.             float2 uv_MainTex;
    31.             float3 worldPos;
    32.             float3 worldNormal;
    33.             float3 viewDir;
    34.          fixed facing : VFACE;
    35.         };
    36.  
    37.         half _Glossiness;
    38.         half _Metallic;
    39.         fixed4 _Color;
    40.  
    41.         // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
    42.         // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
    43.         // #pragma instancing_options assumeuniformscaling
    44.         UNITY_INSTANCING_BUFFER_START(Props)
    45.             // put more per-instance properties here
    46.         UNITY_INSTANCING_BUFFER_END(Props)
    47.  
    48.  
    49.         void surf (Input IN, inout SurfaceOutputStandard o)
    50.         {
    51.        
    52.         float3 localPos = IN.worldPos -  mul(unity_ObjectToWorld, float4(0,0,0,1)).xyz;
    53.        
    54.         float norm_calc = _cutting_plane_norm.x *localPos.x +
    55.                             _cutting_plane_norm.y *localPos.y +
    56.                             _cutting_plane_norm.z *localPos.z +
    57.                             _cutting_plane_norm.w;
    58.        
    59.             clip (norm_calc > 0 ? -1 :1);
    60.  
    61.        
    62.             // Albedo comes from a texture tinted by color
    63.             fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
    64.            
    65. //            if (dot(IN.worldNormal, IN.viewDir) > _e)
    66. //                o.Albedo = c.rgb;
    67. //            else
    68. //                o.Albedo = _Color;
    69.                
    70.          if (IN.facing > 0)
    71.                 o.Albedo = c.rgb;
    72.          else
    73.          {
    74.                 o.Albedo = float3(0,0,0);
    75.             o.Emission = _Color;
    76.          }
    77.    
    78.             // Metallic and smoothness come from slider variables
    79.             o.Metallic = _Metallic;
    80.             o.Smoothness = _Glossiness;
    81.             o.Alpha = c.a;
    82.         }
    83.         ENDCG
    84.     }
    85.     FallBack "Diffuse"
    86. }
    87.  
     
    unity_aica01 likes this.
  11. unity_aica01

    unity_aica01

    Joined:
    May 19, 2020
    Posts:
    86
    Hi! I was trying to develop a clipping plane tool and then get to this post! Pretty interesting and helpull!!
    But I have some questions (well in fact its just 1 question):
    When you set up the tool in the unity editor, you need to assign the material thas contains the shader in all scene gameObjects for clipping? or just in the game object that will make the clip?
     
  12. grobonom

    grobonom

    Joined:
    Jun 23, 2018
    Posts:
    335
    you got 2 ways.
    you set the material to all the objects you want to cut
    or
    you change the material shader of all the objects ( i guess this one is faster ;) )
     
    unity_aica01 likes this.
  13. unity_aica01

    unity_aica01

    Joined:
    May 19, 2020
    Posts:
    86
    Thank you for the reply!
    Yes i was thinking about it, and thought to change the material shader to all my model materials, but when I tried It my cutoff controller (script) need to make a modification due to that I can not set a Vector directly into a shader (or that´s what I guessed after consulting the documentation (shader does not have a definition to SetVector)) so I should use a SetGlobalVector?
    I had already read the docs in unity but in the declaration :
    - public static void SetGlobalVector ( string name , Vector4 value );
    I dont understand the name, in the docs its defined like the properti name that I want to make global... does it reference to the new Vector name and its value?

    Hope I explained my self its a bit messy for my all the shader stuff (im pretty new on it)

    EDIT: I finally understood it!! Sorry for my dumb question, I was calling the shader property (in this case the plane defined in it) instead the shader itself! Now almost working :D YAY!!
     
    Last edited: Jun 7, 2021
  14. pitibonom

    pitibonom

    Joined:
    Aug 17, 2010
    Posts:
    188
    Those global methods are used for setting data in shaders in an application-wide manner ( like the ambient color for example, wich is unique for your whole app ).

    If you need to set a 'per-material' vector you need to use

    Material yourMat = the_mat_to_change;

    yourMat.SetVector("the_shader_vector_to_change",TheNewVectorValue);

    And you gotta do it for each material you need to change this vector on ( wich is pretty fast if you do it once and if you don't have 10000 materials to change ;) )

    anyway, it's fine if it almost work ;)

    Happy unitying !
     
    unity_aica01 likes this.
  15. unity_aica01

    unity_aica01

    Joined:
    May 19, 2020
    Posts:
    86

    Hi! Finally I got it! its working fine in my scene and everything looks correctly! A thousand thanks to you all for the tips and replys very appreciated!
     
    grobonom likes this.