119 lines
4.9 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|