split into multiple assemblies

This commit is contained in:
2022-11-20 12:52:22 +01:00
parent def03954a0
commit 9fdfafc3eb
373 changed files with 380 additions and 119 deletions

View File

@@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
using UnityEngine.XR;
namespace EscapeRoomEngine.Portal.Runtime
{
[RequireComponent(typeof(Camera))]
public class PortalCamera : MonoBehaviour
{
private static readonly Camera.StereoscopicEye[] Eyes =
{ Camera.StereoscopicEye.Left, Camera.StereoscopicEye.Right };
private static readonly Dictionary<Camera.StereoscopicEye, int> EyeTextureNames = new()
{
{ Camera.StereoscopicEye.Left, Shader.PropertyToID("_LeftTex") },
{ Camera.StereoscopicEye.Right, Shader.PropertyToID("_RightTex") }
};
/// <summary>
/// The minimum near clip plane distance to be used when calculating the oblique clip plane.
/// </summary>
public float minNearClipPlane = 0.0001f;
/// <summary>
/// The portal this camera renders through.
/// </summary>
[SerializeField] private Portal portal;
/// <summary>
/// The mesh where the rendered texture will be drawn on.
/// </summary>
[SerializeField] private MeshRenderer screen;
private PlayerCamera _playerCamera;
private Camera _camera;
private readonly Dictionary<Camera.StereoscopicEye, RenderTexture> _textures = new();
private void Awake()
{
// get player camera
if (Camera.main != null) _playerCamera = Camera.main.GetComponent<PlayerCamera>();
else throw new Exception("Main camera has no player camera script set up.");
// get portal camera
_camera = GetComponent<Camera>();
}
private void OnEnable()
{
RenderPipelineManager.beginCameraRendering += Render;
}
private void OnDisable()
{
RenderPipelineManager.beginCameraRendering -= Render;
}
private void Render(ScriptableRenderContext scriptableRenderContext, Camera _)
{
// check whether the portal plane is visible from the player camera
var frustumPlanes = GeometryUtility.CalculateFrustumPlanes(_playerCamera.camera);
if (!GeometryUtility.TestPlanesAABB(frustumPlanes, portal.linkedPortal.portalCamera.screen.bounds))
// don't render this portal if it is not visible
return;
var t = portal.transform;
screen.enabled = false;
foreach (var eye in Eyes)
{
// create portal texture if it doesn't exist yet
if (!_textures.ContainsKey(eye))
{
if (XRSettings.eyeTextureWidth > 0 && XRSettings.eyeTextureHeight > 0)
{
_textures.Add(eye,
new RenderTexture(XRSettings.eyeTextureWidth, XRSettings.eyeTextureHeight, 24));
portal.linkedPortal.portalCamera.screen.material.SetTexture(EyeTextureNames[eye], _textures[eye]);
}
else // no texture was created so nothing should be rendered
continue;
}
// position portal camera
var m = t.localToWorldMatrix * Portal.HalfRotation * portal.linkedPortal.transform.worldToLocalMatrix *
_playerCamera.GetEyeTransform(eye).localToWorldMatrix;
transform.SetPositionAndRotation(m.GetPosition(), m.rotation);
_camera.projectionMatrix = _playerCamera.camera.GetStereoProjectionMatrix(eye);
// 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 = _camera.worldToCameraMatrix.inverse.transpose *
new Vector4(n.x, n.y, n.z, portalPlane.distance); // vector format clip plane in camera space
if (-portalPlane.GetDistanceToPoint(transform.position) >= minNearClipPlane)
// only adjust the near clip plane if it doesn't intersect with the camera
_camera.projectionMatrix = _camera.CalculateObliqueMatrix(clipPlane);
// render portal view
_camera.targetTexture = _textures[eye];
UniversalRenderPipeline.RenderSingleCamera(scriptableRenderContext, _camera);
}
screen.enabled = true;
}
}
}