1
votes

I'm trying to implement portals in Unity. The way I'm doing it is having a camera mimic the player's position and rotation in the other portals local space. My problem is, that whatever is behind the portal gets rendered on this camera, so if I move back from the portal, some other stuff will clip in. I've made a shader that's supposed to add a clipping plane, but it seems it's either clipping everything or nothing:

Shader "Hidden/ClipPlaneShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _PlaneNormal("PlaneNormal",Vector) = (0,1,0,0)
        _PlanePosition("PlanePosition",Vector) = (0,0.5,0,0)
    }
    SubShader
    {
        // No culling or depth
        Cull Off ZWrite Off ZTest Always

        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct v2f
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
                float clip : SV_ClipDistance0;
            };          

            float4 _PlaneNormal;
            float4 _PlanePosition;

            v2f vert (appdata v)
            {           
                float4 worldPos = mul(unity_ObjectToWorld, v.vertex);

                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;                                
                o.clip = dot(worldPos - _PlanePosition, _PlaneNormal);

                return o;
            }

            sampler2D _MainTex;            

            fixed4 frag (v2f i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);             
                return col;
            }   
            ENDCG
        }
    }
}

I'm adding it to the camera via this script, but I don't know if that's the best way to do it:

private void OnRenderImage(RenderTexture src, RenderTexture dest)
{       
    _material.SetVector("_PlanePosition", planePosition);
    _material.SetVector("_PlaneNormal", planeNormal);
    Graphics.Blit(src, dest, _material);
}

Can anyone see what I'm doing wrong?

EDIT: The Portal guys called this problem 'banana juice' and they explain it in this video: https://youtu.be/ivyseNMVt-4?t=1064

I've tried drawning a nice picture here: https://imgur.com/9Dc57Pm

The eye on the left is the player, and the eye on the right is my portal camera. The portal camera should only render what's beneath the yellow line (the clip plane), but it also renders the box, so it ends up looking weird for the player.

EDIT^2: i think I've found a problem in using the OnRenderImage() function to apply my material. That's a 2D texture.

How do i apply the shader to all objects in the scene?

1
I think using the dot product might be the wrong approach, but I'm also not confident i fully understand your problem. Do you have any screenshots you could show? Or maybe you could draw out a top-down sketch of your scene and explain on that whats happening.Adam Stox
I've tried describing the problem a little better and added a picture and video.Boz0r

1 Answers

0
votes

dunno if it's still relevant but the only easy way to "apply" a shader to every object in the scene is Camera.RenderWithShader:

https://docs.unity3d.com/ScriptReference/Camera.RenderWithShader.html