non-VR portal rendering

This commit is contained in:
2022-10-07 20:29:23 +02:00
parent 59abc4b6f7
commit c561d617af
11 changed files with 468 additions and 159 deletions

View File

@@ -1,10 +1,14 @@
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>
@@ -12,25 +16,65 @@ namespace Escape_Room_Engine.Portal
/// <summary>
/// The main camera to take the position for the portal camera from.
/// </summary>
[SerializeField] private Transform playerCamera;
[SerializeField] private Camera playerCamera;
/// <summary>
/// The camera that will draw the view for this portal.
/// </summary>
[SerializeField] private Transform portalCamera;
[SerializeField] private Camera portalCamera;
/// <summary>
/// The quad where the rendered texture will be drawn on.
/// </summary>
[SerializeField] private MeshRenderer portalQuad;
private void Start()
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 Update()
private void Start()
{
var portalCameraMatrix = transform.localToWorldMatrix * other.transform.worldToLocalMatrix *
playerCamera.localToWorldMatrix;
portalCamera.SetPositionAndRotation(portalCameraMatrix.GetPosition(), portalCameraMatrix.rotation);
// 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);
}
}
}