2024-02-02 12:54:47 +01:00
using System.Collections ;
using System.Collections.Generic ;
using UnityEngine ;
2024-02-07 20:26:35 +01:00
// giant mess of code that controlls the portal renderering effects
// !!! if this breaks please dont try fixing it yourself unless you know what your doing !!!
// if you do wanna try the comments may or may not help you
2024-02-02 12:54:47 +01:00
public class WorkingPortal : MonoBehaviour {
2024-02-07 20:26:35 +01:00
// the portal that this portal is linked to, as in the one that you see the view of when you look through this portal
2024-02-02 12:54:47 +01:00
public WorkingPortal linkedWorkingPortal ;
2024-02-07 20:26:35 +01:00
// the mesh renderer that the portal is rendered to.
2024-02-02 12:54:47 +01:00
public MeshRenderer screen ;
2024-02-07 20:26:35 +01:00
// something to do with skipping the render function, not sure exactly what the effects are yet
public bool visibleFromCamera = true ;
2024-02-02 12:54:47 +01:00
public GameObject myGameObject ;
2024-02-07 20:26:35 +01:00
// the view texture that this portals camera is rendered to, this is the view you see when looking through the other portal
2024-02-02 12:54:47 +01:00
public RenderTexture viewTexture ;
2024-02-07 20:26:35 +01:00
// the camera this portal uses for rendering
2024-02-05 18:34:22 +01:00
public Camera WorkingPortalCam ;
2024-02-07 20:26:35 +01:00
float nearClipOffset = 0.05f ;
float nearClipLimit = 0.2f ;
2024-02-02 12:54:47 +01:00
Camera playerCam ;
MeshFilter screenMeshFilter ;
void Awake ( ) {
2024-02-07 20:26:35 +01:00
// bit of jank code by me dont worry about it
2024-02-02 12:54:47 +01:00
myGameObject = gameObject ;
2024-02-07 20:26:35 +01:00
// stops our camera from always rendering, now we trigger it manuelly through the Render() function attached to it
2024-02-02 12:54:47 +01:00
WorkingPortalCam . enabled = false ;
screenMeshFilter = screen . GetComponent < MeshFilter > ( ) ;
2024-02-07 20:26:35 +01:00
// something to do with making the shader itself draw a solid color rather than the camera view
2024-02-02 12:54:47 +01:00
screen . material . SetInt ( "displayMask" , 1 ) ;
}
2024-02-07 20:26:35 +01:00
// does a bunch of stuff to render the view through this portal
2024-02-02 12:54:47 +01:00
public void Render ( Camera newplayerCam ) {
if ( ! visibleFromCamera ) {
return ;
}
2024-02-07 20:26:35 +01:00
playerCam = newplayerCam ;
2024-02-02 12:54:47 +01:00
CreateViewTexture ( ) ;
2024-02-07 20:26:35 +01:00
// listen i have no idea how the rest of this code actually works so take my comments with a grain of salt
// its something to do with moving the camera so what it sees lines up with what the player should see through the portal, then using screen space coordinates to make it so only the part...
// ... of the view covered by the portal actually gets rendered to the view texture
// this has all been heavily edited from the original to remove unneeded features
2024-02-02 12:54:47 +01:00
var localToWorldMatrix = playerCam . transform . localToWorldMatrix ;
2024-02-07 20:26:35 +01:00
var renderPosition = new Vector3 ( ) ;
var renderRotation = new Quaternion ( ) ;
2024-02-02 12:54:47 +01:00
WorkingPortalCam . projectionMatrix = playerCam . projectionMatrix ;
2024-02-07 20:26:35 +01:00
localToWorldMatrix = transform . localToWorldMatrix * linkedWorkingPortal . transform . worldToLocalMatrix * localToWorldMatrix ;
renderPosition = localToWorldMatrix . GetColumn ( 3 ) ;
renderRotation = localToWorldMatrix . rotation ;
2024-02-02 12:54:47 +01:00
// Hide screen so that camera can see through WorkingPortal
screen . shadowCastingMode = UnityEngine . Rendering . ShadowCastingMode . ShadowsOnly ;
2024-02-07 20:26:35 +01:00
linkedWorkingPortal . screen . material . SetInt ( "displayMask" , 1 ) ;
2024-02-02 12:54:47 +01:00
2024-02-07 20:26:35 +01:00
WorkingPortalCam . transform . SetPositionAndRotation ( renderPosition , renderRotation ) ;
SetNearClipPlane ( ) ;
WorkingPortalCam . Render ( ) ;
2024-02-02 12:54:47 +01:00
// 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 ;
}
}
}