Looking-Glass/Assets/playerstuff/glass shader/WorkingPortal.cs

142 lines
5.7 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WorkingPortal : MonoBehaviour {
[Header ("Main Settings")]
public WorkingPortal linkedWorkingPortal;
public MeshRenderer screen;
public int recursionLimit = 5;
public bool visibleFromCamera = true;
[Header ("Advanced Settings")]
public float nearClipOffset = 0.05f;
public float nearClipLimit = 0.2f;
public GameObject myGameObject;
// Private variables
public RenderTexture viewTexture;
public Camera WorkingPortalCam;
Camera playerCam;
Material firstRecursionMat;
MeshFilter screenMeshFilter;
void Awake () {
myGameObject = gameObject;
WorkingPortalCam.enabled = false;
screenMeshFilter = screen.GetComponent<MeshFilter> ();
screen.material.SetInt ("displayMask", 1);
}
// Manually render the camera attached to this WorkingPortal
// Called after PreWorkingPortalRender, and before PostWorkingPortalRender
public void Render (Camera newplayerCam) {
playerCam = newplayerCam;
// Skip rendering the view from this WorkingPortal if player is not looking at the linked WorkingPortal
if (!visibleFromCamera) {
return;
}
CreateViewTexture ();
var localToWorldMatrix = playerCam.transform.localToWorldMatrix;
var renderPositions = new Vector3[recursionLimit];
var renderRotations = new Quaternion[recursionLimit];
int startIndex = 0;
WorkingPortalCam.projectionMatrix = playerCam.projectionMatrix;
for (int i = 0; i < recursionLimit; i++) {
if (i > 0) {
break;
}
localToWorldMatrix = transform.localToWorldMatrix * linkedWorkingPortal.transform.worldToLocalMatrix * localToWorldMatrix;
int renderOrderIndex = recursionLimit - i - 1;
renderPositions[renderOrderIndex] = localToWorldMatrix.GetColumn (3);
renderRotations[renderOrderIndex] = localToWorldMatrix.rotation;
WorkingPortalCam.transform.SetPositionAndRotation (renderPositions[renderOrderIndex], renderRotations[renderOrderIndex]);
startIndex = renderOrderIndex;
}
// Hide screen so that camera can see through WorkingPortal
screen.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.ShadowsOnly;
linkedWorkingPortal.screen.material.SetInt ("displayMask", 0);
for (int i = startIndex; i < recursionLimit; i++) {
WorkingPortalCam.transform.SetPositionAndRotation (renderPositions[i], renderRotations[i]);
Debug.Log(string.Format("rendering at: ", renderPositions[i].x, renderPositions[i].y, renderPositions[i].z));
SetNearClipPlane ();
WorkingPortalCam.Render ();
if (i == startIndex) {
linkedWorkingPortal.screen.material.SetInt ("displayMask", 1);
}
}
// Unhide objects hidden at start of render
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 WorkingPortal camera to the view texture
WorkingPortalCam.targetTexture = viewTexture;
// Display the view texture on the screen of the linked WorkingPortal
linkedWorkingPortal.screen.material.SetTexture ("_MainTex", viewTexture);
}
}
// Use custom projection matrix to align WorkingPortal camera's near clip plane with the surface of the WorkingPortal
// Note that this affects precision of the depth buffer, which can cause issues with effects like screenspace AO
void SetNearClipPlane () {
// Learning resource:
// http://www.terathon.com/lengyel/Lengyel-Oblique.pdf
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 WorkingPortal as it seems this can cause some visual artifacts
if (Mathf.Abs (camSpaceDst) > nearClipLimit) {
Vector4 clipPlaneCameraSpace = new Vector4 (camSpaceNormal.x, camSpaceNormal.y, camSpaceNormal.z, camSpaceDst);
// Update projection based on new clip plane
// Calculate matrix with player cam so that player camera settings (fov, etc) are used
WorkingPortalCam.projectionMatrix = playerCam.CalculateObliqueMatrix (clipPlaneCameraSpace);
} else {
WorkingPortalCam.projectionMatrix = playerCam.projectionMatrix;
}
}
/*
** Some helper/convenience stuff:
*/
int SideOfWorkingPortal (Vector3 pos) {
return System.Math.Sign (Vector3.Dot (pos - transform.position, transform.forward));
}
bool SameSideOfWorkingPortal (Vector3 posA, Vector3 posB) {
return SideOfWorkingPortal (posA) == SideOfWorkingPortal (posB);
}
Vector3 WorkingPortalCamPos {
get {
return WorkingPortalCam.transform.position;
}
}
void OnValidate () {
if (linkedWorkingPortal != null) {
linkedWorkingPortal.linkedWorkingPortal = this;
}
}
}