81 lines
3.1 KiB
C#
81 lines
3.1 KiB
C#
using System;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering;
|
|
using UnityEngine.Rendering.Universal;
|
|
|
|
namespace Escape_Room_Engine.Portal
|
|
{
|
|
public class Portal : MonoBehaviour
|
|
{
|
|
private static readonly Matrix4x4 HalfRotation = Matrix4x4.Rotate(Quaternion.Euler(0, 180, 0));
|
|
|
|
/// <summary>
|
|
/// The portal that is connected with this one.
|
|
/// </summary>
|
|
public Portal other;
|
|
/// <summary>
|
|
/// The main camera to take the position for the portal camera from.
|
|
/// </summary>
|
|
[SerializeField] private Camera playerCamera;
|
|
/// <summary>
|
|
/// The camera that will draw the view for this portal.
|
|
/// </summary>
|
|
[SerializeField] private Camera portalCamera;
|
|
/// <summary>
|
|
/// The quad where the rendered texture will be drawn on.
|
|
/// </summary>
|
|
[SerializeField] private MeshRenderer portalQuad;
|
|
|
|
private RenderTexture _texture;
|
|
|
|
private void Awake()
|
|
{
|
|
// check whether the other portal is set up
|
|
if (!other || other.other != this) throw new Exception("Other Portal not set up correctly.");
|
|
// check whether the player camera is set up
|
|
if (!playerCamera) throw new Exception("No camera initialised.");
|
|
|
|
// create render texture
|
|
_texture = new RenderTexture(Screen.width, Screen.height, 24, RenderTextureFormat.ARGB32);
|
|
}
|
|
|
|
private void Start()
|
|
{
|
|
// assign render texture
|
|
portalCamera.targetTexture = _texture;
|
|
other.portalQuad.material.mainTexture = _texture;
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
RenderPipelineManager.beginCameraRendering += Render;
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
RenderPipelineManager.beginCameraRendering -= Render;
|
|
}
|
|
|
|
private void Render(ScriptableRenderContext scriptableRenderContext, Camera camera)
|
|
{
|
|
var t = transform;
|
|
|
|
// position portal camera
|
|
var portalCameraMatrix = t.localToWorldMatrix * HalfRotation * other.transform.worldToLocalMatrix *
|
|
playerCamera.transform.localToWorldMatrix;
|
|
portalCamera.transform.SetPositionAndRotation(portalCameraMatrix.GetPosition(), portalCameraMatrix.rotation);
|
|
|
|
// set camera clip plane to portal (otherwise the wall behind the portal would be rendered)
|
|
// calculating the clip plane: https://computergraphics.stackexchange.com/a/1506
|
|
var n = -t.forward; // clip plane normal
|
|
var portalPlane = new Plane(n, t.position); // clip plane in world space
|
|
var clipPlane = portalCamera.worldToCameraMatrix.inverse.transpose *
|
|
new Vector4(n.x, n.y, n.z, portalPlane.distance); // vector format clip plane in camera space
|
|
portalCamera.projectionMatrix = playerCamera.CalculateObliqueMatrix(clipPlane);
|
|
|
|
// render portal view
|
|
UniversalRenderPipeline.RenderSingleCamera(scriptableRenderContext, portalCamera);
|
|
}
|
|
}
|
|
}
|