Initial commit
This commit is contained in:
@@ -0,0 +1,523 @@
|
||||
using Fragilem17.MirrorsAndPortals;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Fragilem17.MirrorsAndPortals
|
||||
{
|
||||
public class CloneRenderer : MonoBehaviour
|
||||
{
|
||||
[Tooltip("Leave empty to target this gameObject")]
|
||||
public GameObject GameObjectToClone;
|
||||
|
||||
protected static GameObject _cloneHolder;
|
||||
protected static List<GameObject> _clones;
|
||||
protected GameObject _clone;
|
||||
|
||||
protected static readonly Quaternion halfTurn = Quaternion.Euler(0.0f, 180.0f, 0.0f);
|
||||
|
||||
protected Dictionary<Transform, Transform> _tranforms = new Dictionary<Transform, Transform>();
|
||||
//protected Dictionary<Rigidbody, Rigidbody> _rigidbodies = new Dictionary<Rigidbody, Rigidbody>();
|
||||
//public Dictionary<Collider, Collider> Colliders = new Dictionary<Collider, Collider>();
|
||||
protected Dictionary<MeshRenderer, MeshRenderer> _meshRenderers = new Dictionary<MeshRenderer, MeshRenderer>();
|
||||
protected Dictionary<MeshRenderer, MeshFilter> _meshFilters = new Dictionary<MeshRenderer, MeshFilter>();
|
||||
|
||||
protected Dictionary<SkinnedMeshRenderer, MeshRenderer> _skinnedMeshRenderers = new Dictionary<SkinnedMeshRenderer, MeshRenderer>();
|
||||
protected Dictionary<SkinnedMeshRenderer, MeshFilter> _skinnedMeshRendererFilters = new Dictionary<SkinnedMeshRenderer, MeshFilter>();
|
||||
protected Dictionary<SkinnedMeshRenderer, Mesh> _skinnedMeshRendererMeshes = new Dictionary<SkinnedMeshRenderer, Mesh>();
|
||||
|
||||
protected Portal _inPortal;
|
||||
|
||||
protected Transform _inTransform;
|
||||
protected Transform _outTransform;
|
||||
|
||||
/*public bool CloneColliders = false;
|
||||
public bool CloneRigidbodies = false;
|
||||
|
||||
public bool DisableClonedCollidersAtStart = true;
|
||||
*/
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
if (GameObjectToClone == null)
|
||||
{
|
||||
GameObjectToClone = gameObject;
|
||||
}
|
||||
GenerateClone();
|
||||
_clone.SetActive(false);
|
||||
|
||||
}
|
||||
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
DestroyClone();
|
||||
}
|
||||
|
||||
protected virtual void OnDestroy()
|
||||
{
|
||||
DestroyClone();
|
||||
}
|
||||
|
||||
protected virtual void DestroyClone()
|
||||
{
|
||||
if (_clones != null)
|
||||
{
|
||||
_clones.Remove(_clone);
|
||||
}
|
||||
|
||||
if (_clones.Count == 0 || !_cloneHolder)
|
||||
{
|
||||
// destroy the holder
|
||||
DestroyImmediate(_cloneHolder);
|
||||
_cloneHolder = null;
|
||||
}
|
||||
|
||||
_meshRenderers.Clear();
|
||||
_meshFilters.Clear();
|
||||
_skinnedMeshRenderers.Clear();
|
||||
_skinnedMeshRendererMeshes.Clear();
|
||||
//_rigidbodies.Clear();
|
||||
//Colliders.Clear();
|
||||
|
||||
if (_clone)
|
||||
{
|
||||
DestroyImmediate(_clone);
|
||||
_clone = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected virtual void GenerateClone()
|
||||
{
|
||||
if (!_cloneHolder)
|
||||
{
|
||||
_cloneHolder = new GameObject();
|
||||
_cloneHolder.transform.SetParent(null);
|
||||
_cloneHolder.hideFlags = HideFlags.DontSave;
|
||||
_cloneHolder.name = "Portal ClonesHolder";
|
||||
_clones = new List<GameObject>();
|
||||
}
|
||||
|
||||
if (!_clone)
|
||||
{
|
||||
_clone = new GameObject();
|
||||
_clones.Add(_clone);
|
||||
_clone.hideFlags = HideFlags.DontSave;
|
||||
_clone.name = "clone_" + name;
|
||||
_clone.layer = gameObject.layer;
|
||||
CreateMeshrendererChildren(_clone, GameObjectToClone, _cloneHolder.transform);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void CreateMeshrendererChildren(GameObject target, GameObject original, Transform parent)
|
||||
{
|
||||
_tranforms[original.transform] = target.transform;
|
||||
target.transform.localScale = original.transform.lossyScale;
|
||||
target.transform.SetParent(parent);
|
||||
target.transform.SetPositionAndRotation(original.transform.position, original.transform.rotation);
|
||||
|
||||
|
||||
MeshRenderer originalMr = original.GetComponent<MeshRenderer>();
|
||||
if (originalMr != null)
|
||||
{
|
||||
MeshFilter originalMf = originalMr.GetComponent<MeshFilter>();
|
||||
if (originalMf != null)
|
||||
{
|
||||
_meshFilters[originalMr] = target.AddComponent<MeshFilter>();
|
||||
_meshFilters[originalMr].sharedMesh = originalMf.sharedMesh;
|
||||
_meshRenderers[originalMr] = target.AddComponent<MeshRenderer>();
|
||||
_meshRenderers[originalMr].sharedMaterials = originalMr.sharedMaterials;
|
||||
}
|
||||
}
|
||||
|
||||
SkinnedMeshRenderer originalSmr = original.GetComponent<SkinnedMeshRenderer>();
|
||||
if (originalSmr != null)
|
||||
{
|
||||
_skinnedMeshRenderers[originalSmr] = target.AddComponent<MeshRenderer>();
|
||||
_skinnedMeshRendererFilters[originalSmr] = target.AddComponent<MeshFilter>();
|
||||
_skinnedMeshRendererMeshes[originalSmr] = new Mesh();
|
||||
originalSmr.BakeMesh(_skinnedMeshRendererMeshes[originalSmr], true);
|
||||
_skinnedMeshRendererFilters[originalSmr].sharedMesh = _skinnedMeshRendererMeshes[originalSmr];
|
||||
_skinnedMeshRenderers[originalSmr].sharedMaterials = originalSmr.sharedMaterials;
|
||||
}
|
||||
|
||||
|
||||
/*if (CloneColliders)
|
||||
{
|
||||
Collider[] originalColliders = original.GetComponents<Collider>();
|
||||
if (originalColliders.Length > 0)
|
||||
{
|
||||
for (int i = 0; i < originalColliders.Length; i++)
|
||||
{
|
||||
Collider originalCollider = originalColliders[i];
|
||||
Type type = originalCollider.GetType();
|
||||
Colliders[originalCollider] = target.AddComponent(originalCollider, originalCollider.GetType());
|
||||
Physics.IgnoreCollision(Colliders[originalCollider], originalCollider);
|
||||
|
||||
if (DisableClonedCollidersAtStart)
|
||||
{
|
||||
Colliders[originalCollider].enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CloneRigidbodies)
|
||||
{
|
||||
Rigidbody[] originalRBs = original.GetComponents<Rigidbody>();
|
||||
if (originalRBs.Length > 0)
|
||||
{
|
||||
for (int i = 0; i < originalRBs.Length; i++)
|
||||
{
|
||||
Rigidbody originalRB = originalRBs[i];
|
||||
Type type = originalRB.GetType();
|
||||
_rigidbodies[originalRB] = target.AddComponent(originalRB, originalRB.GetType());
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
for (int i = 0; i < original.transform.childCount; i++)
|
||||
{
|
||||
Transform child = original.transform.GetChild(i);
|
||||
CloneRenderer childsCloneRenderer = child.GetComponent<CloneRenderer>();
|
||||
MeshRenderer originalMrChildren = child.GetComponentInChildren<MeshRenderer>(false);
|
||||
SkinnedMeshRenderer originalSmrChildren = child.GetComponentInChildren<SkinnedMeshRenderer>(false);
|
||||
Collider originalCollider = child.GetComponentInChildren<Collider>(false);
|
||||
|
||||
if (childsCloneRenderer == null && (originalMrChildren != null || originalSmrChildren != null || originalCollider != null))
|
||||
{
|
||||
GameObject clonedChild = new GameObject(child.gameObject.name);
|
||||
clonedChild.hideFlags = HideFlags.DontSave;
|
||||
CreateMeshrendererChildren(clonedChild, child.gameObject, target.transform);
|
||||
clonedChild.layer = child.gameObject.layer;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Only enables a collider that is active in the original
|
||||
*/
|
||||
/*public virtual void EnableCloneColliders()
|
||||
{
|
||||
foreach (KeyValuePair<Collider, Collider> entry in Colliders)
|
||||
{
|
||||
entry.Value.enabled = entry.Key.enabled;
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* disables all colliders in the clone
|
||||
*/
|
||||
/*public virtual void DisableCloneColliders()
|
||||
{
|
||||
foreach (KeyValuePair<Collider, Collider> entry in Colliders)
|
||||
{
|
||||
entry.Value.enabled = false;
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
public virtual void SetIsInPortal(Portal portal, bool physicsDriven = false)
|
||||
{
|
||||
if (_clone != null && _inPortal != portal)
|
||||
{
|
||||
//Debug.Log(gameObject.name + " IN, inPortal: " + portal.name + " physicsDriven: " + physicsDriven);
|
||||
_inPortal = portal;
|
||||
|
||||
_inTransform = _inPortal.PortalSurface.transform;
|
||||
_outTransform = _inPortal.OtherPortal.PortalSurface.transform;
|
||||
|
||||
/*if (portal.OtherPortal && portal.OtherPortal.wallCollider)
|
||||
{
|
||||
foreach (KeyValuePair<Collider, Collider> entry in Colliders)
|
||||
{
|
||||
Physics.IgnoreCollision(entry.Value, portal.OtherPortal.wallCollider);
|
||||
Physics.IgnoreCollision(entry.Value, portal.wallCollider);
|
||||
}
|
||||
}*/
|
||||
|
||||
_clone.SetActive(true);
|
||||
CloneAnimations();
|
||||
|
||||
//UpdateRigidbodies();
|
||||
PositionClone();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public virtual void ExitPortal(Portal portal, bool physicsDriven = false)
|
||||
{
|
||||
if (!_clone) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (portal != _inPortal)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*if (portal.OtherPortal && portal.OtherPortal.wallCollider)
|
||||
{
|
||||
foreach (KeyValuePair<Collider, Collider> entry in Colliders)
|
||||
{
|
||||
Physics.IgnoreCollision(entry.Value, portal.OtherPortal.wallCollider, false);
|
||||
Physics.IgnoreCollision(entry.Value, portal.wallCollider, false);
|
||||
}
|
||||
}*/
|
||||
|
||||
//Debug.Log(gameObject.name + " OUT, portal: " + portal?.name + " : " + physicsDriven);
|
||||
_clone.SetActive(false);
|
||||
|
||||
foreach (KeyValuePair<MeshRenderer, MeshRenderer> entry in _meshRenderers)
|
||||
{
|
||||
if (entry.Key.sharedMaterial.HasProperty("_SectionPos"))
|
||||
{
|
||||
foreach (Material m in entry.Key.materials)
|
||||
{
|
||||
m.SetFloat("_DoClipping", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<SkinnedMeshRenderer, MeshRenderer> entry in _skinnedMeshRenderers)
|
||||
{
|
||||
if (entry.Key.sharedMaterial.HasProperty("_SectionPos"))
|
||||
{
|
||||
foreach (Material m in entry.Key.materials)
|
||||
{
|
||||
m.SetFloat("_DoClipping", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_inPortal = null;
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (_inPortal)
|
||||
{
|
||||
if (!_clone)
|
||||
{
|
||||
DestroyClone();
|
||||
GenerateClone();
|
||||
}
|
||||
|
||||
CloneAnimations();
|
||||
|
||||
PositionClone();
|
||||
|
||||
UpdateLayers();
|
||||
}
|
||||
}
|
||||
|
||||
/*private void FixedUpdate()
|
||||
{
|
||||
if (CloneRigidbodies)
|
||||
{
|
||||
UpdateRigidbodies();
|
||||
}
|
||||
}*/
|
||||
|
||||
private void UpdateLayers()
|
||||
{
|
||||
foreach (KeyValuePair<Transform, Transform> entry in _tranforms)
|
||||
{
|
||||
entry.Value.gameObject.layer = entry.Key.gameObject.layer;
|
||||
}
|
||||
}
|
||||
|
||||
/*protected void UpdateRigidbodies()
|
||||
{
|
||||
if (CloneRigidbodies && _inPortal != null && _clone.activeSelf)
|
||||
{
|
||||
foreach (KeyValuePair<Rigidbody, Rigidbody> entry in _rigidbodies)
|
||||
{
|
||||
//if (Vector3.Distance(Camera.main.transform.position, entry.Key.transform.position) < Vector3.Distance(Camera.main.transform.position, entry.Value.transform.position))
|
||||
//{
|
||||
entry.Value.GetCopyOf<Rigidbody>(entry.Key);
|
||||
|
||||
Vector3 relativeVel = _inTransform.InverseTransformDirection(entry.Key.velocity);
|
||||
relativeVel = halfTurn * relativeVel;
|
||||
entry.Value.velocity = _outTransform.TransformDirection(relativeVel);
|
||||
|
||||
Vector3 relativeAngVel = _inTransform.InverseTransformDirection(entry.Key.angularVelocity);
|
||||
relativeAngVel = halfTurn * relativeAngVel;
|
||||
entry.Value.angularVelocity = _outTransform.TransformDirection(relativeAngVel);
|
||||
|
||||
// Update position of clone.
|
||||
Vector3 relativePos = _inTransform.InverseTransformPoint(entry.Key.position);
|
||||
relativePos = halfTurn * relativePos;
|
||||
entry.Value.MovePosition(_outTransform.TransformPoint(relativePos));
|
||||
|
||||
// Update rotation of clone.
|
||||
Quaternion relativeRot = Quaternion.Inverse(_inTransform.rotation) * entry.Key.rotation;
|
||||
relativeRot = halfTurn * relativeRot;
|
||||
entry.Value.MoveRotation(_outTransform.rotation * relativeRot);
|
||||
/*}
|
||||
else
|
||||
{
|
||||
entry.Key.GetCopyOf<Rigidbody>(entry.Value);
|
||||
|
||||
Vector3 relativeVel = _outTransform.InverseTransformDirection(entry.Value.velocity);
|
||||
relativeVel = halfTurn * relativeVel;
|
||||
entry.Key.velocity = _inTransform.TransformDirection(relativeVel);
|
||||
|
||||
Vector3 relativeAngVel = _outTransform.InverseTransformDirection(entry.Value.angularVelocity);
|
||||
relativeAngVel = halfTurn * relativeAngVel;
|
||||
entry.Key.angularVelocity = _inTransform.TransformDirection(relativeAngVel);
|
||||
|
||||
// Update position of clone.
|
||||
Vector3 relativePos = _outTransform.InverseTransformPoint(entry.Value.position);
|
||||
relativePos = halfTurn * relativePos;
|
||||
entry.Key.MovePosition(_inTransform.TransformPoint(relativePos));
|
||||
|
||||
// Update rotation of clone.
|
||||
Quaternion relativeRot = Quaternion.Inverse(_outTransform.rotation) * entry.Value.rotation;
|
||||
relativeRot = halfTurn * relativeRot;
|
||||
entry.Key.MoveRotation(_inTransform.rotation * relativeRot);
|
||||
}*/
|
||||
|
||||
|
||||
//}
|
||||
//}
|
||||
//}
|
||||
|
||||
protected virtual void CloneAnimations()
|
||||
{
|
||||
if (_inPortal != null && _clone.activeSelf)
|
||||
{
|
||||
// reset pos of root element
|
||||
//float scaleFactor = (inPortal.OtherPortal.transform.localScale.x / inPortal.transform.localScale.x);
|
||||
_clone.transform.localScale = GameObjectToClone.transform.lossyScale;
|
||||
_clone.transform.SetPositionAndRotation(GameObjectToClone.transform.position, transform.rotation);
|
||||
|
||||
foreach (KeyValuePair<Transform, Transform> entry in _tranforms)
|
||||
{
|
||||
entry.Value.gameObject.SetActive(entry.Key.gameObject.activeSelf);
|
||||
if (entry.Key.gameObject.activeSelf)
|
||||
{
|
||||
entry.Value.transform.localScale = entry.Key.transform.localScale;
|
||||
entry.Value.transform.localPosition = entry.Key.transform.localPosition;
|
||||
entry.Value.transform.localRotation = entry.Key.transform.localRotation;
|
||||
//cloneMr.transform.SetPositionAndRotation(orginalMr.transform.position, entry.Key.transform.rotation);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<SkinnedMeshRenderer, Mesh> entry in _skinnedMeshRendererMeshes)
|
||||
{
|
||||
entry.Key.BakeMesh(entry.Value, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void PositionClone()
|
||||
{
|
||||
if (_inPortal != null && _inTransform != null)
|
||||
{
|
||||
float scaleFactor = (_inPortal.OtherPortal.transform.lossyScale.x / _inPortal.transform.lossyScale.x);
|
||||
_clone.transform.localScale = GameObjectToClone.transform.lossyScale * scaleFactor;
|
||||
|
||||
// Update position of clone.
|
||||
Vector3 relativePos = _inTransform.InverseTransformPoint(GameObjectToClone.transform.position);
|
||||
relativePos = halfTurn * relativePos;
|
||||
Vector3 wantedPos = _outTransform.TransformPoint(relativePos);
|
||||
|
||||
//if (!CloneRigidbodies || (CloneRigidbodies && Vector3.Distance(wantedPos, _clone.transform.position) > 0.25f))
|
||||
//{
|
||||
_clone.transform.position = wantedPos;
|
||||
|
||||
// Update rotation of clone.
|
||||
Quaternion relativeRot = Quaternion.Inverse(_inTransform.rotation) * GameObjectToClone.transform.rotation;
|
||||
relativeRot = halfTurn * relativeRot;
|
||||
_clone.transform.rotation = _outTransform.rotation * relativeRot;
|
||||
//}
|
||||
|
||||
|
||||
if (_meshRenderers.Count > 0)
|
||||
{
|
||||
foreach (KeyValuePair<MeshRenderer, MeshRenderer> entry in _meshRenderers)
|
||||
{
|
||||
if (entry.Key.sharedMaterial.HasProperty("_SectionPos"))
|
||||
{
|
||||
foreach (Material m in entry.Key.materials)
|
||||
{
|
||||
m.SetVector("_SectionPos", _inTransform.position + (_inTransform.forward * 0.02f));
|
||||
m.SetVector("_SectionNormal", _inTransform.forward);
|
||||
m.SetFloat("_DoClipping", 1);
|
||||
}
|
||||
|
||||
foreach (Material m in entry.Value.materials)
|
||||
{
|
||||
m.SetVector("_SectionPos", _outTransform.position + (_outTransform.forward * 0.02f));
|
||||
m.SetVector("_SectionNormal", _outTransform.forward);
|
||||
m.SetFloat("_DoClipping", 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_skinnedMeshRenderers.Count > 0)
|
||||
{
|
||||
foreach (KeyValuePair<SkinnedMeshRenderer, MeshRenderer> entry in _skinnedMeshRenderers)
|
||||
{
|
||||
if (entry.Key && entry.Key.sharedMaterial.HasProperty("_SectionPos"))
|
||||
{
|
||||
foreach (Material m in entry.Key.materials)
|
||||
{
|
||||
m.SetVector("_SectionPos", _inTransform.position + (_inTransform.forward * 0.02f));
|
||||
m.SetVector("_SectionNormal", _inTransform.forward);
|
||||
m.SetFloat("_DoClipping", 1);
|
||||
}
|
||||
|
||||
foreach (Material m in entry.Value.materials)
|
||||
{
|
||||
m.SetVector("_SectionPos", _outTransform.position + (_outTransform.forward * 0.02f));
|
||||
m.SetVector("_SectionNormal", _outTransform.forward);
|
||||
m.SetFloat("_DoClipping", 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawBounds(Bounds b, float delay = 0)
|
||||
{
|
||||
// bottom
|
||||
var p1 = new Vector3(b.min.x, b.min.y, b.min.z);
|
||||
var p2 = new Vector3(b.max.x, b.min.y, b.min.z);
|
||||
var p3 = new Vector3(b.max.x, b.min.y, b.max.z);
|
||||
var p4 = new Vector3(b.min.x, b.min.y, b.max.z);
|
||||
|
||||
Debug.DrawLine(p1, p2, Color.blue, delay);
|
||||
Debug.DrawLine(p2, p3, Color.red, delay);
|
||||
Debug.DrawLine(p3, p4, Color.yellow, delay);
|
||||
Debug.DrawLine(p4, p1, Color.magenta, delay);
|
||||
|
||||
// top
|
||||
var p5 = new Vector3(b.min.x, b.max.y, b.min.z);
|
||||
var p6 = new Vector3(b.max.x, b.max.y, b.min.z);
|
||||
var p7 = new Vector3(b.max.x, b.max.y, b.max.z);
|
||||
var p8 = new Vector3(b.min.x, b.max.y, b.max.z);
|
||||
|
||||
Debug.DrawLine(p5, p6, Color.blue, delay);
|
||||
Debug.DrawLine(p6, p7, Color.red, delay);
|
||||
Debug.DrawLine(p7, p8, Color.yellow, delay);
|
||||
Debug.DrawLine(p8, p5, Color.magenta, delay);
|
||||
|
||||
// sides
|
||||
Debug.DrawLine(p1, p5, Color.white, delay);
|
||||
Debug.DrawLine(p2, p6, Color.gray, delay);
|
||||
Debug.DrawLine(p3, p7, Color.green, delay);
|
||||
Debug.DrawLine(p4, p8, Color.cyan, delay);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a0c949f578a98940bc705d279684d93
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 20600
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 228871
|
||||
packageName: Portals for VR
|
||||
packageVersion: 1.2.1
|
||||
assetPath: Assets/Fragilem17/Portals for VR/Scripts/CloneRenderer.cs
|
||||
uploadId: 710348
|
||||
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Fragilem17.MirrorsAndPortals
|
||||
{
|
||||
public static class ComponentExtensions
|
||||
{
|
||||
public static T GetCopyOf<T>(this T comp, T other) where T : Component
|
||||
{
|
||||
Type type = comp.GetType();
|
||||
Type othersType = other.GetType();
|
||||
if (type != othersType)
|
||||
{
|
||||
Debug.LogError($"The type \"{type.AssemblyQualifiedName}\" of \"{comp}\" does not match the type \"{othersType.AssemblyQualifiedName}\" of \"{other}\"!");
|
||||
return null;
|
||||
}
|
||||
|
||||
BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Default;
|
||||
PropertyInfo[] pinfos = type.GetProperties(flags);
|
||||
|
||||
foreach (var pinfo in pinfos)
|
||||
{
|
||||
if (pinfo.CanWrite && pinfo.Name != "name" && pinfo.Name != "hideFlags" && pinfo.Name != "tag")
|
||||
{
|
||||
try
|
||||
{
|
||||
//Debug.Log("pinfos: " + pinfo.Name + " : " + pinfo.GetValue(other, null));
|
||||
pinfo.SetValue(comp, pinfo.GetValue(other, null), null);
|
||||
}
|
||||
catch
|
||||
{
|
||||
/*
|
||||
* In case of NotImplementedException being thrown.
|
||||
* For some reason specifying that exception didn't seem to catch it,
|
||||
* so I didn't catch anything specific.
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FieldInfo[] finfos = type.GetFields(flags);
|
||||
|
||||
foreach (var finfo in finfos)
|
||||
{
|
||||
//Debug.Log("finfo: " + finfo.Name);
|
||||
finfo.SetValue(comp, finfo.GetValue(other));
|
||||
}
|
||||
return comp as T;
|
||||
}
|
||||
|
||||
public static T AddComponent<T>(this GameObject go, T toAdd, Type componentType) where T : Component
|
||||
{
|
||||
return go.AddComponent(componentType).GetCopyOf(toAdd) as T;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18a9182c810e3b64d97f7230bd848903
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 228871
|
||||
packageName: Portals for VR
|
||||
packageVersion: 1.2.1
|
||||
assetPath: Assets/Fragilem17/Portals for VR/Scripts/ComponentExtensions.cs
|
||||
uploadId: 710348
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4a64bae6b9733344089e4c033a06e8f1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,57 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
|
||||
namespace Fragilem17.MirrorsAndPortals
|
||||
{
|
||||
[CustomEditor(typeof(PortalRenderer))]
|
||||
public class PortalRendererEditor : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
PortalRenderer portalRenderer = (PortalRenderer)target;
|
||||
|
||||
#if UNITY_2022_3_OR_NEWER && !UNITY_6000_0_OR_NEWER
|
||||
if (portalRenderer.UseSubmitRenderRequest)
|
||||
{
|
||||
EditorGUILayout.HelpBox("The Portal texture is now created using SubmitRenderRequest instead of RenderSingleCamera, enabling UI elements to be correctly reflected. However, this approach may trigger a runtime error indicating that recursive rendering is not supported. This error can be safely ignored and does not occur in more recent Unity versions.", MessageType.Warning);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
|
||||
bool renderGraphEnabled = RenderGraphEnabled();
|
||||
|
||||
if (renderGraphEnabled && PlayerSettings.GetGraphicsAPIs(BuildTarget.StandaloneWindows)[0].ToString().Contains("Direct3D"))
|
||||
{
|
||||
EditorGUILayout.HelpBox("When RenderGraph is enabled (compatibility mode off) and the Windows Graphics API is set to Direct3D, the scene view fails to render portals and generates repeated console errors. To preview portals correctly in the scene, switch the Windows Graphics API to Vulkan or OpenGL.", MessageType.Warning);
|
||||
}
|
||||
|
||||
if (renderGraphEnabled && PlayerSettings.GetGraphicsAPIs(BuildTarget.Android)[0].ToString().Contains("Vulkan"))
|
||||
{
|
||||
MessageType msgType = MessageType.Warning;
|
||||
if (portalRenderer.FlipSecondRecursion)
|
||||
{
|
||||
msgType = MessageType.Info;
|
||||
}
|
||||
EditorGUILayout.HelpBox("When using RenderGraph with compatibility mode disabled and the Android Graphics API set to Vulkan, the second reflection within a portal (portal-in-portal effect) is flipped along the y-axis in the build. To resolve this issue, enable the 'Flip Second Recursion' option. This will show the second recursion flipped in the editor but it will be corrected in the headset.", msgType);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Draw the default inspector properties
|
||||
DrawDefaultInspector();
|
||||
}
|
||||
private bool RenderGraphEnabled()
|
||||
{
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
var renderGraphSettings = GraphicsSettings.GetRenderPipelineSettings<RenderGraphSettings>();
|
||||
return !renderGraphSettings.enableRenderCompatibilityMode;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bfc8b95a5ea9f5b4a84836d85c131ca4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 228871
|
||||
packageName: Portals for VR
|
||||
packageVersion: 1.2.1
|
||||
assetPath: Assets/Fragilem17/Portals for VR/Scripts/Editor/PortalRendererEditor.cs
|
||||
uploadId: 710348
|
||||
@@ -0,0 +1,153 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
|
||||
namespace Fragilem17.MirrorsAndPortals
|
||||
{
|
||||
/**
|
||||
* Used to contain the reference to the linked portal
|
||||
*/
|
||||
[ExecuteInEditMode]
|
||||
public class Portal : MonoBehaviour
|
||||
{
|
||||
private static readonly Quaternion halfTurn = Quaternion.Euler(0.0f, 180.0f, 0.0f);
|
||||
|
||||
[Tooltip("a reference to the Portal this Portal is looking out of.")]
|
||||
public Portal OtherPortal;
|
||||
|
||||
[Space(10)]
|
||||
|
||||
[Tooltip("The collider that will be disabled the moment we enter the Portal, the collider of the wall this portal is shot at.")]
|
||||
public Collider wallCollider;
|
||||
|
||||
[Space(10)]
|
||||
|
||||
[Tooltip("(autoFilled) a reference to the PortalSurface Component, this actually handles showing the portal")]
|
||||
[HideInInspector]
|
||||
public PortalSurface PortalSurface;
|
||||
|
||||
[Tooltip("(autoFilled) a reference to a PortalTransporter Component, this handles transporting through it.")]
|
||||
[HideInInspector]
|
||||
public PortalTransporter PortalTransporter;
|
||||
|
||||
[HideInInspector]
|
||||
public PortalRenderer MyRenderer;
|
||||
|
||||
protected void OnEnable()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
ObjectFactory.componentWasAdded -= ObjectFactory_componentWasAdded;
|
||||
ObjectFactory.componentWasAdded += ObjectFactory_componentWasAdded;
|
||||
#endif
|
||||
|
||||
Initialise();
|
||||
}
|
||||
|
||||
protected void Initialise()
|
||||
{
|
||||
//if (!PortalSurface)
|
||||
//{
|
||||
PortalSurface = GetComponentInChildren<PortalSurface>();
|
||||
//}
|
||||
//if (!PortalTransporter)
|
||||
//{
|
||||
PortalTransporter = GetComponentInChildren<PortalTransporter>();
|
||||
//}
|
||||
|
||||
if (!PortalSurface)
|
||||
{
|
||||
Debug.LogWarning(PortalUtils.Colorize("[PORTALS] ", PortalUtils.DebugColors.Warn, true) + name + " has a Portal Component but no PortalSurface Component, add a PortalSurface Component to this or a child GameObject.");
|
||||
}
|
||||
|
||||
|
||||
if (!PortalTransporter)
|
||||
{
|
||||
Debug.LogWarning(PortalUtils.Colorize("[PORTALS] ", PortalUtils.DebugColors.Warn, true) + name + " has a Portal Component but no PortalTransporter Component, transporting through this portal won't be possible until you add a PortalTransporter Component.");
|
||||
}
|
||||
else
|
||||
{
|
||||
PortalTransporter.Initialise();
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected void OnDisable()
|
||||
{
|
||||
ObjectFactory.componentWasAdded -= ObjectFactory_componentWasAdded;
|
||||
}
|
||||
|
||||
protected void ObjectFactory_componentWasAdded(Component obj)
|
||||
{
|
||||
//Debug.Log("ObjectFactory_componentWasAdded: " + obj.GetType().Name);
|
||||
if (obj.GetType().Name == "PortalSurface" || obj.GetType().Name == "PortalTransporter" || obj.GetType().Name == "RigidBody")
|
||||
{
|
||||
Initialise();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public bool Place(Collider wallCollider, Vector3 pos, Quaternion rot)
|
||||
{
|
||||
this.wallCollider = wallCollider;
|
||||
transform.SetPositionAndRotation(pos, rot);
|
||||
gameObject.SetActive(true);
|
||||
|
||||
// todo: can we be placed on this collider?
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetOtherPortal(Portal portal) {
|
||||
OtherPortal = portal;
|
||||
}
|
||||
|
||||
|
||||
public void Remove()
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public void PortalRay(ref Ray ray)
|
||||
{
|
||||
if (PortalSurface && OtherPortal && OtherPortal.PortalSurface)
|
||||
{
|
||||
Transform _inTransform = PortalSurface.transform;
|
||||
Transform _outTransform = OtherPortal.PortalSurface.transform;
|
||||
|
||||
Vector3 relativePos = _inTransform.InverseTransformPoint(ray.origin);
|
||||
relativePos = halfTurn * relativePos;
|
||||
ray.origin = _outTransform.TransformPoint(relativePos);
|
||||
|
||||
// Update rotation of clone.
|
||||
Quaternion relativeRot = Quaternion.Inverse(_inTransform.rotation) * Quaternion.LookRotation(ray.direction, Vector3.up);
|
||||
relativeRot = halfTurn * relativeRot;
|
||||
Quaternion newRotation = _outTransform.rotation * relativeRot;
|
||||
ray.direction = newRotation * Vector3.forward;
|
||||
}
|
||||
}
|
||||
|
||||
public void PortalTransform(ref Vector3 position, ref Quaternion rotation, ref float scale)
|
||||
{
|
||||
Transform _inTransform = PortalSurface.transform;
|
||||
Transform _outTransform = OtherPortal.PortalSurface.transform;
|
||||
|
||||
float scaleFactor = (OtherPortal.transform.lossyScale.x / transform.lossyScale.x);
|
||||
scale = scale * scaleFactor;
|
||||
|
||||
// Update position of clone.
|
||||
Vector3 relativePos = _inTransform.InverseTransformPoint(position);
|
||||
relativePos = halfTurn * relativePos;
|
||||
position = _outTransform.TransformPoint(relativePos);
|
||||
|
||||
// Update rotation of clone.
|
||||
Quaternion relativeRot = Quaternion.Inverse(_inTransform.rotation) * rotation;
|
||||
relativeRot = halfTurn * relativeRot;
|
||||
rotation = _outTransform.rotation * relativeRot;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3af7ca4916d35ee4ba154acde45dd813
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 228871
|
||||
packageName: Portals for VR
|
||||
packageVersion: 1.2.1
|
||||
assetPath: Assets/Fragilem17/Portals for VR/Scripts/Portal.cs
|
||||
uploadId: 710348
|
||||
@@ -0,0 +1,124 @@
|
||||
using Fragilem17.MirrorsAndPortals;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Fragilem17.MirrorsAndPortals
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
public class PortalAffectorSphere : MonoBehaviour
|
||||
{
|
||||
public List<MeshRenderer> renderers;
|
||||
|
||||
private static List<string> _shaderNames = new List<string>(new string[] { "_SphereParams1", "_SphereParams2", "_SphereParams3" });
|
||||
//private static int _portalAffectorsInUse = 0;
|
||||
private string _myShaderName = "unset";
|
||||
|
||||
private Portal _inPortal;
|
||||
private Vector3 _originalPortalScaleIn;
|
||||
private Vector3 _originalPortalScaleOut;
|
||||
private static readonly Quaternion halfTurn = Quaternion.Euler(0.0f, 180.0f, 0.0f);
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (_shaderNames.Count == 0)
|
||||
{
|
||||
Debug.LogWarning("a maximum of 3 portal affectors will have an effect on the portal shader");
|
||||
return;
|
||||
}
|
||||
|
||||
_myShaderName = _shaderNames[0];
|
||||
_shaderNames.RemoveAt(0);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (_myShaderName != "unset" && !_shaderNames.Contains(_myShaderName))
|
||||
{
|
||||
_shaderNames.Add(_myShaderName);
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (_inPortal)
|
||||
{
|
||||
Vector3 p = transform.position;
|
||||
_inPortal.PortalSurface.myMeshRenderer.sharedMaterial.SetVector(_myShaderName, new Vector4(p.x, p.y, p.z, transform.lossyScale.x));
|
||||
}
|
||||
/*if (renderers != null && renderers.Count > 0)
|
||||
{
|
||||
foreach (MeshRenderer r in renderers)
|
||||
{
|
||||
Vector3 p = transform.position;
|
||||
if (r != null && r.sharedMaterial != null)
|
||||
{
|
||||
r.sharedMaterial.SetVector(_myShaderName, new Vector4(p.x, p.y, p.z, transform.lossyScale.x));
|
||||
}
|
||||
}
|
||||
|
||||
//Debug.Log(transform.parent.name + "used " + _shaderNames[_usedShaderSlotIndex]);
|
||||
//PositionClone();
|
||||
}*/
|
||||
}
|
||||
|
||||
private void PositionClone()
|
||||
{
|
||||
if (_inPortal != null)
|
||||
{
|
||||
Transform inTransform = _inPortal.PortalSurface.transform;
|
||||
Transform outTransform = _inPortal.OtherPortal.PortalSurface.transform;
|
||||
|
||||
float scaleFactor = (_inPortal.OtherPortal.transform.lossyScale.x / _inPortal.transform.lossyScale.x);
|
||||
|
||||
|
||||
_originalPortalScaleIn = inTransform.localScale;
|
||||
_originalPortalScaleOut = outTransform.localScale;
|
||||
|
||||
inTransform.localScale = Vector3.one;
|
||||
outTransform.localScale = Vector3.one;
|
||||
|
||||
|
||||
// Update position of clone.
|
||||
Vector3 relativePos = inTransform.InverseTransformPoint(transform.position);
|
||||
relativePos = halfTurn * relativePos;
|
||||
Vector3 p = outTransform.TransformPoint(relativePos);
|
||||
|
||||
_inPortal.OtherPortal.PortalSurface.myMeshRenderer.sharedMaterial.SetVector(_myShaderName, new Vector4(p.x, p.y, p.z, transform.lossyScale.x));
|
||||
|
||||
inTransform.localScale = _originalPortalScaleIn;
|
||||
outTransform.localScale = _originalPortalScaleOut;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetIsInPortal(Portal portal)
|
||||
{
|
||||
//Debug.Log("SetIsInPortal " + transform.parent.name + " inPortal: " + portal.name);
|
||||
_inPortal = portal;
|
||||
if (portal.PortalSurface && !renderers.Contains(portal.PortalSurface.myMeshRenderer))
|
||||
{
|
||||
renderers.Add(portal.PortalSurface.myMeshRenderer);
|
||||
}
|
||||
//PositionClone();
|
||||
}
|
||||
|
||||
public void ExitPortal(Portal portal)
|
||||
{
|
||||
//Debug.Log("ExitPortal " + transform.parent.name + " inPortal: " + portal.name);
|
||||
if (portal.PortalSurface)
|
||||
{
|
||||
Vector3 p = new Vector3(999f, 999f, 999f);
|
||||
portal.PortalSurface.myMeshRenderer.sharedMaterial.SetVector(_myShaderName, new Vector4(p.x, p.y, p.z, 0.0001f));
|
||||
|
||||
_inPortal = null;
|
||||
renderers.Remove(portal.PortalSurface.myMeshRenderer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 838474b7f1a4c4944b1eb7ef071e1ed2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 228871
|
||||
packageName: Portals for VR
|
||||
packageVersion: 1.2.1
|
||||
assetPath: Assets/Fragilem17/Portals for VR/Scripts/PortalAffectorSphere.cs
|
||||
uploadId: 710348
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e866cce3e676c124aab2114b652d5a9e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 228871
|
||||
packageName: Portals for VR
|
||||
packageVersion: 1.2.1
|
||||
assetPath: Assets/Fragilem17/Portals for VR/Scripts/PortalRenderer.cs
|
||||
uploadId: 710348
|
||||
@@ -0,0 +1,925 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.XR;
|
||||
using System;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
using System.Linq;
|
||||
//using Newtonsoft.Json;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace Fragilem17.MirrorsAndPortals
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
public class PortalSurface : MonoBehaviour
|
||||
{
|
||||
private Portal _portal;
|
||||
|
||||
[Tooltip("The source material, disable and re-enable this component if you make changes to the material")]
|
||||
public Material Material;
|
||||
|
||||
[Tooltip("When the camera is further from this distance, the surface stops updating it's texture.")]
|
||||
[MinAttribute(0)]
|
||||
public float maxRenderingDistance = 5f;
|
||||
|
||||
[Tooltip("Defines whether a certain amount of color should be blended in with the reflection depending on distance.")]
|
||||
public bool useColorBlending = true;
|
||||
|
||||
public Color BlendColor = Color.black;
|
||||
|
||||
[Tooltip("The value at 'Time' 0, means when you're directly in front of the portal at a distance of 0. 'Time' 1 reflects the maxRenderingDistance.")]
|
||||
public AnimationCurve colorBlendingCurve = AnimationCurve.Linear(0, -99f, 1f, 99f);
|
||||
|
||||
|
||||
[Space(10)]
|
||||
|
||||
[Tooltip("Defines whether the albedo map alpha should be changed over distance.")]
|
||||
public bool useAlbedoAlphaFading = false;
|
||||
|
||||
public AnimationCurve albedoAlphaFadeCurve = AnimationCurve.Linear(0, -99f, 1f, 99f);
|
||||
|
||||
|
||||
[Space(10)]
|
||||
|
||||
[Tooltip("Defines whether the amount of Refraction should be changed depending on distance.")]
|
||||
public bool useRefractionFading = false;
|
||||
|
||||
[Tooltip("The value at 'Time' 0, means when you're directly in front of the portal at a distance of 0. 'Time' 1 reflects the maxRenderingDistance.")]
|
||||
public AnimationCurve refractionFadingCurve = AnimationCurve.Linear(0, -99f, 1f, 99f);
|
||||
|
||||
|
||||
|
||||
[Header("Other")]
|
||||
|
||||
[Tooltip("The custom skybox the portal will use, when none is used, the skybox from the MainCamera is used or the skybox from lighting settings.")]
|
||||
public Material CustomSkybox;
|
||||
|
||||
[Tooltip("The portal camera's nearPlane will be at the distance between the camera and the portalSurface, use this offset to modify the nearPlane")]
|
||||
public float clippingPlaneOffset = -0.002f;
|
||||
|
||||
[Tooltip("An oblique projection matrix rotates the PortalCamera's near clipping field so it aligns with the portals surface. It's required on if stuff is near the back side of the portal. However, the ObliquePM messes up several postprocessing effects like SSAO and the occlusion culling of the portalCamera. It's a tradeoff!")]
|
||||
public bool requireObliqueProjectionMatrix = true;
|
||||
|
||||
[Tooltip("An oblique projection matrix rotates the PortalCamera's near clipping field so it aligns with the portals surface. It's required \"on\" if stuff is near the back side of the portal. However, the ObliquePM messes up several postprocessing effects like SSAO and the occlusion culling of the portalCamera. It's a tradeoff!")]
|
||||
public float nearDistanceToStartDisablingObliquePM = 0.02f;
|
||||
|
||||
public MeshRenderer myMeshRenderer;
|
||||
private MeshFilter _myMeshFilter;
|
||||
|
||||
|
||||
|
||||
private Plane _plane;
|
||||
private Material _material;
|
||||
private Material _myMaterialInstance;
|
||||
private PortalRenderer _myRenderer;
|
||||
private Color _oldFadeColor = Color.black;
|
||||
private Material _oldMaterial;
|
||||
private bool _wasToFar = false;
|
||||
|
||||
private bool _isSelectedInEditor = false;
|
||||
|
||||
[HideInInspector]
|
||||
public Texture _currentTexLeft;
|
||||
[HideInInspector]
|
||||
public Texture _currentTexRight;
|
||||
[HideInInspector]
|
||||
public float _currentDistanceBlend;
|
||||
|
||||
private Vector3 _startPosition;
|
||||
|
||||
|
||||
public Portal Portal { get => _portal; }
|
||||
public Material MyMaterialInstance { get => _myMaterialInstance; }
|
||||
|
||||
// the worldspace bounds of this portalSurface (precompute?)
|
||||
private Vector3[] _portalBounds;
|
||||
|
||||
enum SideEdge {
|
||||
Top,
|
||||
Left,
|
||||
Bottom,
|
||||
Right,
|
||||
WRONG
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_startPosition = transform.localPosition;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// our surfaces can't be batched! we rely on the mesh to get the real worls bounds
|
||||
// also, you want to hide this mesh as soon as it's out of view.
|
||||
// this can't happen when batched with a lot of other meshes.. forcing the recursion to keep rendering.
|
||||
var flags = GameObjectUtility.GetStaticEditorFlags(gameObject);
|
||||
flags &= ~StaticEditorFlags.BatchingStatic;
|
||||
GameObjectUtility.SetStaticEditorFlags(gameObject, flags);
|
||||
#endif
|
||||
|
||||
_portal = GetComponentInParent<Portal>();
|
||||
if (!_portal)
|
||||
{
|
||||
Debug.LogWarning(PortalUtils.Colorize("[PORTALS] ", PortalUtils.DebugColors.Warn, true) + name + " a PortalSurface needs to be a child gameObject of a Portal");
|
||||
}
|
||||
|
||||
//Debug.Log("_isSelectedInEditor " + _isSelectedInEditor + " : "+ gameObject.name);
|
||||
if (myMeshRenderer == null)
|
||||
{
|
||||
myMeshRenderer = GetComponent<MeshRenderer>();
|
||||
}
|
||||
if (_myMeshFilter == null)
|
||||
{
|
||||
_myMeshFilter = GetComponent<MeshFilter>();
|
||||
}
|
||||
|
||||
|
||||
_wasToFar = false;
|
||||
|
||||
if (!Material && myMeshRenderer)
|
||||
{
|
||||
Material = myMeshRenderer.sharedMaterial;
|
||||
}
|
||||
|
||||
|
||||
if (myMeshRenderer && Material)
|
||||
{
|
||||
_oldMaterial = Material;
|
||||
|
||||
if (_isSelectedInEditor)
|
||||
{
|
||||
// make sure we're editing the source materials, not the instance
|
||||
Material.SetColor("_FadeColor", BlendColor);
|
||||
myMeshRenderer.sharedMaterial = Material;
|
||||
_material = Material;
|
||||
}
|
||||
else
|
||||
{
|
||||
_material = new Material(Material);
|
||||
_myMaterialInstance = _material;
|
||||
_material.name += " (for " + gameObject.name + ")";
|
||||
_material.SetColor("_FadeColor", BlendColor);
|
||||
myMeshRenderer.material = _material;
|
||||
}
|
||||
|
||||
// find my bounds and save them
|
||||
|
||||
}
|
||||
|
||||
if (_material.HasProperty("_FadeColorBlend"))
|
||||
{
|
||||
_currentDistanceBlend = _material.GetFloat("_FadeColorBlend");
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
Selection.selectionChanged += OnSelectionChange;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void Start()
|
||||
{
|
||||
SetDefaultCurves();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
|
||||
#if UNITY_EDITOR
|
||||
//Debug.Log("disabling");
|
||||
_isSelectedInEditor = false;
|
||||
Selection.selectionChanged -= OnSelectionChange;
|
||||
#endif
|
||||
if (_material != Material)
|
||||
{
|
||||
DestroyImmediate(_material, true);
|
||||
}
|
||||
if (myMeshRenderer)
|
||||
{
|
||||
myMeshRenderer.material = Material;
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnDestroy()
|
||||
{
|
||||
//Debug.Log("destroying");
|
||||
_isSelectedInEditor = false;
|
||||
Selection.selectionChanged -= OnSelectionChange;
|
||||
//DestroyImmediate(gameObject);
|
||||
}
|
||||
|
||||
[ContextMenu("Copy my properties and settings to the other PortalSurface.")]
|
||||
void CopyPropertiesToOtherPortal()
|
||||
{
|
||||
if (_portal && _portal.OtherPortal && _portal.OtherPortal.PortalSurface)
|
||||
{
|
||||
_portal.OtherPortal.PortalSurface.Material = Material;
|
||||
_portal.OtherPortal.PortalSurface.maxRenderingDistance = maxRenderingDistance;
|
||||
_portal.OtherPortal.PortalSurface.useColorBlending = useColorBlending;
|
||||
_portal.OtherPortal.PortalSurface.BlendColor = BlendColor;
|
||||
_portal.OtherPortal.PortalSurface.colorBlendingCurve.keys = colorBlendingCurve.keys;
|
||||
_portal.OtherPortal.PortalSurface.useAlbedoAlphaFading = useAlbedoAlphaFading;
|
||||
_portal.OtherPortal.PortalSurface.albedoAlphaFadeCurve.keys = albedoAlphaFadeCurve.keys;
|
||||
_portal.OtherPortal.PortalSurface.useRefractionFading = useRefractionFading;
|
||||
_portal.OtherPortal.PortalSurface.refractionFadingCurve.keys = refractionFadingCurve.keys;
|
||||
_portal.OtherPortal.PortalSurface.clippingPlaneOffset = clippingPlaneOffset;
|
||||
EditorUtility.SetDirty(_portal.OtherPortal.PortalSurface);
|
||||
}
|
||||
}
|
||||
|
||||
[ContextMenu("Serialise My Curves")]
|
||||
private void SerialiseMyCurves()
|
||||
{
|
||||
SerializableCurve sc = new SerializableCurve(colorBlendingCurve);
|
||||
string json = JsonUtility.ToJson(sc);
|
||||
//json = JsonConvert.ToString(json);
|
||||
Debug.Log("colorBlendingCurve: " + json);
|
||||
|
||||
sc = new SerializableCurve(albedoAlphaFadeCurve);
|
||||
json = JsonUtility.ToJson(sc);
|
||||
//json = JsonConvert.ToString(json);
|
||||
Debug.Log("albedoAlphaFadeCurve: " + json);
|
||||
|
||||
sc = new SerializableCurve(refractionFadingCurve);
|
||||
json = JsonUtility.ToJson(sc);
|
||||
//json = JsonConvert.ToString(json);
|
||||
Debug.Log("refractionFadingCurve: " + json);
|
||||
}
|
||||
|
||||
private void SetDefaultCurves()
|
||||
{
|
||||
if (colorBlendingCurve.keys.Length == 2 && colorBlendingCurve.keys[0].value == -99f && colorBlendingCurve.keys[1].value == 99f)
|
||||
{
|
||||
Debug.Log("a PortalSurface was enabled, SetDefaultColorBlendingCurve on " + Portal?.name);
|
||||
SetDefaultColorBlendingCurve();
|
||||
EditorUtility.SetDirty(this);
|
||||
}
|
||||
|
||||
if (albedoAlphaFadeCurve.keys.Length == 2 && albedoAlphaFadeCurve.keys[0].value == -99f && albedoAlphaFadeCurve.keys[1].value == 99f)
|
||||
{
|
||||
Debug.Log("a PortalSurface was enabled, SetDefaultAlbedoAlphaFadeCurve on " + Portal?.name);
|
||||
SetDefaultAlbedoAlphaFadeCurve();
|
||||
EditorUtility.SetDirty(this);
|
||||
}
|
||||
|
||||
if (refractionFadingCurve.keys.Length == 2 && refractionFadingCurve.keys[0].value == -99f && refractionFadingCurve.keys[1].value == 99f)
|
||||
{
|
||||
Debug.Log("a PortalSurface was enabled, SetDefaultRefractionFadingCurve on " + Portal?.name);
|
||||
SetDefaultRefractionFadingCurve();
|
||||
EditorUtility.SetDirty(this);
|
||||
}
|
||||
}
|
||||
|
||||
[ContextMenu("Reset RefractionFadingCurve")]
|
||||
private void SetDefaultRefractionFadingCurve()
|
||||
{
|
||||
string curve = "{\"keys\":[{\"inTangent\":0.0,\"inWeight\":0.0,\"outTangent\":-0.0003126605006400496,\"outWeight\":1.0,\"weightedMode\":0,\"time\":0.0,\"value\":0.0},{\"inTangent\":0.0,\"inWeight\":0.3333333432674408,\"outTangent\":0.0,\"outWeight\":0.3333333432674408,\"weightedMode\":0,\"time\":0.05000000074505806,\"value\":0.0},{\"inTangent\":-0.005003984551876783,\"inWeight\":0.12056756019592285,\"outTangent\":-0.005003984551876783,\"outWeight\":0.0,\"weightedMode\":0,\"time\":0.9946242570877075,\"value\":0.1989855170249939}],\"postWrapMode\":\"ClampForever\",\"preWrapMode\":\"ClampForever\"}";
|
||||
SerializableCurve sc2 = JsonUtility.FromJson<SerializableCurve>(curve);
|
||||
refractionFadingCurve = sc2.toCurve();
|
||||
}
|
||||
|
||||
[ContextMenu("Reset AlbedoAlphaFadeCurve")]
|
||||
private void SetDefaultAlbedoAlphaFadeCurve()
|
||||
{
|
||||
string curve = "{\"keys\":[{\"inTangent\":0.0,\"inWeight\":0.0,\"outTangent\":0.0,\"outWeight\":0.0,\"weightedMode\":0,\"time\":0.0,\"value\":0.0},{\"inTangent\":0.0,\"inWeight\":1.0,\"outTangent\":45.0,\"outWeight\":0.022694604471325876,\"weightedMode\":0,\"time\":0.009999999776482582,\"value\":0.0},{\"inTangent\":45.0,\"inWeight\":0.8593189716339111,\"outTangent\":0.0,\"outWeight\":0.11139071732759476,\"weightedMode\":0,\"time\":0.029999999329447748,\"value\":0.8999999761581421},{\"inTangent\":0.03659231960773468,\"inWeight\":0.1438542902469635,\"outTangent\":0.03659231960773468,\"outWeight\":0.3333333432674408,\"weightedMode\":0,\"time\":0.6000000238418579,\"value\":0.8999999761581421},{\"inTangent\":0.0,\"inWeight\":0.0,\"outTangent\":0.0,\"outWeight\":0.0,\"weightedMode\":0,\"time\":1.0,\"value\":2.200000047683716}],\"postWrapMode\":\"ClampForever\",\"preWrapMode\":\"ClampForever\"}";
|
||||
SerializableCurve sc2 = JsonUtility.FromJson<SerializableCurve>(curve);
|
||||
albedoAlphaFadeCurve = sc2.toCurve();
|
||||
}
|
||||
|
||||
[ContextMenu("Reset ColorBlendingCurve")]
|
||||
private void SetDefaultColorBlendingCurve()
|
||||
{
|
||||
string curve = "{\"keys\":[{\"inTangent\":0.0,\"inWeight\":0.0,\"outTangent\":0.0,\"outWeight\":0.0,\"weightedMode\":0,\"time\":0.0,\"value\":0.0},{\"inTangent\":0.0,\"inWeight\":0.3333333432674408,\"outTangent\":0.0,\"outWeight\":0.3333333432674408,\"weightedMode\":0,\"time\":0.6000000238418579,\"value\":0.0},{\"inTangent\":0.0,\"inWeight\":0.0,\"outTangent\":0.0,\"outWeight\":0.0,\"weightedMode\":0,\"time\":1.0,\"value\":1.0}],\"postWrapMode\":\"ClampForever\",\"preWrapMode\":\"ClampForever\"}";
|
||||
SerializableCurve sc2 = JsonUtility.FromJson<SerializableCurve>(curve);
|
||||
colorBlendingCurve = sc2.toCurve();
|
||||
}
|
||||
#endif
|
||||
|
||||
public void UpdatePositionsInMaterial(Vector3 position, Vector3 direction)
|
||||
{
|
||||
if (_material && _material.HasProperty("_WorldPos"))
|
||||
{
|
||||
_material.SetVector("_WorldPos", position);
|
||||
_material.SetVector("_WorldDir", direction);
|
||||
}
|
||||
}
|
||||
|
||||
public bool VisibleFromCamera(Camera renderCamera, bool ignoreDistance = true, float offset = 0, bool ignoreCulling = false)
|
||||
{
|
||||
if (!enabled || !myMeshRenderer || !_material || !gameObject.activeInHierarchy)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ignoreCulling && !myMeshRenderer.isVisible)
|
||||
{
|
||||
//Debug.Log(name + " i'm not visible!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// check the normal of the mirror. if the camera is behind it, return early
|
||||
Vector3 forward = -1 * transform.forward; //transform.TransformDirection(Vector3.forward);
|
||||
//Vector3 toOther = (renderCamera.transform.position+(renderCamera.transform.forward * -offset)) - (transform.position);
|
||||
Vector3 toOther = (renderCamera.transform.position) - (transform.position);
|
||||
|
||||
|
||||
if (Vector3.Dot(forward, toOther) < -offset) // if we're behind the mirror
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ignoreDistance)
|
||||
{
|
||||
float d = Vector3.Distance(ClosestPointOnBoundsFlattenedToPlane(renderCamera.transform.position), renderCamera.transform.position);
|
||||
bool toFar = d > maxRenderingDistance;
|
||||
if (toFar && !_wasToFar)
|
||||
{
|
||||
_wasToFar = true;
|
||||
|
||||
// blend the surface
|
||||
if (useColorBlending && _material.HasProperty("_FadeColorBlend"))
|
||||
{
|
||||
//Debug.Log("toFar: " + gameObject.name + " distnce: "+ d);
|
||||
_material.SetFloat("_FadeColorBlend", colorBlendingCurve.Evaluate(1));
|
||||
}
|
||||
if (useAlbedoAlphaFading && _material.HasProperty("_AlbedoAlpha"))
|
||||
{
|
||||
_material.SetFloat("_AlbedoAlpha", albedoAlphaFadeCurve.Evaluate(1));
|
||||
}
|
||||
if (useRefractionFading && _material.HasProperty("_refraction"))
|
||||
{
|
||||
_material.SetFloat("_refraction", refractionFadingCurve.Evaluate(1));
|
||||
}
|
||||
}
|
||||
if (!toFar && _wasToFar)
|
||||
{
|
||||
_wasToFar = false;
|
||||
}
|
||||
|
||||
if (toFar)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Plane[] planes = GeometryUtility.CalculateFrustumPlanes(renderCamera);
|
||||
planes[4].Translate(renderCamera.transform.forward * offset);
|
||||
bool inBounds = GeometryUtility.TestPlanesAABB(planes, myMeshRenderer.bounds);
|
||||
return inBounds;
|
||||
}
|
||||
|
||||
public Vector3 ClosestPointOnBoundsFlattenedToPlane(Vector3 toPos)
|
||||
{
|
||||
Vector3 p = myMeshRenderer.bounds.ClosestPoint(toPos);
|
||||
p = _plane.ClosestPointOnPlane(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
public Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivotPosition, Quaternion rotation)
|
||||
{
|
||||
return pivotPosition + (rotation * (point - pivotPosition)); // returns new position of the point;
|
||||
}
|
||||
|
||||
|
||||
private static Rect CreateRectFromPoints(Vector2[] points)
|
||||
{
|
||||
float minX = float.MaxValue;
|
||||
float minY = float.MaxValue;
|
||||
float maxX = float.MinValue;
|
||||
float maxY = float.MinValue;
|
||||
|
||||
foreach (Vector2 point in points)
|
||||
{
|
||||
if (point.x < minX)
|
||||
{
|
||||
minX = point.x;
|
||||
}
|
||||
if (point.y < minY)
|
||||
{
|
||||
minY = point.y;
|
||||
}
|
||||
if (point.x > maxX)
|
||||
{
|
||||
maxX = point.x;
|
||||
}
|
||||
if (point.y > maxY)
|
||||
{
|
||||
maxY = point.y;
|
||||
}
|
||||
}
|
||||
|
||||
return new Rect(minX, minY, maxX - minX, maxY - minY);
|
||||
}
|
||||
|
||||
|
||||
private bool RectIntersects(Rect r1, Rect r2, out Rect area)
|
||||
{
|
||||
area = new Rect();
|
||||
|
||||
if (r2.Overlaps(r1))
|
||||
{
|
||||
float x1 = Mathf.Min(r1.xMax, r2.xMax);
|
||||
float x2 = Mathf.Max(r1.xMin, r2.xMin);
|
||||
float y1 = Mathf.Min(r1.yMax, r2.yMax);
|
||||
float y2 = Mathf.Max(r1.yMin, r2.yMin);
|
||||
area.x = Mathf.Min(x1, x2);
|
||||
area.y = Mathf.Min(y1, y2);
|
||||
area.width = Mathf.Max(0.0f, x1 - x2);
|
||||
area.height = Mathf.Max(0.0f, y1 - y2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private Vector3[] _shrinkToVectorArray = new Vector3[4];
|
||||
public Vector3[] ShrinkPointsToBounds(Camera reflectionCamera, float offset, bool debug)
|
||||
{
|
||||
_portalBounds = GetPortalBounds(reflectionCamera, offset);
|
||||
|
||||
|
||||
Vector3[] fustrumBoundsOnPlane = new Vector3[4];
|
||||
bool allPointsFound = GetFustrumBoundsOnPlane(reflectionCamera, offset, ref fustrumBoundsOnPlane);
|
||||
|
||||
/*for (int x = 0; x < 4; x++)
|
||||
{
|
||||
DebugExtension.DebugWireSphere(fustrumBoundsOnPlane[x], Color.blue, 0.1f);
|
||||
}*/
|
||||
|
||||
for (int x = 0; x < 4; x++)
|
||||
{
|
||||
_shrinkToVectorArray[x] = _portalBounds[x];
|
||||
|
||||
fustrumBoundsOnPlane[x] = RotatePointAroundPivot(fustrumBoundsOnPlane[x], transform.position, Quaternion.Inverse(transform.rotation));
|
||||
_portalBounds[x] = RotatePointAroundPivot(_portalBounds[x], transform.position, Quaternion.Inverse(transform.rotation));
|
||||
|
||||
//DebugExtension.DebugWireSphere(fustrumBoundsOnPlane[x], Color.red, 0.1f);
|
||||
//DebugExtension.DebugWireSphere(_portalBounds[x], Color.green, 0.1f);
|
||||
}
|
||||
|
||||
|
||||
Vector2[] rect1 = new Vector2[4];
|
||||
Vector2[] rect2 = new Vector2[4];
|
||||
for (int x = 0; x < 4; x++)
|
||||
{
|
||||
rect1[x] = new Vector2(fustrumBoundsOnPlane[x].x, fustrumBoundsOnPlane[x].y);
|
||||
rect2[x] = new Vector2(_portalBounds[x].x, _portalBounds[x].y);
|
||||
}
|
||||
|
||||
Rect r1 = CreateRectFromPoints(rect1);
|
||||
Rect r2 = CreateRectFromPoints(rect2);
|
||||
Rect rectOut;
|
||||
|
||||
if(RectIntersects(r1, r2, out rectOut))
|
||||
{
|
||||
// bottomLeft / bottomRight / topLeft
|
||||
_shrinkToVectorArray[0] = new Vector3(rectOut.center.x - (rectOut.width/2f), rectOut.center.y - (rectOut.height / 2f), fustrumBoundsOnPlane[0].z);
|
||||
_shrinkToVectorArray[1] = new Vector3(rectOut.center.x + (rectOut.width/2f), rectOut.center.y - (rectOut.height / 2f), fustrumBoundsOnPlane[0].z);
|
||||
_shrinkToVectorArray[2] = new Vector3(rectOut.center.x - (rectOut.width/2f), rectOut.center.y + (rectOut.height / 2f), fustrumBoundsOnPlane[0].z);
|
||||
_shrinkToVectorArray[3] = new Vector3(rectOut.center.x + (rectOut.width/2f), rectOut.center.y + (rectOut.height / 2f), fustrumBoundsOnPlane[0].z);
|
||||
|
||||
for (int x = 0; x < 4; x++)
|
||||
{
|
||||
_shrinkToVectorArray[x] = RotatePointAroundPivot(_shrinkToVectorArray[x], transform.position, transform.rotation);
|
||||
_shrinkToVectorArray[x] = _shrinkToVectorArray[x] + ((_shrinkToVectorArray[x] - reflectionCamera.transform.position) * 0.025f);
|
||||
|
||||
/*if (debug)
|
||||
{
|
||||
DebugExtension.DebugWireSphere(_shrinkToVectorArray[x], Color.green, 0.1f, 0, false);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
return _shrinkToVectorArray;
|
||||
}
|
||||
|
||||
|
||||
private bool GetFustrumBoundsOnPlane(Camera reflectionCamera, float surfaceDist, ref Vector3[] positionsOnPlane)
|
||||
{
|
||||
float offset = 0;
|
||||
if (surfaceDist < 0.01f)
|
||||
{
|
||||
offset = 0.01f - MathF.Max(surfaceDist, 0);
|
||||
}
|
||||
|
||||
Vector3[] frustumCorners = new Vector3[4];
|
||||
reflectionCamera.CalculateFrustumCorners(new Rect(0f, 0f, 1f, 1f), 1, Camera.MonoOrStereoscopicEye.Mono, frustumCorners);
|
||||
bool allSucceeded = true;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
frustumCorners[i] = reflectionCamera.transform.TransformPoint(frustumCorners[i]);
|
||||
if (!ProjectPointOnPlane(reflectionCamera.transform.position, frustumCorners[i], ref positionsOnPlane[i], offset)) {
|
||||
// we're not hitting the plane.. hit far enough, then get the closest to the plane
|
||||
positionsOnPlane[i] = reflectionCamera.transform.position + ((frustumCorners[i] - reflectionCamera.transform.position) * 25f);
|
||||
//DebugExtension.DebugWireSphere(positionsOnPlane[i], Color.magenta, 0.07f);
|
||||
positionsOnPlane[i] = _plane.ClosestPointOnPlane(positionsOnPlane[i]);
|
||||
allSucceeded = false;
|
||||
}
|
||||
//DebugExtension.DebugWireSphere(frustumCorners[i], Color.magenta, 0.1f);
|
||||
//DebugExtension.DebugWireSphere(positionsOnPlane[i], Color.blue, 0.05f);
|
||||
|
||||
//positionsOnPlane[i] += transform.forward * -0.1f;
|
||||
}
|
||||
|
||||
return allSucceeded;
|
||||
}
|
||||
|
||||
|
||||
public void UpdateMaterial(Camera.StereoscopicEye eye = Camera.StereoscopicEye.Left, RenderTexture texture = null, PortalRenderer myRenderer = null, int depth = 1, float distance = 0)
|
||||
{
|
||||
if (myMeshRenderer && _material)
|
||||
{
|
||||
//Debug.Log(gameObject.name + " set prop 3");
|
||||
|
||||
float distPercent = distance / maxRenderingDistance;
|
||||
float dist = distance;
|
||||
_myRenderer = myRenderer;
|
||||
//Debug.Log(name + " : " + distance + " : " + distPercent);
|
||||
Material m = _material;
|
||||
|
||||
if (depth >= _myRenderer.recursions + 1)
|
||||
{
|
||||
// we need to be fully opaque.. no need to do anything else
|
||||
if (useColorBlending && m.HasProperty("_FadeColorBlend"))
|
||||
{
|
||||
m.SetFloat("_FadeColorBlend", colorBlendingCurve.Evaluate(1));
|
||||
}
|
||||
if (useAlbedoAlphaFading && m.HasProperty("_AlbedoAlpha"))
|
||||
{
|
||||
m.SetFloat("_AlbedoAlpha", albedoAlphaFadeCurve.Evaluate(1));
|
||||
}
|
||||
if (useRefractionFading && m.HasProperty("_refraction"))
|
||||
{
|
||||
m.SetFloat("_refraction", refractionFadingCurve.Evaluate(1));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (m.HasProperty("_flipY"))
|
||||
{
|
||||
//Debug.Log("depth: " + depth);
|
||||
if (_myRenderer.FlipSecondRecursion)
|
||||
{
|
||||
m.SetInt("_flipY", depth == 1 ? 0 : 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
m.SetInt("_flipY", 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (m.HasProperty("_ForceEye"))
|
||||
{
|
||||
m.SetInt("_ForceEye", eye == Camera.StereoscopicEye.Left ? 0 : 1);
|
||||
}
|
||||
|
||||
if (eye == Camera.StereoscopicEye.Left && m.HasProperty("_TexLeft") && texture != null)
|
||||
{
|
||||
m.SetTexture("_TexLeft", texture);
|
||||
_currentTexLeft = texture;
|
||||
}
|
||||
|
||||
if (eye == Camera.StereoscopicEye.Right && XRSettings.enabled && m.HasProperty("_TexRight") && texture != null)
|
||||
{
|
||||
m.SetTexture("_TexRight", texture);
|
||||
_currentTexRight = texture;
|
||||
}
|
||||
|
||||
EnableTransparancy();
|
||||
|
||||
|
||||
if (depth != -1)
|
||||
{
|
||||
if (useColorBlending)
|
||||
{
|
||||
if (m.HasProperty("_FadeColorBlend"))
|
||||
{
|
||||
float curveVal = colorBlendingCurve.Evaluate(distPercent);
|
||||
m.SetFloat("_FadeColorBlend", curveVal);
|
||||
//Debug.Log("from surface: " + transform.parent.name + " : " + curveVal);
|
||||
_currentDistanceBlend = curveVal;
|
||||
//Debug.Log(gameObject.name + " 2 blend " + curveVal + " distance: " + distance);
|
||||
}
|
||||
}
|
||||
|
||||
if (useRefractionFading)
|
||||
{
|
||||
if (m.HasProperty("_refraction"))
|
||||
{
|
||||
float curveVal = refractionFadingCurve.Evaluate(distPercent);
|
||||
m.SetFloat("_refraction", curveVal);
|
||||
//Debug.Log(gameObject.name + " 2 blend " + blend + " distance: " + distance);
|
||||
}
|
||||
}
|
||||
|
||||
if (useAlbedoAlphaFading)
|
||||
{
|
||||
if (m.HasProperty("_AlbedoAlpha"))
|
||||
{
|
||||
float curveVal = albedoAlphaFadeCurve.Evaluate(distPercent);
|
||||
m.SetFloat("_AlbedoAlpha", curveVal);
|
||||
//Debug.Log(gameObject.name + " 2 blend " + blend + " distance: " + distance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// returns worldspace bounds of this meshRenderer
|
||||
public Vector3[] GetPortalBounds(Camera reflectionCamera, float offset) // , float depthDistance, Camera.MonoOrStereoscopicEye eye
|
||||
{
|
||||
Bounds b = _myMeshFilter.sharedMesh.bounds;
|
||||
|
||||
// worldspace 0,0,0 is now the transform
|
||||
Vector3 boundsCenterOffset = Vector3.zero - b.center;
|
||||
b.center = transform.position - boundsCenterOffset;
|
||||
|
||||
|
||||
|
||||
//Vector3 closestPointOnPlane = ClosestPointOnBoundsFlattenedToPlane(reflectionCamera.transform.position);
|
||||
//float distance = Vector3.Distance(closestPointOnPlane, reflectionCamera.transform.position);
|
||||
/*if (offset < 0.015f)
|
||||
{
|
||||
b.center += transform.forward * -(0.015f - MathF.Max(offset, 0));
|
||||
}*/
|
||||
// move forward a bit
|
||||
|
||||
Vector3 bottomLeft = b.min; // bottomLeft
|
||||
Vector3 topRight = b.max; // topRight
|
||||
Vector3 topLeft = new Vector3(b.min.x, b.max.y, b.min.z);
|
||||
Vector3 bottomRight = new Vector3(b.max.x, b.min.y, b.min.z);
|
||||
|
||||
float scaleLarger = 1f;
|
||||
|
||||
bottomLeft = ScaleAroundPivot(bottomLeft, transform.position, transform.lossyScale * scaleLarger);
|
||||
topRight = ScaleAroundPivot(topRight, transform.position, transform.lossyScale * scaleLarger);
|
||||
topLeft = ScaleAroundPivot(topLeft, transform.position, transform.lossyScale * scaleLarger);
|
||||
bottomRight = ScaleAroundPivot(bottomRight, transform.position, transform.lossyScale * scaleLarger);
|
||||
|
||||
bottomLeft = RotatePointAroundPivot(bottomLeft, transform.position, transform.rotation);
|
||||
topRight = RotatePointAroundPivot(topRight, transform.position, transform.rotation);
|
||||
topLeft = RotatePointAroundPivot(topLeft, transform.position, transform.rotation);
|
||||
bottomRight = RotatePointAroundPivot(bottomRight, transform.position, transform.rotation);
|
||||
/*
|
||||
DebugExtension.DebugWireSphere(bottomLeft, Color.cyan, 0.2f);
|
||||
DebugExtension.DebugWireSphere(topRight, Color.red, 0.2f);
|
||||
DebugExtension.DebugWireSphere(topLeft, Color.green, 0.2f);
|
||||
DebugExtension.DebugWireSphere(bottomRight, Color.yellow, 0.2f);
|
||||
DebugExtension.DebugBounds(b, Color.cyan);
|
||||
*/
|
||||
Vector3[] points = new Vector3[4];
|
||||
points[0] = bottomLeft;
|
||||
points[1] = bottomRight;
|
||||
points[2] = topLeft;
|
||||
points[3] = topRight;
|
||||
|
||||
return points;
|
||||
}
|
||||
|
||||
private bool ProjectPointOnPlane(Vector3 origin, Vector3 target, ref Vector3 posOnPlane, float offset = 0)
|
||||
{
|
||||
//Plane p = new Plane(-transform.forward, transform.position + (-transform.forward * offset));
|
||||
//
|
||||
Ray r = new Ray(origin, (target - origin));
|
||||
float distance = 0;
|
||||
if(_plane.Raycast(r, out distance))
|
||||
{
|
||||
|
||||
posOnPlane = r.origin + (r.direction.normalized * (distance));
|
||||
//DebugExtension.DebugWireSphere(posOnPlane, Color.blue, 0.05f);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public Vector3 ScaleAroundPivot(Vector3 target, Vector3 pivot, Vector3 newScale)
|
||||
{
|
||||
// calc final position post-scale
|
||||
Vector3 dir = (target - pivot);
|
||||
dir.Scale(newScale);
|
||||
return pivot + dir;
|
||||
}
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
void OnSelectionChange()
|
||||
{
|
||||
if (this && isActiveAndEnabled)
|
||||
{
|
||||
if (gameObject == Selection.activeGameObject)
|
||||
{
|
||||
_isSelectedInEditor = true;
|
||||
|
||||
// make sure we're editing the source materials, not the instance
|
||||
if (Material != null)
|
||||
{
|
||||
Material.SetColor("_FadeColor", BlendColor);
|
||||
myMeshRenderer.sharedMaterial = Material;
|
||||
_material = Material;
|
||||
}
|
||||
}
|
||||
else if (_isSelectedInEditor)
|
||||
{
|
||||
// i'm no longer selected
|
||||
_isSelectedInEditor = false;
|
||||
|
||||
OnDisable();
|
||||
OnEnable();
|
||||
|
||||
if (_myRenderer != null)
|
||||
{
|
||||
_myRenderer.SurfaceGotDeselectedInEditor();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshMaterialInEditor()
|
||||
{
|
||||
OnDisable();
|
||||
OnEnable();
|
||||
}
|
||||
|
||||
|
||||
private void Update()
|
||||
{
|
||||
_plane = new Plane(-transform.forward, transform.position);
|
||||
|
||||
//if (_oldFadeColor != (FadeColor.r + FadeColor.g + FadeColor.b))
|
||||
if (!BlendColor.Equals(_oldFadeColor))
|
||||
{
|
||||
if (_material)
|
||||
{
|
||||
//Debug.Log(gameObject.name + " set prop 1");
|
||||
_material.SetColor("_FadeColor", BlendColor);
|
||||
}
|
||||
//_oldFadeColor = (FadeColor.r + FadeColor.g + FadeColor.b);
|
||||
_oldFadeColor = BlendColor;
|
||||
}
|
||||
|
||||
if (_oldMaterial != Material)
|
||||
{
|
||||
_material = Material;
|
||||
RefreshMaterialInEditor();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if !UNITY_EDITOR
|
||||
private void Update()
|
||||
{
|
||||
_plane = new Plane(-transform.forward, transform.position);
|
||||
}
|
||||
#endif
|
||||
|
||||
public void EnableTransparancy()
|
||||
{
|
||||
if (_material)
|
||||
{
|
||||
//Debug.Log(gameObject.name + " set prop 2");
|
||||
_material.SetInt("_useTransparency", 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void DisableTransparancy()
|
||||
{
|
||||
if (_material)
|
||||
{
|
||||
//Debug.Log(gameObject.name + " set prop 2");
|
||||
_material.SetInt("_useTransparency", 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void TurnOffForceEye()
|
||||
{
|
||||
if (_material && _material.HasProperty("_ForceEye"))
|
||||
{
|
||||
//Debug.Log(gameObject.name + " set prop 2");
|
||||
_material.SetInt("_ForceEye", -1);
|
||||
}
|
||||
}
|
||||
public void ForceLeftEye()
|
||||
{
|
||||
if (_material && _material.HasProperty("_ForceEye"))
|
||||
{
|
||||
//Debug.Log(gameObject.name + " set prop 2");
|
||||
_material.SetInt("_ForceEye", 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MinToAttribute : PropertyAttribute
|
||||
{
|
||||
public float? max;
|
||||
public float min;
|
||||
|
||||
public MinToAttribute() { }
|
||||
public MinToAttribute(float max, float min = 0)
|
||||
{
|
||||
this.max = max;
|
||||
this.min = min;
|
||||
}
|
||||
}
|
||||
|
||||
public class Triangle
|
||||
{
|
||||
private Vector3 point1, point2, point3;
|
||||
|
||||
public Triangle(Vector3 point1, Vector3 point2, Vector3 point3)
|
||||
{
|
||||
this.point1 = point1;
|
||||
this.point2 = point2;
|
||||
this.point3 = point3;
|
||||
}
|
||||
|
||||
public float SurfaceArea()
|
||||
{
|
||||
// Using Heron's Formula to calculate surface area
|
||||
float a = Vector3.Distance(point1, point2);
|
||||
float b = Vector3.Distance(point2, point3);
|
||||
float c = Vector3.Distance(point3, point1);
|
||||
float s = (a + b + c) / 2;
|
||||
return Mathf.Sqrt(s * (s - a) * (s - b) * (s - c));
|
||||
}
|
||||
|
||||
public float Height(Vector3 basePoint)
|
||||
{
|
||||
// Using the formula for height of a triangle
|
||||
Vector3 baseToVertex = Vector3.Cross(point2 - point1, point3 - point1);
|
||||
return Vector3.Dot(baseToVertex, basePoint - point1) / baseToVertex.magnitude;
|
||||
}
|
||||
|
||||
public float Height(float longSide)
|
||||
{
|
||||
return (2f * SurfaceArea()) / longSide;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[CustomPropertyDrawer(typeof(MinToAttribute))]
|
||||
public class MinToDrawer : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position,
|
||||
SerializedProperty property,
|
||||
GUIContent label)
|
||||
{
|
||||
var ctrlRect = EditorGUI.PrefixLabel(position, label);
|
||||
Rect[] r = SplitRectIn3(ctrlRect, 36, 5);
|
||||
var att = (MinToAttribute)attribute;
|
||||
var type = property.propertyType;
|
||||
if (type == SerializedPropertyType.Vector2)
|
||||
{
|
||||
var vec = property.vector2Value;
|
||||
float min = vec.x;
|
||||
float to = vec.y;
|
||||
min = EditorGUI.FloatField(r[0], min);
|
||||
to = EditorGUI.FloatField(r[2], to);
|
||||
EditorGUI.MinMaxSlider(r[1], ref min, ref to, att.min, att.max ?? to);
|
||||
vec = new Vector2(min < to ? min : to, to);
|
||||
property.vector2Value = vec;
|
||||
}
|
||||
else if (type == SerializedPropertyType.Vector2Int)
|
||||
{
|
||||
var vec = property.vector2IntValue;
|
||||
float min = vec.x;
|
||||
float to = vec.y;
|
||||
min = EditorGUI.IntField(r[0], (int)min);
|
||||
to = EditorGUI.IntField(r[2], (int)to);
|
||||
EditorGUI.MinMaxSlider(r[1], ref min, ref to, att.min, att.max ?? to);
|
||||
vec = new Vector2Int(Mathf.RoundToInt(min < to ? min : to), Mathf.RoundToInt(to));
|
||||
property.vector2IntValue = vec;
|
||||
}
|
||||
else
|
||||
EditorGUI.HelpBox(ctrlRect, "MinTo is for Vector2!!", MessageType.Error);
|
||||
}
|
||||
|
||||
public static Rect[] SplitRectIn3(Rect rect, int bordersSize, int space = 0)
|
||||
{
|
||||
var r = SplitRect(rect, 3);
|
||||
int pad = (int)r[0].width - bordersSize;
|
||||
int ps = pad + space;
|
||||
r[0].width = r[2].width -= ps;
|
||||
r[1].width += pad * 2;
|
||||
r[1].x -= pad;
|
||||
r[2].x += ps;
|
||||
return r;
|
||||
}
|
||||
public static Rect[] SplitRect(Rect a, int n)
|
||||
{
|
||||
Rect[] r = new Rect[n];
|
||||
for (int i = 0; i < n; ++i)
|
||||
r[i] = new Rect(a.x + a.width / n * i, a.y, a.width / n, a.height);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6df2b0603a5ae544fa0844a69cef2fc5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 228871
|
||||
packageName: Portals for VR
|
||||
packageVersion: 1.2.1
|
||||
assetPath: Assets/Fragilem17/Portals for VR/Scripts/PortalSurface.cs
|
||||
uploadId: 710348
|
||||
@@ -0,0 +1,253 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Fragilem17.MirrorsAndPortals
|
||||
{
|
||||
/**
|
||||
* Used to transport PortalableObjects to the linked portal defined in the portalSurface
|
||||
*/
|
||||
public class PortalTransporter : MonoBehaviour
|
||||
{
|
||||
private Portal _portal;
|
||||
public List<PortalableObject> portalableObjects = new List<PortalableObject>();
|
||||
//private List<CloneRenderer> cloneObjects = new List<CloneRenderer>();
|
||||
public HashSet<CloneRenderer> cloneObjects = new HashSet<CloneRenderer>();
|
||||
public HashSet<CloneRenderer> cloneObjectsActuallyTouching = new HashSet<CloneRenderer>();
|
||||
public HashSet<CloneRenderer> cloneObjectsToRemove = new HashSet<CloneRenderer>();
|
||||
private List<PortalAffectorSphere> portalAffectorSpheres = new List<PortalAffectorSphere>();
|
||||
private Vector3 _originalScale;
|
||||
|
||||
[Space(10)]
|
||||
[Header("Events")]
|
||||
public UnityEvent<PortalableObject> OnObjectEnteredPortal;
|
||||
public UnityEvent<PortalableObject> OnObjectTransportedAwayFromHere;
|
||||
public UnityEvent<PortalableObject> OnObjectTransportedToHere;
|
||||
public UnityEvent<PortalableObject> OnObjectExitedPortal;
|
||||
|
||||
[HideInInspector]
|
||||
public Collider MyCollider;
|
||||
|
||||
public enum PortalReason {
|
||||
Undefined,
|
||||
ExitedCurrentPortalCollider,
|
||||
EnteredOtherPortalCollider
|
||||
}
|
||||
|
||||
public Portal Portal { get => _portal; }
|
||||
|
||||
public void Initialise()
|
||||
{
|
||||
MyCollider = GetComponent<Collider>();
|
||||
if (!MyCollider)
|
||||
{
|
||||
Debug.LogWarning(PortalUtils.Colorize("[PORTALS] ", PortalUtils.DebugColors.Warn, true) + name + " has a PortalTransporter Component but no trigger Collider, add a big enough Collider for things to hit it before reaching the actual portal.");
|
||||
}
|
||||
else
|
||||
{
|
||||
MyCollider.isTrigger = true;
|
||||
}
|
||||
|
||||
Rigidbody rb = GetComponent<Rigidbody>();
|
||||
if (!rb)
|
||||
{
|
||||
Debug.LogWarning(PortalUtils.Colorize("[PORTALS] ", PortalUtils.DebugColors.Warn, true) + name + " has a PortalTransporter Component but no RigidBody Component. Add a (Kinematic) Rigidbody Component to this GameObject.");
|
||||
}
|
||||
|
||||
_portal = GetComponentInParent<Portal>();
|
||||
if (!_portal)
|
||||
{
|
||||
Debug.LogWarning(PortalUtils.Colorize("[PORTALS] ", PortalUtils.DebugColors.Warn, true) + name + " has a PortalTransporter Component but no Portal Component, add a Portal Component to this or a parent GameObject.");
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnEnable()
|
||||
{
|
||||
Initialise();
|
||||
}
|
||||
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
//CheckNeedPortal();
|
||||
}
|
||||
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
//CheckNeedPortal();
|
||||
}
|
||||
|
||||
protected void Update()
|
||||
{
|
||||
CheckNeedPortal();
|
||||
}
|
||||
|
||||
protected void CheckNeedPortal()
|
||||
{
|
||||
PortalableObject p = null;
|
||||
for (int i = 0; i < portalableObjects.Count; ++i)
|
||||
{
|
||||
p = portalableObjects[i];
|
||||
if (p)
|
||||
{
|
||||
Vector3 objPos = _portal.PortalSurface.transform.InverseTransformPoint(p.transform.position);
|
||||
|
||||
if (objPos.z > 0)
|
||||
{
|
||||
PortalableObject po = portalableObjects[i];
|
||||
if (po.CanPortal())
|
||||
{
|
||||
//Debug.Log("PortalTransporter " + Portal.name + " : fixedUpdate z > 0 - doing portal on " + po.name + " : " + objPos.z);
|
||||
|
||||
if (_portal.OtherPortal && _portal.OtherPortal.PortalTransporter)
|
||||
{
|
||||
// only trigger the ExternalTriggerEnter if we're actually telepoting inside our collider!
|
||||
_portal.OtherPortal.PortalTransporter.ExternalTriggerEnter(po.gameObject, false);
|
||||
_portal.OtherPortal.PortalTransporter.OnObjectTransportedToHere.Invoke(po);
|
||||
}
|
||||
po.PortalFrom(_portal);
|
||||
OnObjectTransportedAwayFromHere.Invoke(po);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void ExternalTriggerEnter(GameObject other, bool fromPhysics = false)
|
||||
{
|
||||
// first trigger the exit in the other portal
|
||||
if (!fromPhysics && _portal.OtherPortal && _portal.OtherPortal.PortalTransporter)
|
||||
{
|
||||
_portal.OtherPortal.PortalTransporter.ExternalTriggerExit(other, fromPhysics, PortalReason.EnteredOtherPortalCollider);
|
||||
}
|
||||
|
||||
Vector3 objPos = _portal.PortalSurface.transform.InverseTransformPoint(other.transform.position);
|
||||
// did we enter in front of the portal?
|
||||
//Debug.Log("ExternalTriggerEnter objPos: " + other.name + " " + objPos.z + " " + fromPhysics + " :" + Portal.name);
|
||||
if (!fromPhysics || (fromPhysics && objPos.z < 0))
|
||||
{
|
||||
PortalableObject obj = other.GetComponent<PortalableObject>();
|
||||
if (obj && obj.isActiveAndEnabled && !portalableObjects.Contains(obj))
|
||||
{
|
||||
//Debug.Log("Adding to portal list of " + _portal.name + " object:" + other.name);
|
||||
portalableObjects.Add(obj);
|
||||
//obj.OnExitPortalCollider.AddListener(onPortalableObjectExitPortalCollider);
|
||||
|
||||
obj.SetIsInPortal(_portal);
|
||||
OnObjectEnteredPortal.Invoke(obj);
|
||||
}
|
||||
else
|
||||
{
|
||||
PortalableObjectCollider helper = other.GetComponent<PortalableObjectCollider>();
|
||||
if (helper && helper.isActiveAndEnabled && !portalableObjects.Contains(helper.PortalableObject))
|
||||
{
|
||||
//Debug.Log("Adding to portal list of " + _portal.name + " object:" + other.name);
|
||||
portalableObjects.Add(helper.PortalableObject);
|
||||
//obj.OnExitPortalCollider.AddListener(onPortalableObjectExitPortalCollider);
|
||||
|
||||
helper.PortalableObject.SetIsInPortal(_portal);
|
||||
OnObjectEnteredPortal.Invoke(helper.PortalableObject);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CloneRenderer cloneObject = other.GetComponent<CloneRenderer>();
|
||||
if (cloneObject && cloneObject.isActiveAndEnabled && !cloneObjects.Contains(cloneObject))
|
||||
{
|
||||
cloneObjects.Add(cloneObject);
|
||||
cloneObject.SetIsInPortal(_portal, true);
|
||||
}
|
||||
|
||||
PortalAffectorSphere affectorSphere = other.GetComponent<PortalAffectorSphere>();
|
||||
if (affectorSphere && affectorSphere.isActiveAndEnabled && !portalAffectorSpheres.Contains(affectorSphere))
|
||||
{
|
||||
//if (fromPhysics)
|
||||
//{
|
||||
portalAffectorSpheres.Add(affectorSphere);
|
||||
//}
|
||||
affectorSphere.SetIsInPortal(_portal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*private void onPortalableObjectExitPortalCollider(PortalableObject obj, Portal p)
|
||||
{
|
||||
if (p == Portal)
|
||||
{
|
||||
ExternalTriggerExit(obj.gameObject, false);
|
||||
}
|
||||
}*/
|
||||
|
||||
public void ExternalTriggerExit(GameObject other, bool fromPhysics = false, PortalReason reason = PortalReason.Undefined)
|
||||
{
|
||||
PortalableObject portalableObj = other.GetComponent<PortalableObject>();
|
||||
|
||||
/*
|
||||
bool isPortallingAlongWithMasterPortalable = false;
|
||||
if (portalableObj) {
|
||||
//portalableObj.OnExitPortalCollider.RemoveListener(onPortalableObjectExitPortalCollider);
|
||||
isPortallingAlongWithMasterPortalable = portalableObj.EnablePortalAlongWithMasterPortalable;
|
||||
}
|
||||
|
||||
// todo: as long as we're grabbing something, and it's gonna portal along with the player, then don't exit the portal when it's collider exits this transporter.
|
||||
// but, what to do when the player does not portal?
|
||||
if (reason == PortalReason.ExitedCurrentPortalCollider && isPortallingAlongWithMasterPortalable)
|
||||
{
|
||||
// are we on the other side of the surface when exiting the collider? then keep it inside the portal
|
||||
Vector3 objPos = _portal.PortalSurface.transform.InverseTransformPoint(other.transform.position);
|
||||
Debug.Log("objPos: " + objPos.z);
|
||||
if (objPos.z > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
CloneRenderer cloneObject = other.GetComponent<CloneRenderer>();
|
||||
/*if (cloneObject)
|
||||
{
|
||||
Debug.Log(cloneObject.name + " exits portal " + Portal.name + " IF " + cloneObjects.Contains(cloneObject) + " AND NOT isPortallingAlongWithMasterPortalable: " + isPortallingAlongWithMasterPortalable);
|
||||
}*/
|
||||
|
||||
if (cloneObject && cloneObjects.Contains(cloneObject))
|
||||
{
|
||||
cloneObjects.Remove(cloneObject);
|
||||
cloneObject.ExitPortal(_portal, fromPhysics);
|
||||
}
|
||||
|
||||
if (portalableObj && portalableObjects.Contains(portalableObj))
|
||||
{
|
||||
//Debug.Log("Exit Portal " + gameObject.name);
|
||||
//Debug.Log("Removing from portal list of " + _portal.name + " object:" + other.name);
|
||||
//Debug.Log("PortalableObject " + portalableObj.name + " ExitsPortal: " + _portal.name + " fromPhysics: " + fromPhysics);
|
||||
portalableObjects.Remove(portalableObj);
|
||||
portalableObj.ExitPortal(_portal);
|
||||
OnObjectExitedPortal.Invoke(portalableObj);
|
||||
}
|
||||
|
||||
PortalAffectorSphere affectorSphere = other.GetComponent<PortalAffectorSphere>();
|
||||
if (affectorSphere && portalAffectorSpheres.Contains(affectorSphere))
|
||||
{
|
||||
portalAffectorSpheres.Remove(affectorSphere);
|
||||
affectorSphere.ExitPortal(_portal);
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnTriggerEnter(Collider other)
|
||||
{
|
||||
//Debug.Log("OnTriggerEnter: " + other.name);
|
||||
ExternalTriggerEnter(other.gameObject, true);
|
||||
}
|
||||
|
||||
protected void OnTriggerExit(Collider other)
|
||||
{
|
||||
ExternalTriggerExit(other.gameObject, true, PortalReason.ExitedCurrentPortalCollider);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d80c73be3fe0d35469084ced2f981279
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 228871
|
||||
packageName: Portals for VR
|
||||
packageVersion: 1.2.1
|
||||
assetPath: Assets/Fragilem17/Portals for VR/Scripts/PortalTransporter.cs
|
||||
uploadId: 710348
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Fragilem17.MirrorsAndPortals
|
||||
{
|
||||
[ExecuteInEditMode]
|
||||
public class PortalUtil_FollowTransform : MonoBehaviour
|
||||
{
|
||||
public Transform Target;
|
||||
public bool FollowRotation = true;
|
||||
|
||||
void Update()
|
||||
{
|
||||
Follow();
|
||||
}
|
||||
|
||||
public void Follow() {
|
||||
if (Target)
|
||||
{
|
||||
transform.position = Target.position;
|
||||
if (FollowRotation)
|
||||
{
|
||||
transform.rotation = Target.rotation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e45716cad1ae61742980d5f24affa708
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -45
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 228871
|
||||
packageName: Portals for VR
|
||||
packageVersion: 1.2.1
|
||||
assetPath: Assets/Fragilem17/Portals for VR/Scripts/PortalUtil_FollowTransform.cs
|
||||
uploadId: 710348
|
||||
@@ -0,0 +1,362 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
namespace Fragilem17.MirrorsAndPortals
|
||||
{
|
||||
public class PortalUtils
|
||||
{
|
||||
public enum DebugColors
|
||||
{
|
||||
Info,
|
||||
Warn,
|
||||
Error
|
||||
}
|
||||
|
||||
public static string Colorize(string text, DebugColors color, bool bold = false)
|
||||
{
|
||||
string c = "00BC0E";
|
||||
if (color == DebugColors.Error)
|
||||
{
|
||||
c = "BE0000";
|
||||
}
|
||||
else if (color == DebugColors.Warn)
|
||||
{
|
||||
c = "FFB900";
|
||||
}
|
||||
|
||||
return "<color=#" + c + ">" + (bold ? "<b>" : "") + text + (bold ? "</b>" : "") + "</color>";
|
||||
}
|
||||
|
||||
// taken from http://www.terathon.com/code/oblique.html
|
||||
public static void MakeProjectionMatrixOblique(ref Matrix4x4 matrix, Vector4 clipPlane)
|
||||
{
|
||||
Vector4 q = matrix.inverse * new Vector4(Mathf.Sign(clipPlane.x), Mathf.Sign(clipPlane.y), 1.0f, 1.0f);
|
||||
Vector4 c = clipPlane * (2.0F / (Vector4.Dot(clipPlane, q)));
|
||||
|
||||
// Replace the third row of the projection matrix
|
||||
matrix[2] = c.x - matrix[3];
|
||||
matrix[6] = c.y - matrix[7];
|
||||
matrix[10] = c.z - matrix[11];
|
||||
matrix[14] = c.w - matrix[15];
|
||||
|
||||
|
||||
/*
|
||||
Vector4 q;
|
||||
|
||||
// Calculate the clip-space corner point opposite the clipping plane
|
||||
// as (sgn(clipPlane.x), sgn(clipPlane.y), 1, 1) and
|
||||
// transform it into camera space by multiplying it
|
||||
// by the inverse of the projection matrix
|
||||
|
||||
q.x = (sgn(clipPlane.x) + matrix[8]) / matrix[0];
|
||||
q.y = (sgn(clipPlane.y) + matrix[9]) / matrix[5];
|
||||
q.z = -1.0F;
|
||||
q.w = (1.0F + matrix[10]) / matrix[14];
|
||||
|
||||
// Calculate the scaled plane vector
|
||||
Vector4 c = clipPlane * (2.0F / Vector4.Dot(clipPlane, q));
|
||||
|
||||
// Replace the third row of the projection matrix
|
||||
matrix[2] = c.x;
|
||||
matrix[6] = c.y;
|
||||
matrix[10] = c.z + 1.0F;
|
||||
matrix[14] = c.w;
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
public static Matrix4x4 OffAxisProjectionMatrix(float near, float far, Vector3 pa, Vector3 pb, Vector3 pc, Vector3 pe)
|
||||
{
|
||||
Vector3 va; // from pe to pa
|
||||
Vector3 vb; // from pe to pb
|
||||
Vector3 vc; // from pe to pc
|
||||
Vector3 vr; // right axis of screen
|
||||
Vector3 vu; // up axis of screen
|
||||
Vector3 vn; // normal vector of screen
|
||||
|
||||
float l; // distance to left screen edge
|
||||
float r; // distance to right screen edge
|
||||
float b; // distance to bottom screen edge
|
||||
float t; // distance to top screen edge
|
||||
float d; // distance from eye to screen
|
||||
|
||||
vr = pb - pa;
|
||||
vu = pc - pa;
|
||||
va = pa - pe;
|
||||
vb = pb - pe;
|
||||
vc = pc - pe;
|
||||
|
||||
// are we looking at the backface of the plane object?
|
||||
if (Vector3.Dot(-Vector3.Cross(va, vc), vb) < 0.0)
|
||||
{
|
||||
// mirror points along the z axis (most users
|
||||
// probably expect the x axis to stay fixed)
|
||||
vu = -vu;
|
||||
pa = pc;
|
||||
pb = pa + vr;
|
||||
pc = pa + vu;
|
||||
va = pa - pe;
|
||||
vb = pb - pe;
|
||||
vc = pc - pe;
|
||||
}
|
||||
|
||||
vr.Normalize();
|
||||
vu.Normalize();
|
||||
vn = -Vector3.Cross(vr, vu);
|
||||
// we need the minus sign because Unity
|
||||
// uses a left-handed coordinate system
|
||||
vn.Normalize();
|
||||
|
||||
d = -Vector3.Dot(va, vn);
|
||||
|
||||
// Set near clip plane
|
||||
near = d; // + _clippingDistance;
|
||||
|
||||
l = Vector3.Dot(vr, va) * near / d;
|
||||
r = Vector3.Dot(vr, vb) * near / d;
|
||||
b = Vector3.Dot(vu, va) * near / d;
|
||||
t = Vector3.Dot(vu, vc) * near / d;
|
||||
|
||||
Matrix4x4 p = new Matrix4x4(); // projection matrix
|
||||
p[0, 0] = 2.0f * near / (r - l);
|
||||
p[0, 1] = 0.0f;
|
||||
p[0, 2] = (r + l) / (r - l);
|
||||
p[0, 3] = 0.0f;
|
||||
|
||||
p[1, 0] = 0.0f;
|
||||
p[1, 1] = 2.0f * near / (t - b);
|
||||
p[1, 2] = (t + b) / (t - b);
|
||||
p[1, 3] = 0.0f;
|
||||
|
||||
p[2, 0] = 0.0f;
|
||||
p[2, 1] = 0.0f;
|
||||
p[2, 2] = (far + near) / (near - far);
|
||||
p[2, 3] = 2.0f * far * near / (near - far);
|
||||
|
||||
p[3, 0] = 0.0f;
|
||||
p[3, 1] = 0.0f;
|
||||
p[3, 2] = -1.0f;
|
||||
p[3, 3] = 0.0f;
|
||||
|
||||
Matrix4x4 rm = new Matrix4x4(); // rotation matrix;
|
||||
rm[0, 0] = vr.x;
|
||||
rm[0, 1] = vr.y;
|
||||
rm[0, 2] = vr.z;
|
||||
rm[0, 3] = 0.0f;
|
||||
|
||||
rm[1, 0] = vu.x;
|
||||
rm[1, 1] = vu.y;
|
||||
rm[1, 2] = vu.z;
|
||||
rm[1, 3] = 0.0f;
|
||||
|
||||
rm[2, 0] = vn.x;
|
||||
rm[2, 1] = vn.y;
|
||||
rm[2, 2] = vn.z;
|
||||
rm[2, 3] = 0.0f;
|
||||
|
||||
rm[3, 0] = 0.0f;
|
||||
rm[3, 1] = 0.0f;
|
||||
rm[3, 2] = 0.0f;
|
||||
rm[3, 3] = 1.0f;
|
||||
|
||||
Matrix4x4 tm = new Matrix4x4(); // translation matrix;
|
||||
tm[0, 0] = 1.0f;
|
||||
tm[0, 1] = 0.0f;
|
||||
tm[0, 2] = 0.0f;
|
||||
tm[0, 3] = -pe.x;
|
||||
|
||||
tm[1, 0] = 0.0f;
|
||||
tm[1, 1] = 1.0f;
|
||||
tm[1, 2] = 0.0f;
|
||||
tm[1, 3] = -pe.y;
|
||||
|
||||
tm[2, 0] = 0.0f;
|
||||
tm[2, 1] = 0.0f;
|
||||
tm[2, 2] = 1.0f;
|
||||
tm[2, 3] = -pe.z;
|
||||
|
||||
tm[3, 0] = 0.0f;
|
||||
tm[3, 1] = 0.0f;
|
||||
tm[3, 2] = 0.0f;
|
||||
tm[3, 3] = 1.0f;
|
||||
|
||||
Matrix4x4 worldToCameraMatrix = rm * tm;
|
||||
return p * worldToCameraMatrix;
|
||||
}
|
||||
|
||||
// Extended sign: returns -1, 0 or 1 based on sign of a
|
||||
private static float sgn(float a)
|
||||
{
|
||||
if (a > 0.0f) return 1.0f;
|
||||
if (a < 0.0f) return -1.0f;
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
// Given position/normal of the plane, calculates plane in camera space.
|
||||
public static Vector4 CameraSpacePlane(Matrix4x4 worldToCameraMatrix, Vector3 pos, Vector3 normal, float sideSign, float clippingPlaneOffset)
|
||||
{
|
||||
Vector3 offsetPos = pos + normal * clippingPlaneOffset;
|
||||
Vector3 cpos = worldToCameraMatrix.MultiplyPoint(offsetPos);
|
||||
Vector3 cnormal = worldToCameraMatrix.MultiplyVector(normal).normalized * sideSign;
|
||||
return new Vector4(cnormal.x, cnormal.y, cnormal.z, -Vector3.Dot(cpos, cnormal));
|
||||
}
|
||||
|
||||
/*
|
||||
// Calculates reflection matrix around the given plane
|
||||
public static void CalculateReflectionMatrix(ref Matrix4x4 reflectionMat, Vector4 plane)
|
||||
{
|
||||
reflectionMat.m00 = (1F - 2F * plane[0] * plane[0]);
|
||||
reflectionMat.m01 = (-2F * plane[0] * plane[1]);
|
||||
reflectionMat.m02 = (-2F * plane[0] * plane[2]);
|
||||
reflectionMat.m03 = (-2F * plane[3] * plane[0]);
|
||||
|
||||
reflectionMat.m10 = (-2F * plane[1] * plane[0]);
|
||||
reflectionMat.m11 = (1F - 2F * plane[1] * plane[1]);
|
||||
reflectionMat.m12 = (-2F * plane[1] * plane[2]);
|
||||
reflectionMat.m13 = (-2F * plane[3] * plane[1]);
|
||||
|
||||
reflectionMat.m20 = (-2F * plane[2] * plane[0]);
|
||||
reflectionMat.m21 = (-2F * plane[2] * plane[1]);
|
||||
reflectionMat.m22 = (1F - 2F * plane[2] * plane[2]);
|
||||
reflectionMat.m23 = (-2F * plane[3] * plane[2]);
|
||||
|
||||
reflectionMat.m30 = 0F;
|
||||
reflectionMat.m31 = 0F;
|
||||
reflectionMat.m32 = 0F;
|
||||
reflectionMat.m33 = 1F;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class SerializableCurve
|
||||
{
|
||||
public SerializableKeyframe[] keys;
|
||||
public string postWrapMode;
|
||||
public string preWrapMode;
|
||||
|
||||
[Serializable]
|
||||
public class SerializableKeyframe
|
||||
{
|
||||
public Single inTangent;
|
||||
public Single inWeight;
|
||||
public Single outTangent;
|
||||
public Single outWeight;
|
||||
public Int32 weightedMode;
|
||||
//public Int32 tangentMode;
|
||||
public Single time;
|
||||
public Single value;
|
||||
|
||||
public SerializableKeyframe(Keyframe original, int index)
|
||||
{
|
||||
inTangent = original.inTangent;
|
||||
inWeight = original.inWeight;
|
||||
|
||||
outTangent = original.outTangent;
|
||||
outWeight = original.outWeight;
|
||||
|
||||
weightedMode = (int)original.weightedMode;
|
||||
//tangentMode = original.tangentMode;
|
||||
|
||||
time = original.time;
|
||||
value = original.value;
|
||||
}
|
||||
}
|
||||
|
||||
public SerializableCurve(AnimationCurve original)
|
||||
{
|
||||
postWrapMode = getWrapModeAsString(original.postWrapMode);
|
||||
preWrapMode = getWrapModeAsString(original.preWrapMode);
|
||||
keys = new SerializableKeyframe[original.length];
|
||||
for (int i = 0; i < original.keys.Length; i++)
|
||||
{
|
||||
keys[i] = new SerializableKeyframe(original.keys[i], i);
|
||||
}
|
||||
}
|
||||
|
||||
public AnimationCurve toCurve()
|
||||
{
|
||||
AnimationCurve res = new AnimationCurve();
|
||||
res.postWrapMode = getWrapMode(postWrapMode);
|
||||
res.preWrapMode = getWrapMode(preWrapMode);
|
||||
Keyframe[] newKeys = new Keyframe[keys.Length];
|
||||
for (int i = 0; i < keys.Length; i++)
|
||||
{
|
||||
SerializableKeyframe aux = keys[i];
|
||||
Keyframe newK = new Keyframe();
|
||||
newK.inTangent = aux.inTangent;
|
||||
newK.inWeight = aux.inWeight;
|
||||
newK.outTangent = aux.outTangent;
|
||||
newK.outWeight = aux.outWeight;
|
||||
//newK.tangentMode = aux.tangentMode;
|
||||
newK.weightedMode = (WeightedMode)aux.weightedMode;
|
||||
newK.time = aux.time;
|
||||
newK.value = aux.value;
|
||||
newKeys[i] = newK;
|
||||
}
|
||||
res.keys = newKeys;
|
||||
return res;
|
||||
}
|
||||
|
||||
private WrapMode getWrapMode(String mode)
|
||||
{
|
||||
if (mode.Equals("Clamp"))
|
||||
{
|
||||
return WrapMode.Clamp;
|
||||
}
|
||||
if (mode.Equals("ClampForever"))
|
||||
{
|
||||
return WrapMode.ClampForever;
|
||||
}
|
||||
if (mode.Equals("Default"))
|
||||
{
|
||||
return WrapMode.Default;
|
||||
}
|
||||
if (mode.Equals("Loop"))
|
||||
{
|
||||
return WrapMode.Loop;
|
||||
}
|
||||
if (mode.Equals("Once"))
|
||||
{
|
||||
return WrapMode.Once;
|
||||
}
|
||||
if (mode.Equals("PingPong"))
|
||||
{
|
||||
return WrapMode.PingPong;
|
||||
}
|
||||
Debug.LogError("Wat is this wrap mode???");
|
||||
return WrapMode.Default;
|
||||
}
|
||||
|
||||
private string getWrapModeAsString(WrapMode mode)
|
||||
{
|
||||
if (mode.Equals(WrapMode.Clamp))
|
||||
{
|
||||
return "Clamp";
|
||||
}
|
||||
if (mode.Equals(WrapMode.ClampForever))
|
||||
{
|
||||
return "ClampForever";
|
||||
}
|
||||
if (mode.Equals(WrapMode.Default))
|
||||
{
|
||||
return "Default";
|
||||
}
|
||||
if (mode.Equals(WrapMode.Loop))
|
||||
{
|
||||
return "Loop";
|
||||
}
|
||||
if (mode.Equals(WrapMode.Once))
|
||||
{
|
||||
return "Once";
|
||||
}
|
||||
if (mode.Equals(WrapMode.PingPong))
|
||||
{
|
||||
return "PingPong";
|
||||
}
|
||||
Debug.LogError("Wat is this wrap mode???");
|
||||
return "f you";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 309421c83ba44944e8ec30c6bdc74f30
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 228871
|
||||
packageName: Portals for VR
|
||||
packageVersion: 1.2.1
|
||||
assetPath: Assets/Fragilem17/Portals for VR/Scripts/PortalUtils.cs
|
||||
uploadId: 710348
|
||||
@@ -0,0 +1,436 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
namespace Fragilem17.MirrorsAndPortals
|
||||
{
|
||||
[RequireComponent(typeof(Collider))]
|
||||
public class PortalableObject : MonoBehaviour
|
||||
{
|
||||
[Tooltip("Leave empty to target this gameObject, use this to transport a PlayerController as soon as the 'head' passes through.")]
|
||||
[FormerlySerializedAs("TransformToTransport")]
|
||||
public Transform TransformToPortal;
|
||||
|
||||
[Tooltip("When true, this object will be transported by a portal when passing through it. unless PortalWithMasterPortalable is turned on, then it will only portal when the master is portalled. ")]
|
||||
[FormerlySerializedAs("AllowTransporting")]
|
||||
public bool PortallingEnabled = true;
|
||||
|
||||
[Space(10)] // 10 pixels of spacing here.
|
||||
|
||||
[Header("Events")]
|
||||
public UnityEvent<Portal> OnEnterPortalCollider;
|
||||
|
||||
[FormerlySerializedAs("OnPreWarpEvent")]
|
||||
public UnityEvent<PortalableObject, Portal> OnPrePortalEvent;
|
||||
|
||||
[FormerlySerializedAs("OnPostWarpEvent")]
|
||||
public UnityEvent<PortalableObject, Portal> OnPostPortalEvent;
|
||||
|
||||
public UnityEvent<PortalableObject, Portal> OnExitPortalCollider;
|
||||
|
||||
|
||||
[Space(10)] // 10 pixels of spacing here.
|
||||
|
||||
[Tooltip("Turn on if this is your playerController.")]
|
||||
public bool IsMasterPortalableObject;
|
||||
|
||||
[Tooltip("When true, this object will transport keeping it's relative distance from the MasterPortalableObject (your PlayerController)")]
|
||||
[FormerlySerializedAs("PortalWithMasterPortalable")]
|
||||
public bool PortalAlongWithMasterPortalable;
|
||||
|
||||
|
||||
protected Portal _inPortal;
|
||||
protected TransformTargetOfPortalableObject _myTransformTargetOfPortalableObject;
|
||||
protected Rigidbody _rigidbody;
|
||||
protected CharacterController _characterController;
|
||||
protected Collider[] _colliders;
|
||||
public List<Rigidbody> RigidbodiesToPortal;
|
||||
|
||||
[HideInInspector]
|
||||
public CloneRenderer[] childCloneRenderers;
|
||||
|
||||
private static readonly Quaternion halfTurn = Quaternion.Euler(0.0f, 180.0f, 0.0f);
|
||||
|
||||
private bool childOfAnotherPortalable = false;
|
||||
|
||||
public static PortalableObject MasterPortalable;
|
||||
|
||||
public bool EnablePortalAlongWithMasterPortalable
|
||||
{
|
||||
get => PortalAlongWithMasterPortalable;
|
||||
set
|
||||
{
|
||||
PortalAlongWithMasterPortalable = value;
|
||||
/*if (PortalAlongWithMasterPortalable != value)
|
||||
{
|
||||
PortalAlongWithMasterPortalable = value;
|
||||
if (!PortalAlongWithMasterPortalable && _inPortal != null)
|
||||
{
|
||||
// if we're no longer gonna portal along, then make sure we exit the current portal
|
||||
ExitPortal(_inPortal);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
public bool SetPortallingEnabled { get => PortallingEnabled; set => PortallingEnabled = value; }
|
||||
|
||||
[Tooltip("Assign a transform and it will always be positioned on the other side of the nearest portal relative to this object")]
|
||||
public Transform ClonePositionToClosestPortal;
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
//Debug.Log("AWAKE!! " + name);
|
||||
if (!TransformToPortal)
|
||||
{
|
||||
TransformToPortal = GetComponent<Transform>();
|
||||
}
|
||||
|
||||
if (MasterPortalable != null && IsMasterPortalableObject && MasterPortalable != this)
|
||||
{
|
||||
Debug.LogError("There appears to be a second MasterPortalableObject in the scene, there should be only one! (" + name + ")");
|
||||
}
|
||||
|
||||
if (IsMasterPortalableObject)
|
||||
{
|
||||
MasterPortalable = this;
|
||||
}
|
||||
|
||||
|
||||
_characterController = TransformToPortal.GetComponentInChildren<CharacterController>();
|
||||
|
||||
_rigidbody = TransformToPortal.GetComponent<Rigidbody>();
|
||||
_colliders = TransformToPortal.GetComponentsInChildren<Collider>(true);
|
||||
}
|
||||
|
||||
protected virtual void LateUpdate()
|
||||
{
|
||||
if (ClonePositionToClosestPortal)
|
||||
{
|
||||
Portal closest = PortalRenderer.FindClosestPortalInAllRenderers(transform.position);
|
||||
|
||||
Transform _inTransform = closest.PortalSurface.transform;
|
||||
Transform _outTransform = closest.OtherPortal.PortalSurface.transform;
|
||||
|
||||
float scaleFactor = (closest.OtherPortal.transform.lossyScale.x / closest.transform.lossyScale.x);
|
||||
ClonePositionToClosestPortal.transform.localScale = transform.lossyScale * scaleFactor;
|
||||
|
||||
// Update position of clone.
|
||||
Vector3 relativePos = _inTransform.InverseTransformPoint(transform.position);
|
||||
relativePos = halfTurn * relativePos;
|
||||
ClonePositionToClosestPortal.transform.position = _outTransform.TransformPoint(relativePos);
|
||||
|
||||
// Update rotation of clone.
|
||||
Quaternion relativeRot = Quaternion.Inverse(_inTransform.rotation) * transform.rotation;
|
||||
relativeRot = halfTurn * relativeRot;
|
||||
ClonePositionToClosestPortal.transform.rotation = _outTransform.rotation * relativeRot;
|
||||
}
|
||||
}
|
||||
|
||||
protected void OnEnable()
|
||||
{
|
||||
// todo, if we change the TransformToTransport pointer, we need to remove the target below
|
||||
_myTransformTargetOfPortalableObject = TransformToPortal.GetComponent<TransformTargetOfPortalableObject>();
|
||||
if (_myTransformTargetOfPortalableObject == null)
|
||||
{
|
||||
_myTransformTargetOfPortalableObject = TransformToPortal.gameObject.AddComponent<TransformTargetOfPortalableObject>();
|
||||
}
|
||||
_myTransformTargetOfPortalableObject.PortalableObject = this;
|
||||
|
||||
if (IsMasterPortalableObject)
|
||||
{
|
||||
MasterPortalable = this;
|
||||
}
|
||||
|
||||
if (MasterPortalable != null && MasterPortalable != this)
|
||||
{
|
||||
MasterPortalable.OnEnterPortalCollider.RemoveListener(OnMasterPortalEnterPortalCollider);
|
||||
MasterPortalable.OnExitPortalCollider.RemoveListener(OnMasterPortalExitPortalCollider);
|
||||
MasterPortalable.OnPrePortalEvent.RemoveListener(OnMasterPortalablePreWarp);
|
||||
MasterPortalable.OnPostPortalEvent.RemoveListener(OnMasterPortalableWarped);
|
||||
|
||||
//Debug.Log("ADDING LISTENER! " + name);
|
||||
MasterPortalable.OnEnterPortalCollider.AddListener(OnMasterPortalEnterPortalCollider);
|
||||
MasterPortalable.OnExitPortalCollider.AddListener(OnMasterPortalExitPortalCollider);
|
||||
MasterPortalable.OnPrePortalEvent.AddListener(OnMasterPortalablePreWarp);
|
||||
MasterPortalable.OnPostPortalEvent.AddListener(OnMasterPortalableWarped);
|
||||
}
|
||||
|
||||
OnTransformParentChanged();
|
||||
}
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
// Awake and OnEnable are called together, Start is called when all other components' Awake and OnEnable have been Called
|
||||
// only here are we sure a MasterPortalable exists.
|
||||
OnEnable();
|
||||
}
|
||||
|
||||
protected void OnDisable()
|
||||
{
|
||||
if (MasterPortalable != null && MasterPortalable != this)
|
||||
{
|
||||
MasterPortalable.OnEnterPortalCollider.RemoveListener(OnMasterPortalEnterPortalCollider);
|
||||
MasterPortalable.OnExitPortalCollider.RemoveListener(OnMasterPortalExitPortalCollider);
|
||||
MasterPortalable.OnPrePortalEvent.RemoveListener(OnMasterPortalablePreWarp);
|
||||
MasterPortalable.OnPostPortalEvent.RemoveListener(OnMasterPortalableWarped);
|
||||
}
|
||||
if (IsMasterPortalableObject)
|
||||
{
|
||||
MasterPortalable = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected virtual void OnMasterPortalExitPortalCollider(PortalableObject masterObject, Portal portal)
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void OnMasterPortalEnterPortalCollider(Portal portal)
|
||||
{
|
||||
if (PortalAlongWithMasterPortalable)
|
||||
{
|
||||
SetIsInPortal(portal);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnMasterPortalablePreWarp(PortalableObject masterObject, Portal fromPortal)
|
||||
{
|
||||
if (PortalAlongWithMasterPortalable)
|
||||
{
|
||||
PreWarp(fromPortal);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnMasterPortalableWarped(PortalableObject masterObject, Portal fromPortal)
|
||||
{
|
||||
if (PortalAlongWithMasterPortalable)
|
||||
{
|
||||
//Debug.Log("OnMasterPortalableWarped! i will go along " + name);
|
||||
PortalFrom(fromPortal, true);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnTransformParentChanged()
|
||||
{
|
||||
CheckForParentPortalables();
|
||||
}
|
||||
|
||||
protected void CheckForParentPortalables()
|
||||
{
|
||||
// check for the existance of a parent PortalableObject
|
||||
TransformTargetOfPortalableObject[] parentPortalables = GetComponentsInParent<TransformTargetOfPortalableObject>();
|
||||
//Debug.Log("check OnTransformParentChanged: " + name + " :" + parentPortalables.Length);
|
||||
childOfAnotherPortalable = (parentPortalables.Length > 1);
|
||||
}
|
||||
|
||||
public virtual void SetIsInPortal(Portal portal)
|
||||
{
|
||||
ExitPortal(portal.OtherPortal);
|
||||
|
||||
_inPortal = portal;
|
||||
OnEnterPortalCollider?.Invoke(portal);
|
||||
if (PortallingEnabled) // !childOfAnotherPortalable &&
|
||||
{
|
||||
//Debug.Log("SetIsInPortal " + this.name + " inPortal: " + portal.name + " turning OFF colliders ");
|
||||
if (portal.wallCollider)
|
||||
{
|
||||
// if that's the case.. then we can turn of the colliders
|
||||
// disable collisions with other portal
|
||||
_colliders = TransformToPortal.GetComponentsInChildren<Collider>(true);
|
||||
for (int i = 0; i < _colliders.Length; i++)
|
||||
{
|
||||
Physics.IgnoreCollision(_colliders[i], portal.wallCollider);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void ExitPortal(Portal portal)
|
||||
{
|
||||
if (_inPortal == portal)
|
||||
{
|
||||
_inPortal = null;
|
||||
}
|
||||
|
||||
OnExitPortalCollider?.Invoke(this, portal);
|
||||
//Debug.Log("ExitPortal " + this.name + " inPortal: " + portal.name + " turning ON colliders ");
|
||||
|
||||
|
||||
if (portal.wallCollider)
|
||||
{
|
||||
for (int i = 0; i < _colliders.Length; i++)
|
||||
{
|
||||
Physics.IgnoreCollision(_colliders[i], portal.wallCollider, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected virtual void PreWarp(Portal fromPortal)
|
||||
{
|
||||
//Debug.Log(" PRE: " + name);
|
||||
OnPrePortalEvent.Invoke(this, fromPortal);
|
||||
if (_characterController)
|
||||
{
|
||||
_characterController.enabled = false;
|
||||
}
|
||||
|
||||
}
|
||||
protected virtual void PostWarp(Portal fromPortal)
|
||||
{
|
||||
//Debug.Log("POST: " + name);
|
||||
OnPostPortalEvent.Invoke(this, fromPortal);
|
||||
//Debug.Log("PortalableObject postWarp, gonna triggered teleport function in HVR");
|
||||
if (_characterController)
|
||||
{
|
||||
_characterController.enabled = true;
|
||||
}
|
||||
|
||||
|
||||
// instant move clones to other portal
|
||||
childCloneRenderers = FindChildCloneRenderers();
|
||||
for (int i = 0; i < childCloneRenderers.Length; i++)
|
||||
{
|
||||
fromPortal.PortalTransporter.cloneObjects.Remove(childCloneRenderers[i]);
|
||||
childCloneRenderers[i].ExitPortal(fromPortal, false);
|
||||
|
||||
Collider[] myColliders = childCloneRenderers[i].GetComponents<Collider>();
|
||||
foreach (Collider c in myColliders) {
|
||||
|
||||
//Debug.DrawLine(childCloneRenderers[i].transform.position, fromPortal.OtherPortal.PortalTransporter.transform.position, Color.cyan, 10);
|
||||
|
||||
Vector3 direction;
|
||||
float distance;
|
||||
bool overlapped = Physics.ComputePenetration(
|
||||
|
||||
c, childCloneRenderers[i].transform.position, childCloneRenderers[i].transform.rotation,
|
||||
fromPortal.OtherPortal.PortalTransporter.MyCollider, fromPortal.OtherPortal.PortalTransporter.transform.position, fromPortal.OtherPortal.PortalTransporter.transform.rotation,
|
||||
out direction, out distance);
|
||||
|
||||
//Debug.Log(childCloneRenderers[i].name + " : " + direction + " : " + distance + " : " + overlapped);
|
||||
|
||||
if (overlapped)
|
||||
{
|
||||
//Debug.Log("AFTER WARP " + childCloneRenderers[i].name + " WOULD BE TOUCHING SO SET ME IN PORTAL: " + fromPortal.OtherPortal.name);
|
||||
childCloneRenderers[i].SetIsInPortal(fromPortal.OtherPortal, false);
|
||||
fromPortal.OtherPortal.PortalTransporter.cloneObjects.Add(childCloneRenderers[i]);
|
||||
break;
|
||||
}
|
||||
/*else
|
||||
{
|
||||
Debug.Log("AFTER WARP not touching new portal: " + fromPortal.OtherPortal.name);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected virtual CloneRenderer[] FindChildCloneRenderers()
|
||||
{
|
||||
return TransformToPortal.GetComponentsInChildren<CloneRenderer>(true);
|
||||
}
|
||||
|
||||
public virtual bool CanPortal() {
|
||||
|
||||
//Debug.Log("AllowTransporting canWarp?: " + name + " :" + AllowTransporting);
|
||||
return (!childOfAnotherPortalable && PortallingEnabled && !PortalAlongWithMasterPortalable);
|
||||
}
|
||||
|
||||
public virtual bool PortalFrom(Portal fromPortal, bool force = false)
|
||||
{
|
||||
if (!force && !CanPortal())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//Debug.Log("WARP " + name + " from " + fromPortal.name + " childOfAnotherPortalable: " + childOfAnotherPortalable + " force: " + force);
|
||||
|
||||
// if we're forced, that means the Master got us here and a preWarp has already been done
|
||||
if (!force) {
|
||||
PreWarp(fromPortal);
|
||||
}
|
||||
|
||||
if (force)
|
||||
{
|
||||
// master got us here.. we might have entered through physics.. but on the wrong side of the portal therefor not adding to the list in transporter
|
||||
if (!fromPortal.OtherPortal.PortalTransporter.portalableObjects.Contains(this))
|
||||
{
|
||||
//Debug.Log("(from master) Adding to portal list of " + fromPortal.OtherPortal.name + " object:" + this.name);
|
||||
fromPortal.OtherPortal.PortalTransporter.portalableObjects.Add(this);
|
||||
}
|
||||
}
|
||||
|
||||
// disable collisions with other portal
|
||||
if (fromPortal.OtherPortal.wallCollider)
|
||||
{
|
||||
for (int i = 0; i < _colliders.Length; i++)
|
||||
{
|
||||
Physics.IgnoreCollision(_colliders[i], fromPortal.OtherPortal.wallCollider);
|
||||
}
|
||||
}
|
||||
|
||||
var inTransform = fromPortal.PortalSurface.transform;
|
||||
var outTransform = fromPortal.OtherPortal.PortalSurface.transform;
|
||||
|
||||
// van scale p1.0 to p0.5 = player 0.5 = portal out / portal in
|
||||
// van scale p0.5 to p1.0 = player 2 = portal out / portal in
|
||||
float scaleFactor = (fromPortal.OtherPortal.transform.lossyScale.x / fromPortal.transform.lossyScale.x);
|
||||
|
||||
|
||||
Vector3 originalScaleBeforeWarp = TransformToPortal.localScale;
|
||||
TransformToPortal.localScale = TransformToPortal.localScale * scaleFactor;
|
||||
|
||||
|
||||
// Position the camera behind the other portal.
|
||||
Vector3 relativePos = inTransform.InverseTransformPoint(TransformToPortal.position);
|
||||
relativePos = halfTurn * relativePos;
|
||||
TransformToPortal.position = outTransform.TransformPoint(relativePos);
|
||||
|
||||
// Rotate the camera to look through the other portal.
|
||||
Quaternion relativeRot = Quaternion.Inverse(inTransform.rotation) * TransformToPortal.rotation;
|
||||
relativeRot = halfTurn * relativeRot;
|
||||
TransformToPortal.rotation = outTransform.rotation * relativeRot;
|
||||
|
||||
// Update velocity of rigidbody.
|
||||
if (_rigidbody)
|
||||
{
|
||||
Vector3 relativeVel = inTransform.InverseTransformDirection(_rigidbody.linearVelocity);
|
||||
relativeVel = halfTurn * relativeVel;
|
||||
_rigidbody.linearVelocity = outTransform.TransformDirection(relativeVel);
|
||||
|
||||
Vector3 relativeAngVel = inTransform.InverseTransformDirection(_rigidbody.angularVelocity);
|
||||
relativeAngVel = halfTurn * relativeAngVel;
|
||||
_rigidbody.angularVelocity = outTransform.TransformDirection(relativeAngVel);
|
||||
|
||||
_rigidbody.position = TransformToPortal.position; // so it works for RB with interpolation
|
||||
_rigidbody.rotation = TransformToPortal.rotation; // so it works for RB with interpolation
|
||||
}
|
||||
|
||||
if (RigidbodiesToPortal.Count > 0)
|
||||
{
|
||||
foreach (Rigidbody rb in RigidbodiesToPortal)
|
||||
{
|
||||
if (rb && rb != _rigidbody)
|
||||
{
|
||||
Vector3 relativeVel = inTransform.InverseTransformDirection(rb.linearVelocity);
|
||||
relativeVel = halfTurn * relativeVel;
|
||||
rb.linearVelocity = outTransform.TransformDirection(relativeVel);
|
||||
|
||||
Vector3 relativeAngVel = inTransform.InverseTransformDirection(rb.angularVelocity);
|
||||
relativeAngVel = halfTurn * relativeAngVel;
|
||||
rb.angularVelocity = outTransform.TransformDirection(relativeAngVel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PostWarp(fromPortal);
|
||||
|
||||
SendMessage("OnWarped", transform.rotation, SendMessageOptions.DontRequireReceiver);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9581fdc03f0e386459a466474b74272c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: -20
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 228871
|
||||
packageName: Portals for VR
|
||||
packageVersion: 1.2.1
|
||||
assetPath: Assets/Fragilem17/Portals for VR/Scripts/PortalableObject.cs
|
||||
uploadId: 710348
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
namespace Fragilem17.MirrorsAndPortals
|
||||
{
|
||||
public class PortalableObjectCollider : MonoBehaviour
|
||||
{
|
||||
public PortalableObject PortalableObject;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4a7922b64e0eeb429ee73795b2f10dc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 228871
|
||||
packageName: Portals for VR
|
||||
packageVersion: 1.2.1
|
||||
assetPath: Assets/Fragilem17/Portals for VR/Scripts/PortalableObjectCollider.cs
|
||||
uploadId: 710348
|
||||
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
namespace Fragilem17.MirrorsAndPortals
|
||||
{
|
||||
public class StraightenTrackingSpace : MonoBehaviour
|
||||
{
|
||||
public float speed = 1f;
|
||||
public bool useLateUpdate = true;
|
||||
public bool useLerp = true;
|
||||
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!useLateUpdate)
|
||||
{
|
||||
Straighten();
|
||||
}
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (useLateUpdate)
|
||||
{
|
||||
Straighten();
|
||||
}
|
||||
}
|
||||
|
||||
private void Straighten()
|
||||
{
|
||||
Vector3 euler = transform.rotation.eulerAngles;
|
||||
|
||||
if (useLerp)
|
||||
{
|
||||
transform.rotation = Quaternion.LerpUnclamped(transform.rotation, Quaternion.Euler(0, euler.y, 0), speed * Time.deltaTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
transform.rotation = Quaternion.Euler(0, euler.y, 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 67c80556e8a1733459944d1d9191eaef
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 228871
|
||||
packageName: Portals for VR
|
||||
packageVersion: 1.2.1
|
||||
assetPath: Assets/Fragilem17/Portals for VR/Scripts/StraightenTrackingSpace.cs
|
||||
uploadId: 710348
|
||||
@@ -0,0 +1,11 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Fragilem17.MirrorsAndPortals
|
||||
{
|
||||
public class TransformTargetOfPortalableObject : MonoBehaviour
|
||||
{
|
||||
public PortalableObject PortalableObject;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e3d344611d5a4a843a36570dd4dd072d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 228871
|
||||
packageName: Portals for VR
|
||||
packageVersion: 1.2.1
|
||||
assetPath: Assets/Fragilem17/Portals for VR/Scripts/TransformTargetOfPortalableObject.cs
|
||||
uploadId: 710348
|
||||
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace Fragilem17.MirrorsAndPortals
|
||||
{
|
||||
/**
|
||||
* Used to transport PortalableObjects to the linked portal defined in the portalSurface
|
||||
*/
|
||||
[RequireComponent(typeof(PortalTransporter))]
|
||||
public class TransporterEventFilter : MonoBehaviour
|
||||
{
|
||||
|
||||
[Tooltip("Any gameObject wich contains this string in the name will trigger the event.")]
|
||||
public String NameFilter = "*";
|
||||
|
||||
private PortalTransporter _portalTransporter;
|
||||
[Space(10)]
|
||||
|
||||
[Header("Events")]
|
||||
public UnityEvent<PortalableObject> OnObjectEnteredPortal;
|
||||
public UnityEvent<PortalableObject> OnObjectTransportedAwayFromHere;
|
||||
public UnityEvent<PortalableObject> OnObjectTransportedToHere;
|
||||
public UnityEvent<PortalableObject> OnObjectExitedPortal;
|
||||
|
||||
|
||||
protected void OnEnable()
|
||||
{
|
||||
_portalTransporter = GetComponent<PortalTransporter>();
|
||||
if (_portalTransporter == null)
|
||||
{
|
||||
Debug.LogWarning("Could not find a PortalTransporter component");
|
||||
return;
|
||||
}
|
||||
|
||||
_portalTransporter.OnObjectEnteredPortal.AddListener(OnObjectEnteredPortalEvent);
|
||||
_portalTransporter.OnObjectTransportedAwayFromHere.AddListener(OnObjectTransportedAwayFromHereEvent);
|
||||
_portalTransporter.OnObjectTransportedToHere.AddListener(OnObjectTransportedToHereEvent);
|
||||
_portalTransporter.OnObjectExitedPortal.AddListener(OnObjectExitedPortalEvent);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_portalTransporter.OnObjectEnteredPortal.RemoveListener(OnObjectEnteredPortalEvent);
|
||||
_portalTransporter.OnObjectTransportedAwayFromHere.RemoveListener(OnObjectTransportedAwayFromHereEvent);
|
||||
_portalTransporter.OnObjectTransportedToHere.RemoveListener(OnObjectTransportedToHereEvent);
|
||||
_portalTransporter.OnObjectExitedPortal.RemoveListener(OnObjectExitedPortalEvent);
|
||||
}
|
||||
|
||||
private void OnObjectEnteredPortalEvent(PortalableObject obj)
|
||||
{
|
||||
if (AllowedByFilter(obj))
|
||||
{
|
||||
OnObjectEnteredPortal.Invoke(obj);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnObjectTransportedAwayFromHereEvent(PortalableObject obj)
|
||||
{
|
||||
if (AllowedByFilter(obj))
|
||||
{
|
||||
OnObjectTransportedAwayFromHere.Invoke(obj);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnObjectTransportedToHereEvent(PortalableObject obj)
|
||||
{
|
||||
if (AllowedByFilter(obj))
|
||||
{
|
||||
OnObjectTransportedToHere.Invoke(obj);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnObjectExitedPortalEvent(PortalableObject obj)
|
||||
{
|
||||
if (AllowedByFilter(obj))
|
||||
{
|
||||
OnObjectExitedPortal.Invoke(obj);
|
||||
}
|
||||
}
|
||||
|
||||
private bool AllowedByFilter(PortalableObject obj)
|
||||
{
|
||||
if (NameFilter == "" || NameFilter == "*")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj.name.Contains(NameFilter))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b717a5a59309e840ae77aefc02bf25e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 228871
|
||||
packageName: Portals for VR
|
||||
packageVersion: 1.2.1
|
||||
assetPath: Assets/Fragilem17/Portals for VR/Scripts/TransporterEventFilter.cs
|
||||
uploadId: 710348
|
||||
Reference in New Issue
Block a user