Unity3D: How to show only the intersection/cross-section between two meshes at runtime?
Asked Answered
A

1

16

The Problem

Hi, I'm basically trying to do the same thing as described here: Unity Intersections Mask

desiredeffect

With the caveat that the plane isn't exactly a plane but a (very large relative to the arbitrary 3D object) 3D Cone, and the camera I'm using has to be an orthographic camera (so no deferred rendering).

I also need to do this basically every frame.

What I tried

I've tried looking up various intersection depth shaders but they all seem to be done with the perspective camera.

Even then they don't render the non-intersecting parts of the 3D objects as transparent, instead coloring parts of them differently.

The linked stackoverflow question mentions rendering the plane normally as an opaque object, and then using a fragment shader to render only the part of objects that intersect the plane.

However based on my (admittedly) very limited understanding of shaders, I'm uncertain of how to get around to doing this - as far as I know each fragment only has 1 value as it's depth, which is the distance from the near-clipping plane of the camera to the point on the object closest to the camera that is shown by that fragment/pixel.

Since the rest of the object is transparent in this case, and I need to show parts of the object that would normally be covered(and thus, from what I understand, depth not known), I can't see how I could only draw the parts that intersect my cone.


I've tried the following approaches other than using shaders:

  1. Use a CSG algorithm to actually do a boolean intersect operation between the cone and objects and render that.

    • Couldn't do it because the CSG algorithms were too expensive to do every frame.
  2. Try using the contactPointsfrom the Collision generated by Unity to extract all points(vertices) where the two meshes intersect and construct a new mesh from those points

    • This led me down the path of 3D Delaunay triangulation, which was too much for me to understand, probably too expensive like the CSG attempt, and I'm pretty sure there is a much simpler solution to this problem given that I'm just missing here.

Some Code

The shader I initially tried using(and which didn't work) was based off code from here: https://forum.unity.com/threads/depth-buffer-with-orthographic-camera.355878/#post-2302460

And applied to each of the objects.

With the float partY = i.projPos.y + (i.projPos.y/_ZBias); modified without the hard-coded _ZBias correction factor(and other color-related values slightly changed).

From my understanding, it should work since it seems to me like it's comparing the depth buffer and the actual depth of the object and only coloring it as the _HighlightColor when the two are sufficiently similar.

Of course, I know almost nothing about shaders, so I have little faith in my assessment of this code.

//Highlights intersections with other objects
Shader "Custom/IntersectionHighlights"
{
    Properties
    {
        _RegularColor("Main Color", Color) = (1, 1, 1, 0) //Color when not intersecting
        _HighlightColor("Highlight Color", Color) = (0, 0, 0, 1) //Color when intersecting
        _HighlightThresholdMax("Highlight Threshold Max", Float) = 1 //Max difference for intersections
        _ZBias("Highlight Z Bias", Float) = 2.5    //Balance out the Z-axis fading
    }
    SubShader
    {
        Tags { "Queue" = "Transparent" "RenderType"="Transparent"  }
        Pass
        {
            Blend SrcAlpha OneMinusSrcAlpha
            ZWrite Off
            Cull Off
            CGPROGRAM
            #pragma target 3.0
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"
            uniform sampler2D _CameraDepthTexture; //Depth Texture
            uniform float4 _RegularColor;
            uniform float4 _HighlightColor;
            uniform float _HighlightThresholdMax;
            uniform float _ZBias;
            struct v2f
            {
                float4 pos : SV_POSITION;
                float4 projPos : TEXCOORD1; //Screen position of pos
            };
            v2f vert(appdata_base v)
            {
                v2f o;
                o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
                o.projPos = ComputeScreenPos(o.pos);
                return o;
            }
            half4 frag(v2f i) : COLOR
            {
                float4 finalColor = _RegularColor;
                //Get the distance to the camera from the depth buffer for this point
                float sceneZ = tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos)).r * 400;

                //Actual distance to the camera
                float partY = i.projPos.y;// + (i.projPos.y/_ZBias);

                //If the two are similar, then there is an object intersecting with our object
                float diff = (abs(sceneZ - partY)) / _HighlightThresholdMax;
                if (diff <= 1)
                {
                    finalColor = _HighlightColor;
                }

                half4 c;
                c.r = finalColor.r;
                c.g = finalColor.g;
                c.b = finalColor.b;
                c.a = (diff<=1)? 1.0f: 0.0f;
                return c;
            }
            ENDCG
        }
    }
    FallBack "VertexLit"

The result of the (erroneous) code above is that the object always becomes transparent, regardless of whether or not it intersects the cone:

wrongresult

(The object is fully transparent even though it intersects the cone(pic taken from Scene View at runtime))

Ultimately it just seems to me like it comes back to shaders. How would I get around to achieving this effect? It doesn't necessarily have to be with shaders, anything that works is fine for me tbh. An example code would be great.

Allgood answered 30/7, 2019 at 14:3 Comment(0)
L
0

It looks like a stencil shadow (well done in Doom 3) where your plane is a geometry being shaded and volumes like sphere and cylinder are shadow volumes.

It is a multi-pass algorithm involving some stencil buffer math.

Lillian answered 28/11, 2023 at 19:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.