166 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			166 lines
		
	
	
		
			6.3 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System.Collections.Generic;
 | |
| using _PROJECT.Components.Portals2;
 | |
| using Unity.XR.CoreUtils;
 | |
| using UnityEngine;
 | |
| using UnityEngine.Rendering;
 | |
| 
 | |
| #if (UNITY_EDITOR)
 | |
| using static UnityEditor.GameObjectUtility;
 | |
| #endif
 | |
| 
 | |
| public class PortalScene : MonoBehaviour
 | |
| {
 | |
|     private StencilPortal _portal;
 | |
|     private StencilPortal _targetPortal;
 | |
|     private PortalScene _targetPortalScene;
 | |
|     public LayerMask defaultLayer;
 | |
|     public LayerMask portalLayer;
 | |
|     public BoxCollider boxCollider;
 | |
|     private GameObject _skybox;
 | |
| 
 | |
| #if (UNITY_EDITOR)
 | |
|     public void BuildPortalScene()
 | |
|     {
 | |
|         _portal = transform.parent.GetComponentInChildren<StencilPortal>();
 | |
|         _targetPortal = _portal.targetPortal;
 | |
|         _targetPortalScene = _targetPortal.portalScene;
 | |
|         boxCollider = GetComponent<BoxCollider>();
 | |
|         _skybox = transform.Find("Skybox").gameObject;
 | |
| 
 | |
| 
 | |
|         // Make skybox size slightly smaller than collider
 | |
|         _skybox.transform.localScale = _targetPortalScene.boxCollider.bounds.size * 0.999f;
 | |
|         _skybox.transform.position =
 | |
|             _targetPortalScene.boxCollider.bounds.center + _targetPortal.normalVisible.forward * -0.001f;
 | |
| 
 | |
|         // Move skybox to this portal, but mirror the position
 | |
|         _skybox.transform.position =
 | |
|             StencilPortal.TransformPositionBetweenPortals(_targetPortal, _portal, _skybox.transform.position);
 | |
|         _skybox.transform.localRotation =
 | |
|             StencilPortal.TransformRotationBetweenPortals(_targetPortal, _portal, _skybox.transform.rotation);
 | |
| 
 | |
|         // Get all gameobjects in target portal collider
 | |
|         var gameObjects = _targetPortalScene.getAllCollisions(defaultLayer);
 | |
| 
 | |
|         // Clone all gameobjects found
 | |
|         var clonedGameObjects = CloneGameObjects(gameObjects, portalLayer);
 | |
| 
 | |
|         // Add normalVector rotation to portalScene
 | |
|         transform.rotation = transform.rotation * Quaternion.Inverse(_portal.normalVisible.rotation);
 | |
|     }
 | |
| 
 | |
|     private List<GameObject> getAllCollisions(LayerMask mask)
 | |
|     {
 | |
|         // Cast physics overlapbox
 | |
|         var colliders = Physics.OverlapBox(boxCollider.bounds.center, boxCollider.bounds.extents,
 | |
|             boxCollider.transform.rotation, mask);
 | |
| 
 | |
|         // Make list of all gameobjects
 | |
|         var gameObjects = new List<GameObject>();
 | |
|         foreach (var collider in colliders)
 | |
|         {
 | |
|             if (collider.gameObject.GetComponent<StencilPortal>()) continue;
 | |
|             if (collider.gameObject.GetComponent<PortalScene>()) continue;
 | |
|             gameObjects.Add(collider.gameObject);
 | |
|         }
 | |
| 
 | |
|         // Return list of gameobjects
 | |
|         return gameObjects;
 | |
|     }
 | |
| 
 | |
|     private List<GameObject> CloneGameObjects(List<GameObject> gameObjects, LayerMask targetMask)
 | |
|     {
 | |
|         // Make list of cloned gameobjects
 | |
|         var clonedGameObjects = new List<GameObject>();
 | |
|         foreach (var gameObject in gameObjects)
 | |
|         {
 | |
|             // Clone gameobject without static flag
 | |
|             var clonedGameObject = Instantiate(gameObject, transform);
 | |
|             clonedGameObject.isStatic = false;
 | |
| 
 | |
|             // Remove all children from cloned gameobject
 | |
|             foreach (Transform child in clonedGameObject.transform)
 | |
|             {
 | |
|                 DestroyImmediate(child.gameObject);
 | |
|             }
 | |
|             
 | |
|             var flags = GetStaticEditorFlags(gameObject);
 | |
|             SetStaticEditorFlags(clonedGameObject, flags);
 | |
| 
 | |
|             // Make sure mesh is not shared
 | |
|             var meshFilter = clonedGameObject.GetComponent<MeshFilter>();
 | |
|             if (meshFilter)
 | |
|             {
 | |
|                 meshFilter.mesh = Instantiate(meshFilter.sharedMesh);
 | |
|             }
 | |
| 
 | |
|             // Make sure material is not shared
 | |
|             var originalMeshRenderer = gameObject.GetComponent<MeshRenderer>();
 | |
|             
 | |
|             // Destroy cloned object if no mesh renderer is found
 | |
|             if (!originalMeshRenderer)
 | |
|             {
 | |
|                 DestroyImmediate(clonedGameObject);
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             var clonedMeshRenderer = clonedGameObject.GetComponent<MeshRenderer>();
 | |
|             if (clonedMeshRenderer)
 | |
|             {
 | |
|                 var materials = new Material[clonedMeshRenderer.sharedMaterials.Length];
 | |
|                 for (var i = 0; i < originalMeshRenderer.sharedMaterials.Length; i++)
 | |
|                 {
 | |
|                     materials[i] = Instantiate(originalMeshRenderer.sharedMaterials[i]);
 | |
|                 }
 | |
| 
 | |
|                 clonedMeshRenderer.materials = materials;
 | |
|             }
 | |
| 
 | |
|             // Remove collider if exists
 | |
|             var collider = clonedGameObject.GetComponent<Collider>();
 | |
|             if (collider)
 | |
|             {
 | |
|                 DestroyImmediate(collider);
 | |
|             }
 | |
| 
 | |
|             // Add LightmapDataSync component
 | |
|             // Check if lightmap data is available
 | |
|             if (originalMeshRenderer.lightmapIndex >= 0)
 | |
|             {
 | |
|                 var lightmapDataSync = clonedGameObject.AddComponent<LightmapDataSync>();
 | |
|                 // Set lightmap data
 | |
|                 lightmapDataSync.toCloneRenderer = originalMeshRenderer;
 | |
|             }
 | |
| 
 | |
|             // Check if blend probes are enabled on original gameobject
 | |
|             if (originalMeshRenderer.lightProbeUsage == LightProbeUsage.BlendProbes)
 | |
|             {
 | |
|                 // Use probes from original position
 | |
|                 clonedMeshRenderer.lightProbeUsage = LightProbeUsage.BlendProbes;
 | |
|                 clonedMeshRenderer.probeAnchor = originalMeshRenderer.transform;
 | |
|             }
 | |
| 
 | |
|             // Set position and rotation of cloned gameobject
 | |
|             clonedGameObject.transform.position =
 | |
|                 StencilPortal.TransformPositionBetweenPortals(_targetPortal, _portal, gameObject.transform.position);
 | |
|             
 | |
|             // Move slightly up
 | |
|             clonedGameObject.transform.position += _targetPortal.normalVisible.up * 0.002f;
 | |
|             clonedGameObject.transform.rotation =
 | |
|                 StencilPortal.TransformRotationBetweenPortals(_targetPortal, _portal, gameObject.transform.rotation);
 | |
| 
 | |
|             // Set layer of cloned gameobject to target layer
 | |
|             clonedGameObject.layer = targetMask.GetFirstLayerIndex();
 | |
| 
 | |
|             // Set parent of cloned gameobject to our portal scene
 | |
|             clonedGameObject.transform.parent = transform;
 | |
| 
 | |
|             // Add cloned gameobject to list
 | |
|             clonedGameObjects.Add(clonedGameObject);
 | |
|         }
 | |
| 
 | |
|         // Return list of cloned gameobjects
 | |
|         return clonedGameObjects;
 | |
|     }
 | |
| #endif
 | |
| } |