Search Unity

CSG faking with shaders: nearly there?

Discussion in 'Shaders' started by UserAnon91, Jul 26, 2015.

  1. UserAnon91

    UserAnon91

    Joined:
    Jul 8, 2013
    Posts:
    17
    I've been trolling forum posts trying to find a current example of how to fake csg with shaders, my ultimate goal being that I would like to render nothing except for the location that an object is overlapped. I believe that I'm close to achieving this effect, although there seems to be something I'm missing. 1.png

    My goal at this point is to have the small circle inside the sphere render, and nothing else.
    2.png

    At this point, the cube renders everywhere except for where the sphere is ahead of it on zdepth. Removing the cube from render, only rendering the circle, and not rendering the sphere is what I'd like to achieve
    3.png

    The cube is using the "Regular" shader.

    The sphere that masks is using the "Special" shader

    Cube;
    Code (CSharp):
    1. Shader "Custom/Regular" {
    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.     }
    8.     SubShader {
    9.         Tags { "RenderType"="Opaque" "Queue"="Geometry+2"}
    10.         LOD 200
    11.        
    12.         CGPROGRAM
    13.         #pragma surface surf Lambert
    14.         float4 _Color;
    15.         struct Input {
    16.             float4 color : COLOR;
    17.         };
    18.         void surf (Input IN, inout SurfaceOutput o) {
    19.             o.Albedo = _Color.rgb;
    20.             o.Normal = half3(0,0,-1);
    21.             o.Alpha = 1;
    22.         }
    23.         ENDCG
    24.     }
    25.     FallBack "Diffuse"
    26. }
    27.  
    Sphere "Mask";
    Code (CSharp):
    1. Shader "Custom/Special" {
    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.     }
    8.     SubShader {
    9.         Tags { "RenderType"="Opaque" "Queue"="Geometry+1"}
    10.         cull back
    11.         Colormask 0
    12.        
    13.         CGINCLUDE
    14.             struct appdata {
    15.                 float4 vertex : POSITION;
    16.             };
    17.             struct v2f {
    18.                 float4 pos : SV_POSITION;
    19.             };
    20.             v2f vert(appdata v) {
    21.                 v2f o;
    22.                 o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
    23.                 return o;
    24.             }
    25.             half4 frag(v2f i) : SV_Target {
    26.                 return half4(1,1,0,1);
    27.             }
    28.         ENDCG
    29.         Pass
    30.         {
    31.             Tags {"Queue"="Geometry+3" }
    32.             Cull Front
    33.             ColorMask 0
    34.            
    35.             CGPROGRAM
    36.             #pragma vertex vert
    37.             #pragma fragment frag
    38.             ENDCG
    39.        
    40.         }
    41.         Pass
    42.         {
    43.             Tags {"Queue"="Geometry+4" }
    44.             cull back
    45.             ztest Equal
    46.             ColorMask rgba
    47.            
    48.             CGPROGRAM
    49.             #pragma vertex vert
    50.             #pragma fragment frag
    51.             ENDCG
    52.        
    53.         }
    54.     }
    55.     FallBack "Diffuse"
    56. }
    57.  
    Any help would be appreciated, I'm at a bit of a standstill atm :(

    Thanks everyone,
    -Gudge
     
  2. UserAnon91

    UserAnon91

    Joined:
    Jul 8, 2013
    Posts:
    17
  3. UserAnon91

    UserAnon91

    Joined:
    Jul 8, 2013
    Posts:
    17
    I'm attempting to get the effect demonstrated in this forum post: forum . The section I'm trying to get is the red overlap area.
     
  4. Jonny-Roy

    Jonny-Roy

    Joined:
    May 29, 2013
    Posts:
    666
    Try with ZTest NotEqual

    You might find real accuracy issues doing this though, as the depth buffer is only approximate depending on your target device.
     
  5. UserAnon91

    UserAnon91

    Joined:
    Jul 8, 2013
    Posts:
    17
    Unfortunately it didn't help, changing ztest equal to notequal made the sphere render yellow D:
    4.png
     
  6. Jonny-Roy

    Jonny-Roy

    Joined:
    May 29, 2013
    Posts:
    666
    I would have thought you'd be rendering the sphere with depth only?
     
  7. Jonny-Roy

    Jonny-Roy

    Joined:
    May 29, 2013
    Posts:
    666
    Although...that won't really help from all views as you won't get depth for the backface!
     
  8. Jonny-Roy

    Jonny-Roy

    Joined:
    May 29, 2013
    Posts:
    666
    Thinking about this, I'm not 100% sure you could do this without using rendertextures, so you'd go something like this:

    1) Render Sphere Backface depth to RT1
    2) Render Sphere Frontface depth to RT2
    3) Render Cube and use Clip command if pixel depth equals RT1 or RT2.

    I think thats the old way, then you can use a threshold to change the width of the cut too.
     
  9. UserAnon91

    UserAnon91

    Joined:
    Jul 8, 2013
    Posts:
    17
    With ztest equal and colormask 0 on special, i get close to the effect that I want but the issue would be with regular i think. the rest of the cube needs to not be displayed.

    I'm attempting to use this to replace roughly 2000 area lights, so any practical use of this would be awesome. That said, there will be roughly 2000 objects with the regular shader interacting with walls in my "arena".
    5.png

    If I'm understanding your render texture idea, it would only require two textures, one for the sphere (no matter how many there are), and one for the walls using the main camera? If that's the case, then it will almost certainly be an improvement.
     
  10. Jonny-Roy

    Jonny-Roy

    Joined:
    May 29, 2013
    Posts:
    666
    Well, two both would be for the sphere no matter how many, then the cubes no matter how many would use both of the textures, you could probably just use 1 and use the depth texture instead of the second one (2 above) and probably depth test it, but I'm not 100% sure what you're going to be doing with this, so tricky to say...also I'm in the middle of something complex myself thats throwing my thoughts! :S
     
  11. UserAnon91

    UserAnon91

    Joined:
    Jul 8, 2013
    Posts:
    17
    I'll fiddle around with rendertextures to see how that goes and i'll report back once that's done :)
     
  12. Jonny-Roy

    Jonny-Roy

    Joined:
    May 29, 2013
    Posts:
    666
    The one great thing with the RT way, easier to debug, you can just output the RT and see what is going on!
     
  13. UserAnon91

    UserAnon91

    Joined:
    Jul 8, 2013
    Posts:
    17
    Just to be clear so I know exactly what to try, are you suggesting the Unity Render texture which uses separate cameras, or render to a texture with a shader.
     
  14. Jonny-Roy

    Jonny-Roy

    Joined:
    May 29, 2013
    Posts:
    666
    Quickest way is use a new camera as a child of you existing one and put it rendering to a rendertexture, then set that as a global shader texture for your other objects to pick up on.
     
  15. FuzzyQuills

    FuzzyQuills

    Joined:
    Jun 8, 2013
    Posts:
    2,871
    From what I am getting at, you're trying to do an overlay of some sort, of which such overlay comes from the cut-out bits of a mesh, correct? :D