Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Showcase Improved portal rendering script - Non Euclidean effect

Discussion in 'Scripting' started by Meaningless-Trinket, Dec 21, 2020.

  1. Meaningless-Trinket

    Meaningless-Trinket

    Joined:
    Apr 25, 2020
    Posts:
    83
    I made an improved portal rendering switch script.

    This is for sectors and portals that overlap in 3D space.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Rendering;
    3.  
    4. public class PortalSwitch : MonoBehaviour
    5. {
    6.  
    7.     public GameObject Sector;
    8.  
    9.     public int NextSector;
    10.  
    11.     public int LastSector;
    12.  
    13.     public float PortalDistance = 0.7f;
    14.  
    15.     public GameObject[] AddPortals;
    16.  
    17.     public GameObject[] RemovePortals;
    18.  
    19.     private Material[] SectorMaterials;
    20.  
    21.     private Plane portalPlane;
    22.  
    23.     private GameObject Player;
    24.  
    25.     void Start()
    26.     {
    27.         Player = GameObject.FindWithTag("Player");
    28.         Mesh portalMesh = GetComponent<MeshFilter>().sharedMesh;
    29.         Vector3[] normals = portalMesh.normals;
    30.         for (int i = 0; i < normals.Length; ++i)
    31.         {
    32.             portalPlane.SetNormalAndPosition(transform.TransformDirection(normals[i]), transform.position);
    33.         }
    34.         SectorMaterials = Sector.GetComponent<Renderer>().sharedMaterials;
    35.         for (int i = 0; i < SectorMaterials.Length; ++i)
    36.         {
    37.             SectorMaterials[i].SetInt("_SectorComp", (int)CompareFunction.Equal);
    38.         }
    39.     }
    40.     void OnTriggerStay(Collider other)
    41.     {
    42.         if (portalPlane.GetDistanceToPoint(Camera.main.transform.position) < PortalDistance)
    43.         {
    44.             Player.gameObject.layer = NextSector;
    45.             for (int i = 0; i < SectorMaterials.Length; ++i)
    46.             {
    47.                 SectorMaterials[i].SetInt("_SectorComp", (int)CompareFunction.Always);
    48.             }
    49.             for (int i = 0; i < AddPortals.Length; ++i)
    50.             {
    51.                 AddPortals[i].GetComponent<Renderer>().enabled = true;
    52.             }
    53.             for (int i = 0; i < RemovePortals.Length; ++i)
    54.             {
    55.                 RemovePortals[i].GetComponent<Renderer>().enabled = false;
    56.             }
    57.         }
    58.         else
    59.         {
    60.             Player.gameObject.layer = LastSector;
    61.             for (int i = 0; i < SectorMaterials.Length; ++i)
    62.             {
    63.                 SectorMaterials[i].SetInt("_SectorComp", (int)CompareFunction.Equal);
    64.             }
    65.             for (int i = 0; i < AddPortals.Length; ++i)
    66.             {
    67.                 AddPortals[i].GetComponent<Renderer>().enabled = false;
    68.             }
    69.             for (int i = 0; i < RemovePortals.Length; ++i)
    70.             {
    71.                 RemovePortals[i].GetComponent<Renderer>().enabled = true;
    72.             }
    73.         }
    74.     }
    75.     void OnDestroy()
    76.     {
    77.         for (int i = 0; i < SectorMaterials.Length; ++i)
    78.         {
    79.             SectorMaterials[i].SetInt("_SectorComp", (int)CompareFunction.Equal);
    80.         }
    81.     }
    82. }
    83.  

    The PortalSwitch script attaches to a 2D portal game object.

    When entering a portal the player's layer switches to the layer of the new sector.

    The sector changes from portal rendering to normal rendering when the player is inside the sector.

    Portals render the other sectors and each sector can be a different layer.

    Layers can be changed to not interact with other layers in the project settings.

    When entering or exiting a portal, a portal's mesh renderer can be turned on or off.

    Each portal can be a different layer.

    If you need to render more than one sector in one spot then two or more portals can be put together.

    Portal shader for quad game objects.

    Code (CSharp):
    1. Shader "Custom/Portal"
    2. {
    3.     Properties
    4.     {
    5.         [IntRange] _PortalRef("Portal Ref Number", Range(0,255)) = 0
    6.     }
    7.         SubShader
    8.     {
    9.         Tags { "RenderType" = "Opaque" "Queue" = "Geometry-1"}
    10.  
    11.         Stencil
    12.         {
    13.             Ref[_PortalRef]
    14.             Comp Always
    15.             Pass Replace
    16.         }
    17.  
    18.         Pass
    19.         {
    20.             Blend Zero One
    21.             ZWrite Off
    22.         }
    23.     }
    24. }
    25.  

    Sector shader for sector game objects.

    Code (CSharp):
    1. Shader "Custom/Sector"
    2. {
    3.     Properties
    4.     {
    5.         _Color("Color", Color) = (1,1,1,1)
    6.         _MainTex("Albedo (RGB)", 2D) = "white" {}
    7.         _Glossiness("Smoothness", Range(0,1)) = 0.5
    8.         _Metallic("Metallic", Range(0,1)) = 0.0
    9.         [HDR] _Emission("Emission", color) = (0,0,0)
    10.         [Enum(Equal,3,Always,8)] _SectorComp("Sector Comp", int) = 3
    11.         [IntRange] _SectorRef("Sector Ref Number", Range(0,255)) = 0
    12.     }
    13.         SubShader
    14.         {
    15.             Tags { "RenderType" = "Opaque" }
    16.             LOD 300
    17.  
    18.             Stencil
    19.             {
    20.                 Ref[_SectorRef]
    21.                 Comp[_SectorComp]
    22.             }
    23.  
    24.             CGPROGRAM
    25.             // Physically based Standard lighting model, and enable shadows on all light types
    26.             #pragma surface surf Standard fullforwardshadows
    27.  
    28.             // Use shader model 3.0 target, to get nicer looking lighting
    29.             #pragma target 3.0
    30.  
    31.             sampler2D _MainTex;
    32.  
    33.             struct Input
    34.             {
    35.                 float2 uv_MainTex;
    36.             };
    37.  
    38.             half _Glossiness;
    39.             half _Metallic;
    40.             fixed4 _Color;
    41.             half3 _Emission;
    42.  
    43.             // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader.
    44.             // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing.
    45.             // #pragma instancing_options assumeuniformscaling
    46.             UNITY_INSTANCING_BUFFER_START(Props)
    47.                 // put more per-instance properties here
    48.             UNITY_INSTANCING_BUFFER_END(Props)
    49.  
    50.             void surf(Input IN, inout SurfaceOutputStandard o)
    51.             {
    52.                 // Albedo comes from a texture tinted by color
    53.                 fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    54.                 o.Albedo = c.rgb;
    55.                 // Metallic and smoothness come from slider variables
    56.                 o.Metallic = _Metallic;
    57.                 o.Smoothness = _Glossiness;
    58.                 o.Alpha = c.a;
    59.                 o.Emission = _Emission * tex2D(_MainTex, IN.uv_MainTex);
    60.             }
    61.             ENDCG
    62.         }
    63.             FallBack "Diffuse"
    64. }
    65.  

    This video shows how it works.

     
    Last edited: Dec 21, 2020
    TheDuples likes this.