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(); _targetPortal = _portal.targetPortal; _targetPortalScene = _targetPortal.portalScene; boxCollider = GetComponent(); _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 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(); foreach (var collider in colliders) { if (collider.gameObject.GetComponent()) continue; if (collider.gameObject.GetComponent()) continue; gameObjects.Add(collider.gameObject); } // Return list of gameobjects return gameObjects; } private List CloneGameObjects(List gameObjects, LayerMask targetMask) { // Make list of cloned gameobjects var clonedGameObjects = new List(); 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(); if (meshFilter) { meshFilter.mesh = Instantiate(meshFilter.sharedMesh); } // Make sure material is not shared var originalMeshRenderer = gameObject.GetComponent(); // Destroy cloned object if no mesh renderer is found if (!originalMeshRenderer) { DestroyImmediate(clonedGameObject); continue; } var clonedMeshRenderer = clonedGameObject.GetComponent(); 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(); if (collider) { DestroyImmediate(collider); } // Add LightmapDataSync component // Check if lightmap data is available if (originalMeshRenderer.lightmapIndex >= 0) { var lightmapDataSync = clonedGameObject.AddComponent(); // 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 }