Looking-Glass/Assets/playerstuff/glass shader/WorkingPortal.cs
2024-03-10 22:31:45 +00:00

119 lines
4.9 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// This class manages the rendering effects of portals.
// !!! Caution: Modifying this code without proper understanding may lead to unintended consequences. !!!
public class WorkingPortal : MonoBehaviour {
// The portal that this portal is linked to; the one whose view is seen when looking through this portal.
public WorkingPortal linkedWorkingPortal;
// The mesh renderer that renders the portal.
public MeshRenderer screen;
// Determines if the portal is visible from the camera.
public bool visibleFromCamera = true;
public GameObject myGameObject;
// The render texture that this portal's camera renders to, providing the view when looking through the linked portal.
public RenderTexture viewTexture;
// The camera used for rendering this portal.
public Camera WorkingPortalCam;
// Offset values for adjusting the near clipping plane.
float nearClipOffset = 0.05f;
float nearClipLimit = 0.2f;
// Reference to the player's camera.
Camera playerCam;
// Mesh filter of the portal's screen.
MeshFilter screenMeshFilter;
void Awake () {
// Set reference to this GameObject.
myGameObject = gameObject;
// Disable camera rendering by default; rendering is triggered manually via the Render() function.
WorkingPortalCam.enabled = false;
// Retrieve the mesh filter component of the portal screen.
screenMeshFilter = screen.GetComponent<MeshFilter> ();
// Set the display mask to render solid color instead of the camera view.
screen.material.SetInt ("displayMask", 1);
}
// Renders the view through this portal.
public void Render (Camera newplayerCam) {
if (!visibleFromCamera) {
return;
}
playerCam = newplayerCam;
CreateViewTexture ();
// This section aligns the portal camera with the player's view and renders only the portion visible through the portal.
var localToWorldMatrix = playerCam.transform.localToWorldMatrix;
var renderPosition = new Vector3();
var renderRotation = new Quaternion();
WorkingPortalCam.projectionMatrix = playerCam.projectionMatrix;
localToWorldMatrix = transform.localToWorldMatrix * linkedWorkingPortal.transform.worldToLocalMatrix * localToWorldMatrix;
renderPosition = localToWorldMatrix.GetColumn (3);
renderRotation = localToWorldMatrix.rotation;
// Hide the portal screen to allow camera to see through it.
screen.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly;
linkedWorkingPortal.screen.material.SetInt ("displayMask", 1);
WorkingPortalCam.transform.SetPositionAndRotation (renderPosition, renderRotation);
SetNearClipPlane ();
WorkingPortalCam.Render ();
// Revert hiding objects that were hidden at the start of rendering.
screen.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On;
}
void CreateViewTexture () {
if (viewTexture == null || viewTexture.width != Screen.width || viewTexture.height != Screen.height) {
if (viewTexture != null) {
viewTexture.Release ();
}
viewTexture = new RenderTexture (Screen.width, Screen.height, 0);
// Render the view from the portal camera to the view texture.
WorkingPortalCam.targetTexture = viewTexture;
// Display the view texture on the screen of the linked portal.
linkedWorkingPortal.screen.material.SetTexture ("_MainTex", viewTexture);
}
}
// Adjusts the near clipping plane to align with the surface of the portal.
void SetNearClipPlane () {
Transform clipPlane = transform;
int dot = System.Math.Sign (Vector3.Dot (clipPlane.forward, transform.position - WorkingPortalCam.transform.position));
Vector3 camSpacePos = WorkingPortalCam.worldToCameraMatrix.MultiplyPoint (clipPlane.position);
Vector3 camSpaceNormal = WorkingPortalCam.worldToCameraMatrix.MultiplyVector (clipPlane.forward) * dot;
float camSpaceDst = -Vector3.Dot (camSpacePos, camSpaceNormal) + nearClipOffset;
// Don't use oblique clip plane if very close to the portal as it may cause visual artifacts.
if (Mathf.Abs (camSpaceDst) > nearClipLimit) {
Vector4 clipPlaneCameraSpace = new Vector4 (camSpaceNormal.x, camSpaceNormal.y, camSpaceNormal.z, camSpaceDst);
// Update projection based on the new clip plane.
// Calculate matrix with player cam to use its settings (e.g., fov).
WorkingPortalCam.projectionMatrix = playerCam.CalculateObliqueMatrix (clipPlaneCameraSpace);
} else {
// Use default projection matrix if very close to the portal.
WorkingPortalCam.projectionMatrix = playerCam.projectionMatrix;
}
}
}