added portals
This commit is contained in:
@@ -1,223 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Unity.XR.CoreUtils;
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR;
|
||||
|
||||
public class Portal : MonoBehaviour
|
||||
{
|
||||
public bool allowRender;
|
||||
private bool _canRender;
|
||||
private bool _shouldRender = true;
|
||||
|
||||
public Portal targetPortal;
|
||||
public Transform normalVisible;
|
||||
public Transform normalInvisible;
|
||||
|
||||
public Camera portalLCamera;
|
||||
public Camera portalRCamera;
|
||||
|
||||
public Renderer viewThroughRenderer;
|
||||
|
||||
private RenderTexture _viewThroughRenderTextureL;
|
||||
private RenderTexture _viewThroughRenderTextureR;
|
||||
|
||||
private Material _viewThroughMaterial;
|
||||
|
||||
private Camera _mainCamera;
|
||||
private Vector4 _vectorPlane;
|
||||
|
||||
public bool _shouldTeleport;
|
||||
|
||||
private bool ShouldRender(Plane[] cameraPlanes) =>
|
||||
viewThroughRenderer.isVisible &&
|
||||
GeometryUtility.TestPlanesAABB(cameraPlanes,
|
||||
viewThroughRenderer.bounds);
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// Generate bounding plane
|
||||
var plane = new Plane(normalVisible.forward, transform.position + normalVisible.forward * -0.01f);
|
||||
_vectorPlane = new Vector4(plane.normal.x, plane.normal.y, plane.normal.z, plane.distance);
|
||||
|
||||
if (allowRender)
|
||||
{
|
||||
float scaleX = transform.localScale.x;
|
||||
float scaleY = transform.localScale.y;
|
||||
|
||||
// Create render texture
|
||||
_viewThroughRenderTextureL =
|
||||
new RenderTexture((1440), (1600), 24);
|
||||
_viewThroughRenderTextureL.Create();
|
||||
|
||||
_viewThroughRenderTextureR =
|
||||
new RenderTexture((1440), (1600), 24);
|
||||
_viewThroughRenderTextureR.Create();
|
||||
|
||||
|
||||
// Assign render texture to portal camera
|
||||
portalLCamera.targetTexture = _viewThroughRenderTextureL;
|
||||
portalRCamera.targetTexture = _viewThroughRenderTextureR;
|
||||
|
||||
// Assign render texture to portal material (cloned)
|
||||
_viewThroughMaterial = viewThroughRenderer.material;
|
||||
_viewThroughMaterial.SetTexture("_TexL", _viewThroughRenderTextureL);
|
||||
_viewThroughMaterial.SetTexture("_TexR", _viewThroughRenderTextureR);
|
||||
|
||||
// Cache the main camera
|
||||
_mainCamera = Camera.main;
|
||||
|
||||
Application.onBeforeRender += OnBeforeRender;
|
||||
_shouldTeleport = true;
|
||||
_canRender = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
portalLCamera.gameObject.SetActive(false);
|
||||
portalRCamera.gameObject.SetActive(false);
|
||||
viewThroughRenderer.enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBeforeRender()
|
||||
{
|
||||
if (!_canRender) return;
|
||||
var cameraPlanes = GeometryUtility.CalculateFrustumPlanes(_mainCamera);
|
||||
if (!ShouldRender(cameraPlanes))
|
||||
{
|
||||
if (!_shouldRender) return;
|
||||
Debug.Log("Disabling render for " + transform.name);
|
||||
viewThroughRenderer.material = new Material(Shader.Find("Unlit/Color"));
|
||||
portalLCamera.enabled = false;
|
||||
portalRCamera.enabled = false;
|
||||
_shouldRender = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_shouldRender)
|
||||
{
|
||||
Debug.Log("Enabling render for " + transform.name);
|
||||
viewThroughRenderer.material = _viewThroughMaterial;
|
||||
portalLCamera.enabled = true;
|
||||
portalRCamera.enabled = true;
|
||||
_shouldRender = true;
|
||||
}
|
||||
|
||||
UpdateCamera(portalLCamera, XRNode.LeftEye);
|
||||
UpdateCamera(portalRCamera, XRNode.RightEye);
|
||||
}
|
||||
|
||||
private void UpdateCamera(Camera portalCamera, XRNode eye)
|
||||
{
|
||||
// Calculate portal camera position and rotation
|
||||
var virtualPosition = TransformPositionBetweenPortals(this, targetPortal, GetEyeWorldPosition(eye));
|
||||
var virtualRotation = TransformRotationBetweenPortals(this, targetPortal, GetEyeRotation(eye));
|
||||
|
||||
// Position camera
|
||||
portalCamera.transform.SetPositionAndRotation(virtualPosition, virtualRotation);
|
||||
|
||||
// Calculate projection matrix
|
||||
var clipThroughSpace = Matrix4x4.Transpose(Matrix4x4.Inverse(portalCamera.worldToCameraMatrix)) *
|
||||
targetPortal._vectorPlane;
|
||||
|
||||
// Set portal camera projection matrix to clip walls between target portal and portal camera
|
||||
// Inherits main camera near/far clip plane and FOV settings
|
||||
portalCamera.projectionMatrix =
|
||||
CalculateObliqueMatrix(
|
||||
_mainCamera.GetStereoProjectionMatrix(eye == XRNode.LeftEye
|
||||
? Camera.StereoscopicEye.Left
|
||||
: Camera.StereoscopicEye.Right), clipThroughSpace);
|
||||
}
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (!_canRender) return;
|
||||
Application.onBeforeRender -= OnBeforeRender;
|
||||
// Release render texture from GPU
|
||||
_viewThroughRenderTextureL.Release();
|
||||
_viewThroughRenderTextureR.Release();
|
||||
|
||||
|
||||
// Destroy cloned material and render texture
|
||||
Destroy(_viewThroughMaterial);
|
||||
Destroy(_viewThroughRenderTextureL);
|
||||
Destroy(_viewThroughRenderTextureR);
|
||||
}
|
||||
|
||||
|
||||
private static Vector3 TransformPositionBetweenPortals(Portal sender, Portal target, Vector3 position)
|
||||
{
|
||||
return
|
||||
target.normalInvisible.TransformPoint(
|
||||
sender.normalVisible.InverseTransformPoint(position));
|
||||
}
|
||||
|
||||
private static Quaternion TransformRotationBetweenPortals(Portal sender, Portal target, Quaternion rotation)
|
||||
{
|
||||
return
|
||||
target.normalInvisible.rotation *
|
||||
Quaternion.Inverse(sender.normalVisible.rotation) *
|
||||
rotation;
|
||||
}
|
||||
|
||||
private Vector3 GetEyeWorldPosition(XRNode eye)
|
||||
{
|
||||
if (!XRSettings.enabled) return _mainCamera.transform.position;
|
||||
|
||||
InputDevice device = InputDevices.GetDeviceAtXRNode(eye);
|
||||
|
||||
if (!device.isValid) return default;
|
||||
|
||||
float cameraSeparation = _mainCamera.stereoSeparation;
|
||||
|
||||
return _mainCamera.transform.position + _mainCamera.transform.right *
|
||||
(eye == XRNode.LeftEye ? -cameraSeparation : cameraSeparation) / 2;
|
||||
}
|
||||
|
||||
private Quaternion GetEyeRotation(XRNode _)
|
||||
{
|
||||
return _mainCamera.transform.rotation;
|
||||
}
|
||||
|
||||
static Matrix4x4 CalculateObliqueMatrix(Matrix4x4 projection, Vector4 clipPlane)
|
||||
{
|
||||
Matrix4x4 obliqueMatrix = projection;
|
||||
Vector4 q = projection.inverse * new Vector4(
|
||||
Math.Sign(clipPlane.x),
|
||||
Math.Sign(clipPlane.y),
|
||||
1.0f,
|
||||
1.0f
|
||||
);
|
||||
Vector4 c = clipPlane * (2.0F / (Vector4.Dot(clipPlane, q)));
|
||||
obliqueMatrix[2] = c.x - projection[3];
|
||||
obliqueMatrix[6] = c.y - projection[7];
|
||||
obliqueMatrix[10] = c.z - projection[11];
|
||||
obliqueMatrix[14] = c.w - projection[15];
|
||||
return obliqueMatrix;
|
||||
}
|
||||
|
||||
private void OnTriggerEnter(Collider other)
|
||||
{
|
||||
if (!_canRender || !_shouldTeleport) return;
|
||||
if (!other.CompareTag("Player")) return;
|
||||
Debug.Log(transform.name + " player entered and should teleport");
|
||||
targetPortal._shouldTeleport = false;
|
||||
// Move player to target portal collider relative position
|
||||
other.transform.position = TransformPositionBetweenPortals(this, targetPortal, other.transform.position);
|
||||
other.transform.rotation = TransformRotationBetweenPortals(this, targetPortal, other.transform.rotation);
|
||||
}
|
||||
|
||||
private void OnTriggerExit(Collider other)
|
||||
{
|
||||
if (!_canRender || !_shouldTeleport || IsInvoking(nameof(AllowTeleport))) return;
|
||||
if (!other.CompareTag("Player")) return;
|
||||
Debug.Log(transform.name + " player exited");
|
||||
Invoke(nameof(AllowTeleport), 1f);
|
||||
}
|
||||
|
||||
private void AllowTeleport()
|
||||
{
|
||||
_shouldTeleport = true;
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9cc1c8f52cb11d142b26f98158580b66
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user